mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2025-04-21 07:56:48 +02:00
Compare commits
6 Commits
0391df5bbd
...
06f38edcc7
Author | SHA1 | Date | |
---|---|---|---|
|
06f38edcc7 | ||
|
76c1cc694f | ||
|
4219b8fd77 | ||
|
064e7fa473 | ||
|
ea9b7843fc | ||
|
755efe08da |
10
CHANGES.md
10
CHANGES.md
@ -2,7 +2,14 @@ Changes in PDFio
|
|||||||
================
|
================
|
||||||
|
|
||||||
|
|
||||||
v1.5.2 - YYYY-MM-DD
|
v1.6.0 - YYYY-MM-DD
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
- Added `pdfioFileCreateFontObjFromData` function for embedding fonts in
|
||||||
|
memory (Issue #120)
|
||||||
|
|
||||||
|
|
||||||
|
v1.5.2 - 2025-04-12
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
- Updated maximum allowed PDF string size to 64k (Issue #117)
|
- Updated maximum allowed PDF string size to 64k (Issue #117)
|
||||||
@ -11,6 +18,7 @@ v1.5.2 - YYYY-MM-DD
|
|||||||
- Fixed form detection in `pdfioinfo` example code (Issue #114)
|
- Fixed form detection in `pdfioinfo` example code (Issue #114)
|
||||||
- Fixed parsing of certain date/time values (Issue #115)
|
- Fixed parsing of certain date/time values (Issue #115)
|
||||||
- Fixed support for empty name values (Issue #116)
|
- Fixed support for empty name values (Issue #116)
|
||||||
|
- Fixed range checking in `pdfioImageGetBytesPerLine` (Issue #121)
|
||||||
|
|
||||||
|
|
||||||
v1.5.1 - 2025-03-28
|
v1.5.1 - 2025-03-28
|
||||||
|
24
configure
vendored
24
configure
vendored
@ -1,6 +1,6 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# Guess values for system-dependent variables and create Makefiles.
|
||||||
# Generated by GNU Autoconf 2.71 for pdfio 1.5.2.
|
# Generated by GNU Autoconf 2.71 for pdfio 1.6.0.
|
||||||
#
|
#
|
||||||
# Report bugs to <https://github.com/michaelrsweet/pdfio/issues>.
|
# Report bugs to <https://github.com/michaelrsweet/pdfio/issues>.
|
||||||
#
|
#
|
||||||
@ -610,8 +610,8 @@ MAKEFLAGS=
|
|||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='pdfio'
|
PACKAGE_NAME='pdfio'
|
||||||
PACKAGE_TARNAME='pdfio'
|
PACKAGE_TARNAME='pdfio'
|
||||||
PACKAGE_VERSION='1.5.2'
|
PACKAGE_VERSION='1.6.0'
|
||||||
PACKAGE_STRING='pdfio 1.5.2'
|
PACKAGE_STRING='pdfio 1.6.0'
|
||||||
PACKAGE_BUGREPORT='https://github.com/michaelrsweet/pdfio/issues'
|
PACKAGE_BUGREPORT='https://github.com/michaelrsweet/pdfio/issues'
|
||||||
PACKAGE_URL='https://www.msweet.org/pdfio'
|
PACKAGE_URL='https://www.msweet.org/pdfio'
|
||||||
|
|
||||||
@ -1295,7 +1295,7 @@ if test "$ac_init_help" = "long"; then
|
|||||||
# Omit some internal or obsolete options to make the list less imposing.
|
# Omit some internal or obsolete options to make the list less imposing.
|
||||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
cat <<_ACEOF
|
||||||
\`configure' configures pdfio 1.5.2 to adapt to many kinds of systems.
|
\`configure' configures pdfio 1.6.0 to adapt to many kinds of systems.
|
||||||
|
|
||||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
@ -1361,7 +1361,7 @@ fi
|
|||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of pdfio 1.5.2:";;
|
short | recursive ) echo "Configuration of pdfio 1.6.0:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
@ -1460,7 +1460,7 @@ fi
|
|||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
pdfio configure 1.5.2
|
pdfio configure 1.6.0
|
||||||
generated by GNU Autoconf 2.71
|
generated by GNU Autoconf 2.71
|
||||||
|
|
||||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||||
@ -1678,7 +1678,7 @@ cat >config.log <<_ACEOF
|
|||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
running configure, to aid debugging if configure makes a mistake.
|
||||||
|
|
||||||
It was created by pdfio $as_me 1.5.2, which was
|
It was created by pdfio $as_me 1.6.0, which was
|
||||||
generated by GNU Autoconf 2.71. Invocation command line was
|
generated by GNU Autoconf 2.71. Invocation command line was
|
||||||
|
|
||||||
$ $0$ac_configure_args_raw
|
$ $0$ac_configure_args_raw
|
||||||
@ -2434,9 +2434,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
PDFIO_VERSION="1.5.2"
|
PDFIO_VERSION="1.6.0"
|
||||||
PDFIO_VERSION_MAJOR="`echo 1.5.2 | awk -F. '{print $1}'`"
|
PDFIO_VERSION_MAJOR="`echo 1.6.0 | awk -F. '{print $1}'`"
|
||||||
PDFIO_VERSION_MINOR="`echo 1.5.2 | awk -F. '{printf("%d\n",$2);}'`"
|
PDFIO_VERSION_MINOR="`echo 1.6.0 | awk -F. '{printf("%d\n",$2);}'`"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -5099,7 +5099,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
|||||||
# report actual input values of CONFIG_FILES etc. instead of their
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
ac_log="
|
||||||
This file was extended by pdfio $as_me 1.5.2, which was
|
This file was extended by pdfio $as_me 1.6.0, which was
|
||||||
generated by GNU Autoconf 2.71. Invocation command line was
|
generated by GNU Autoconf 2.71. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
CONFIG_FILES = $CONFIG_FILES
|
||||||
@ -5155,7 +5155,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
|
|||||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config='$ac_cs_config_escaped'
|
ac_cs_config='$ac_cs_config_escaped'
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
pdfio config.status 1.5.2
|
pdfio config.status 1.6.0
|
||||||
configured by $0, generated by GNU Autoconf 2.71,
|
configured by $0, generated by GNU Autoconf 2.71,
|
||||||
with options \\"\$ac_cs_config\\"
|
with options \\"\$ac_cs_config\\"
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ AC_PREREQ([2.70])
|
|||||||
|
|
||||||
|
|
||||||
dnl Package name and version...
|
dnl Package name and version...
|
||||||
AC_INIT([pdfio], [1.5.2], [https://github.com/michaelrsweet/pdfio/issues], [pdfio], [https://www.msweet.org/pdfio])
|
AC_INIT([pdfio], [1.6.0], [https://github.com/michaelrsweet/pdfio/issues], [pdfio], [https://www.msweet.org/pdfio])
|
||||||
|
|
||||||
PDFIO_VERSION="AC_PACKAGE_VERSION"
|
PDFIO_VERSION="AC_PACKAGE_VERSION"
|
||||||
PDFIO_VERSION_MAJOR="`echo AC_PACKAGE_VERSION | awk -F. '{print $1}'`"
|
PDFIO_VERSION_MAJOR="`echo AC_PACKAGE_VERSION | awk -F. '{print $1}'`"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.TH pdfio 3 "pdf read/write library" "2025-04-04" "pdf read/write library"
|
.TH pdfio 3 "pdf read/write library" "2025-04-12" "pdf read/write library"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
pdfio \- pdf read/write library
|
pdfio \- pdf read/write library
|
||||||
.SH Introduction
|
.SH Introduction
|
||||||
|
@ -4787,7 +4787,7 @@ size_t pdfioImageGetBytesPerLine(<a href="#pdfio_obj_t">pdfio_obj_t</a> *obj);</
|
|||||||
<td class="description">Image object</td></tr>
|
<td class="description">Image object</td></tr>
|
||||||
</tbody></table>
|
</tbody></table>
|
||||||
<h4 class="returnvalue">Return Value</h4>
|
<h4 class="returnvalue">Return Value</h4>
|
||||||
<p class="description">Number of bytes per line</p>
|
<p class="description">Number of bytes per line or <code>0</code> on error</p>
|
||||||
<h3 class="function"><a id="pdfioImageGetHeight">pdfioImageGetHeight</a></h3>
|
<h3 class="function"><a id="pdfioImageGetHeight">pdfioImageGetHeight</a></h3>
|
||||||
<p class="description">Get the height of an image object.</p>
|
<p class="description">Get the height of an image object.</p>
|
||||||
<p class="code">
|
<p class="code">
|
||||||
|
@ -32,11 +32,11 @@ if test $(grep AC_INIT configure.ac | awk '{print $2}') != "[$version],"; then
|
|||||||
status=1
|
status=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test $(head -4 CHANGES.md | tail -1 | awk '{print $1}') != "v$version"; then
|
if test $(head -5 CHANGES.md | tail -1 | awk '{print $1}') != "v$version"; then
|
||||||
echo "Still need to update CHANGES.md version number."
|
echo "Still need to update CHANGES.md version number."
|
||||||
status=1
|
status=1
|
||||||
fi
|
fi
|
||||||
if test $(head -4 CHANGES.md | tail -1 | awk '{print $3}') = "YYYY-MM-DD"; then
|
if test $(head -5 CHANGES.md | tail -1 | awk '{print $3}') = "YYYY-MM-DD"; then
|
||||||
echo "Still need to update CHANGES.md release date."
|
echo "Still need to update CHANGES.md release date."
|
||||||
status=1
|
status=1
|
||||||
fi
|
fi
|
||||||
|
805
pdfio-content.c
805
pdfio-content.c
@ -84,6 +84,7 @@ typedef pdfio_obj_t *(*_pdfio_image_func_t)(pdfio_dict_t *dict, int fd);
|
|||||||
static pdfio_obj_t *copy_jpeg(pdfio_dict_t *dict, int fd);
|
static pdfio_obj_t *copy_jpeg(pdfio_dict_t *dict, int fd);
|
||||||
static pdfio_obj_t *copy_png(pdfio_dict_t *dict, int fd);
|
static pdfio_obj_t *copy_png(pdfio_dict_t *dict, int fd);
|
||||||
static bool create_cp1252(pdfio_file_t *pdf);
|
static bool create_cp1252(pdfio_file_t *pdf);
|
||||||
|
static pdfio_obj_t *create_font(pdfio_obj_t *file_obj, ttf_t *font, bool unicode);
|
||||||
static pdfio_obj_t *create_image(pdfio_dict_t *dict, const unsigned char *data, size_t width, size_t height, size_t depth, size_t num_colors, bool alpha);
|
static pdfio_obj_t *create_image(pdfio_dict_t *dict, const unsigned char *data, size_t width, size_t height, size_t depth, size_t num_colors, bool alpha);
|
||||||
#ifdef HAVE_LIBPNG
|
#ifdef HAVE_LIBPNG
|
||||||
static void png_error_func(png_structp pp, png_const_charp message);
|
static void png_error_func(png_structp pp, png_const_charp message);
|
||||||
@ -1536,9 +1537,84 @@ pdfioFileCreateFontObjFromBase(
|
|||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'pdfioFileCreateFontObjFromFile()' - Add a font object to a PDF file.
|
// 'pdfioFileCreateFontObjFromData()' - Add a font in memory to a PDF file.
|
||||||
//
|
//
|
||||||
// This function embeds a TrueType/OpenType font into a PDF file. The
|
// This function embeds TrueType/OpenType font data into a PDF file. The
|
||||||
|
// "unicode" parameter controls whether the font is encoded for two-byte
|
||||||
|
// characters (potentially full Unicode, but more typically a subset)
|
||||||
|
// or to only support the Windows CP1252 (ISO-8859-1 with additional
|
||||||
|
// characters such as the Euro symbol) subset of Unicode.
|
||||||
|
//
|
||||||
|
|
||||||
|
pdfio_obj_t * // O - Font object
|
||||||
|
pdfioFileCreateFontObjFromData(
|
||||||
|
pdfio_file_t *pdf, // I - PDF file
|
||||||
|
const void *data, // I - Font data in memory
|
||||||
|
size_t datasize, // I - Size of font in memory
|
||||||
|
bool unicode) // I - Force Unicode
|
||||||
|
{
|
||||||
|
ttf_t *font; // TrueType font
|
||||||
|
pdfio_obj_t *obj, // Font object
|
||||||
|
*file_obj = NULL; // File object
|
||||||
|
pdfio_dict_t *file; // Font file dictionary
|
||||||
|
pdfio_stream_t *st = NULL; // Font stream
|
||||||
|
|
||||||
|
|
||||||
|
// Range check input...
|
||||||
|
if (!pdf)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
if (!data || !datasize)
|
||||||
|
{
|
||||||
|
_pdfioFileError(pdf, "No TrueType/OpenType data specified.");
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a TrueType font object from the data...
|
||||||
|
if ((font = ttfCreateData(data, datasize, 0, (ttf_err_cb_t)ttf_error_cb, pdf)) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
// Create the font file dictionary and object...
|
||||||
|
if ((file = pdfioDictCreate(pdf)) == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
pdfioDictSetName(file, "Filter", "FlateDecode");
|
||||||
|
|
||||||
|
if ((file_obj = pdfioFileCreateObj(pdf, file)) == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if ((st = pdfioObjCreateStream(file_obj, PDFIO_FILTER_FLATE)) == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!pdfioStreamWrite(st, data, datasize))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
pdfioStreamClose(st);
|
||||||
|
|
||||||
|
// Create the font object...
|
||||||
|
if ((obj = create_font(file_obj, font, unicode)) == NULL)
|
||||||
|
ttfDelete(font);
|
||||||
|
|
||||||
|
return (obj);
|
||||||
|
|
||||||
|
// If we get here we had an unrecoverable error...
|
||||||
|
error:
|
||||||
|
|
||||||
|
if (st)
|
||||||
|
pdfioStreamClose(st);
|
||||||
|
else
|
||||||
|
pdfioObjClose(file_obj);
|
||||||
|
|
||||||
|
ttfDelete(font);
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'pdfioFileCreateFontObjFromFile()' - Add a font file to a PDF file.
|
||||||
|
//
|
||||||
|
// This function embeds a TrueType/OpenType font file into a PDF file. The
|
||||||
// "unicode" parameter controls whether the font is encoded for two-byte
|
// "unicode" parameter controls whether the font is encoded for two-byte
|
||||||
// characters (potentially full Unicode, but more typically a subset)
|
// characters (potentially full Unicode, but more typically a subset)
|
||||||
// or to only support the Windows CP1252 (ISO-8859-1 with additional
|
// or to only support the Windows CP1252 (ISO-8859-1 with additional
|
||||||
@ -1552,16 +1628,10 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
bool unicode) // I - Force Unicode
|
bool unicode) // I - Force Unicode
|
||||||
{
|
{
|
||||||
ttf_t *font; // TrueType font
|
ttf_t *font; // TrueType font
|
||||||
ttf_rect_t bounds; // Font bounds
|
pdfio_dict_t *file; // Font file dictionary
|
||||||
pdfio_dict_t *dict, // Font dictionary
|
pdfio_obj_t *obj, // Font object
|
||||||
*desc, // Font descriptor
|
*file_obj = NULL; // Font file object
|
||||||
*file; // Font file dictionary
|
pdfio_stream_t *st = NULL; // Font stream
|
||||||
pdfio_obj_t *obj = NULL, // Font object
|
|
||||||
*desc_obj, // Font descriptor object
|
|
||||||
*file_obj; // Font file object
|
|
||||||
const char *basefont; // Base font name
|
|
||||||
pdfio_array_t *bbox; // Font bounding box array
|
|
||||||
pdfio_stream_t *st; // Font stream
|
|
||||||
int fd = -1; // File
|
int fd = -1; // File
|
||||||
unsigned char buffer[16384]; // Read buffer
|
unsigned char buffer[16384]; // Read buffer
|
||||||
ssize_t bytes; // Bytes read
|
ssize_t bytes; // Bytes read
|
||||||
@ -1584,360 +1654,50 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((font = ttfCreate(filename, 0, (ttf_err_cb_t)ttf_error_cb, pdf)) == NULL)
|
if ((font = ttfCreate(filename, 0, (ttf_err_cb_t)ttf_error_cb, pdf)) == NULL)
|
||||||
{
|
goto error;
|
||||||
close(fd);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the font file dictionary and object...
|
// Create the font file dictionary and object...
|
||||||
if ((file = pdfioDictCreate(pdf)) == NULL)
|
if ((file = pdfioDictCreate(pdf)) == NULL)
|
||||||
goto done;
|
goto error;
|
||||||
|
|
||||||
pdfioDictSetName(file, "Filter", "FlateDecode");
|
pdfioDictSetName(file, "Filter", "FlateDecode");
|
||||||
|
|
||||||
if ((file_obj = pdfioFileCreateObj(pdf, file)) == NULL)
|
if ((file_obj = pdfioFileCreateObj(pdf, file)) == NULL)
|
||||||
goto done;
|
goto error;
|
||||||
|
|
||||||
if ((st = pdfioObjCreateStream(file_obj, PDFIO_FILTER_FLATE)) == NULL)
|
if ((st = pdfioObjCreateStream(file_obj, PDFIO_FILTER_FLATE)) == NULL)
|
||||||
goto done;
|
goto error;
|
||||||
|
|
||||||
while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
|
while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
|
||||||
{
|
{
|
||||||
if (!pdfioStreamWrite(st, buffer, (size_t)bytes))
|
if (!pdfioStreamWrite(st, buffer, (size_t)bytes))
|
||||||
{
|
goto error;
|
||||||
pdfioStreamClose(st);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
fd = -1;
|
|
||||||
pdfioStreamClose(st);
|
|
||||||
|
|
||||||
// Create the font descriptor dictionary and object...
|
|
||||||
if ((bbox = pdfioArrayCreate(pdf)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
ttfGetBounds(font, &bounds);
|
|
||||||
|
|
||||||
pdfioArrayAppendNumber(bbox, bounds.left);
|
|
||||||
pdfioArrayAppendNumber(bbox, bounds.bottom);
|
|
||||||
pdfioArrayAppendNumber(bbox, bounds.right);
|
|
||||||
pdfioArrayAppendNumber(bbox, bounds.top);
|
|
||||||
|
|
||||||
if ((desc = pdfioDictCreate(pdf)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
basefont = pdfioStringCreate(pdf, ttfGetPostScriptName(font));
|
|
||||||
|
|
||||||
pdfioDictSetName(desc, "Type", "FontDescriptor");
|
|
||||||
pdfioDictSetName(desc, "FontName", basefont);
|
|
||||||
pdfioDictSetObj(desc, "FontFile2", file_obj);
|
|
||||||
pdfioDictSetNumber(desc, "Flags", ttfIsFixedPitch(font) ? 0x21 : 0x20);
|
|
||||||
pdfioDictSetArray(desc, "FontBBox", bbox);
|
|
||||||
pdfioDictSetNumber(desc, "ItalicAngle", ttfGetItalicAngle(font));
|
|
||||||
pdfioDictSetNumber(desc, "Ascent", ttfGetAscent(font));
|
|
||||||
pdfioDictSetNumber(desc, "Descent", ttfGetDescent(font));
|
|
||||||
pdfioDictSetNumber(desc, "CapHeight", ttfGetCapHeight(font));
|
|
||||||
pdfioDictSetNumber(desc, "XHeight", ttfGetXHeight(font));
|
|
||||||
// Note: No TrueType value exists for this but PDF requires it, so we
|
|
||||||
// calculate a generic value from 50 to 250 based on the weight...
|
|
||||||
pdfioDictSetNumber(desc, "StemV", ttfGetWeight(font) / 4 + 25);
|
|
||||||
|
|
||||||
if ((desc_obj = pdfioFileCreateObj(pdf, desc)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
pdfioObjClose(desc_obj);
|
|
||||||
|
|
||||||
if (unicode)
|
|
||||||
{
|
|
||||||
// Unicode (CID) font...
|
|
||||||
pdfio_dict_t *cid2gid, // CIDToGIDMap dictionary
|
|
||||||
*to_unicode; // ToUnicode dictionary
|
|
||||||
pdfio_obj_t *cid2gid_obj, // CIDToGIDMap object
|
|
||||||
*to_unicode_obj;// ToUnicode object
|
|
||||||
size_t i, j, // Looping vars
|
|
||||||
num_cmap; // Number of CMap entries
|
|
||||||
const int *cmap; // CMap entries
|
|
||||||
int min_glyph, // First glyph
|
|
||||||
max_glyph; // Last glyph
|
|
||||||
unsigned short glyphs[65536]; // Glyph to Unicode mapping
|
|
||||||
unsigned char *bufptr, // Pointer into buffer
|
|
||||||
*bufend; // End of buffer
|
|
||||||
pdfio_dict_t *type2; // CIDFontType2 font dictionary
|
|
||||||
pdfio_obj_t *type2_obj; // CIDFontType2 font object
|
|
||||||
pdfio_array_t *descendants; // Decendant font list
|
|
||||||
pdfio_dict_t *sidict; // CIDSystemInfo dictionary
|
|
||||||
pdfio_array_t *w_array, // Width array
|
|
||||||
*temp_array; // Temporary width sub-array
|
|
||||||
int w0, w1; // Widths
|
|
||||||
|
|
||||||
// Create a CIDSystemInfo mapping to Adobe UCS2 v0 (Unicode)
|
|
||||||
if ((sidict = pdfioDictCreate(pdf)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
pdfioDictSetString(sidict, "Registry", "Adobe");
|
|
||||||
pdfioDictSetString(sidict, "Ordering", "Identity");
|
|
||||||
pdfioDictSetNumber(sidict, "Supplement", 0);
|
|
||||||
|
|
||||||
// Create a CIDToGIDMap object for the Unicode font...
|
|
||||||
if ((cid2gid = pdfioDictCreate(pdf)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
#ifndef DEBUG
|
|
||||||
pdfioDictSetName(cid2gid, "Filter", "FlateDecode");
|
|
||||||
#endif // !DEBUG
|
|
||||||
|
|
||||||
if ((cid2gid_obj = pdfioFileCreateObj(pdf, cid2gid)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_NONE)) == NULL)
|
|
||||||
#else
|
|
||||||
if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_FLATE)) == NULL)
|
|
||||||
#endif // DEBUG
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
cmap = ttfGetCMap(font, &num_cmap);
|
|
||||||
min_glyph = 65536;
|
|
||||||
max_glyph = 0;
|
|
||||||
memset(glyphs, 0, sizeof(glyphs));
|
|
||||||
|
|
||||||
PDFIO_DEBUG("pdfioFileCreateFontObjFromFile: num_cmap=%u\n", (unsigned)num_cmap);
|
|
||||||
|
|
||||||
for (i = 0, bufptr = buffer, bufend = buffer + sizeof(buffer); i < num_cmap; i ++)
|
|
||||||
{
|
|
||||||
PDFIO_DEBUG("pdfioFileCreateFontObjFromFile: cmap[%u]=%d\n", (unsigned)i, cmap[i]);
|
|
||||||
if (cmap[i] < 0 || cmap[i] >= (int)(sizeof(glyphs) / sizeof(glyphs[0])))
|
|
||||||
{
|
|
||||||
// Map undefined glyph to .notdef...
|
|
||||||
*bufptr++ = 0;
|
|
||||||
*bufptr++ = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Map to specified glyph...
|
|
||||||
*bufptr++ = (unsigned char)(cmap[i] >> 8);
|
|
||||||
*bufptr++ = (unsigned char)(cmap[i] & 255);
|
|
||||||
|
|
||||||
glyphs[cmap[i]] = (unsigned short)i;
|
|
||||||
if (cmap[i] < min_glyph)
|
|
||||||
min_glyph = cmap[i];
|
|
||||||
if (cmap[i] > max_glyph)
|
|
||||||
max_glyph = cmap[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bufptr >= bufend)
|
|
||||||
{
|
|
||||||
// Flush buffer...
|
|
||||||
if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer)))
|
|
||||||
{
|
|
||||||
pdfioStreamClose(st);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
bufptr = buffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bufptr > buffer)
|
|
||||||
{
|
|
||||||
// Flush buffer...
|
|
||||||
if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer)))
|
|
||||||
{
|
|
||||||
pdfioStreamClose(st);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioStreamClose(st);
|
pdfioStreamClose(st);
|
||||||
|
|
||||||
// ToUnicode mapping object
|
// Create the font object...
|
||||||
to_unicode = pdfioDictCreate(pdf);
|
if ((obj = create_font(file_obj, font, unicode)) == NULL)
|
||||||
pdfioDictSetName(to_unicode, "Type", "CMap");
|
ttfDelete(font);
|
||||||
pdfioDictSetName(to_unicode, "CMapName", "Adobe-Identity-UCS2");
|
|
||||||
pdfioDictSetDict(to_unicode, "CIDSystemInfo", sidict);
|
|
||||||
|
|
||||||
#ifndef DEBUG
|
return (obj);
|
||||||
pdfioDictSetName(to_unicode, "Filter", "FlateDecode");
|
|
||||||
#endif // !DEBUG
|
|
||||||
|
|
||||||
if ((to_unicode_obj = pdfioFileCreateObj(pdf, to_unicode)) == NULL)
|
// If we get here we had an unrecoverable error...
|
||||||
goto done;
|
error:
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
if ((st = pdfioObjCreateStream(to_unicode_obj, PDFIO_FILTER_NONE)) == NULL)
|
|
||||||
#else
|
|
||||||
if ((st = pdfioObjCreateStream(to_unicode_obj, PDFIO_FILTER_FLATE)) == NULL)
|
|
||||||
#endif // DEBUG
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
pdfioStreamPuts(st,
|
|
||||||
"stream\n"
|
|
||||||
"/CIDInit /ProcSet findresource begin\n"
|
|
||||||
"12 dict begin\n"
|
|
||||||
"begincmap\n"
|
|
||||||
"/CIDSystemInfo<<\n"
|
|
||||||
"/Registry (Adobe)\n"
|
|
||||||
"/Ordering (UCS2)\n"
|
|
||||||
"/Supplement 0\n"
|
|
||||||
">> def\n"
|
|
||||||
"/CMapName /Adobe-Identity-UCS2 def\n"
|
|
||||||
"/CMapType 2 def\n"
|
|
||||||
"1 begincodespacerange\n"
|
|
||||||
"<0000> <FFFF>\n"
|
|
||||||
"endcodespacerange\n"
|
|
||||||
"endcmap\n"
|
|
||||||
"CMapName currentdict /CMap defineresource pop\n"
|
|
||||||
"end\n"
|
|
||||||
"end\n");
|
|
||||||
|
|
||||||
pdfioStreamClose(st);
|
|
||||||
|
|
||||||
// Create a CIDFontType2 dictionary for the Unicode font...
|
|
||||||
if ((type2 = pdfioDictCreate(pdf)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
// Width array
|
|
||||||
if ((w_array = pdfioArrayCreate(pdf)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
for (i = 0, w0 = ttfGetWidth(font, 0), w1 = 0; i < 65536; w0 = w1)
|
|
||||||
{
|
|
||||||
for (j = 1; (i + j) < 65536; j ++)
|
|
||||||
{
|
|
||||||
if ((w1 = ttfGetWidth(font, (int)(i + j))) != w0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (j >= 4)
|
|
||||||
{
|
|
||||||
// Encode a long sequence of zeros...
|
|
||||||
// Encode a repeating sequence...
|
|
||||||
pdfioArrayAppendNumber(w_array, (double)i);
|
|
||||||
pdfioArrayAppendNumber(w_array, (double)(i + j - 1));
|
|
||||||
pdfioArrayAppendNumber(w_array, w0);
|
|
||||||
|
|
||||||
i += j;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Encode a non-repeating sequence...
|
|
||||||
pdfioArrayAppendNumber(w_array, (double)i);
|
|
||||||
|
|
||||||
if ((temp_array = pdfioArrayCreate(pdf)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
pdfioArrayAppendNumber(temp_array, w0);
|
|
||||||
for (i ++; i < 65536 && pdfioArrayGetSize(temp_array) < 8191; i ++, w0 = w1)
|
|
||||||
{
|
|
||||||
if ((w1 = ttfGetWidth(font, (int)i)) == w0 && i < 65530)
|
|
||||||
{
|
|
||||||
for (j = 1; j < 4; j ++)
|
|
||||||
{
|
|
||||||
if (ttfGetWidth(font, (int)(i + j)) != w0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (j >= 4)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioArrayAppendNumber(temp_array, w1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioArrayAppendArray(w_array, temp_array);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then the dictionary for the CID base font...
|
|
||||||
pdfioDictSetName(type2, "Type", "Font");
|
|
||||||
pdfioDictSetName(type2, "Subtype", "CIDFontType2");
|
|
||||||
pdfioDictSetName(type2, "BaseFont", basefont);
|
|
||||||
pdfioDictSetDict(type2, "CIDSystemInfo", sidict);
|
|
||||||
pdfioDictSetObj(type2, "CIDToGIDMap", cid2gid_obj);
|
|
||||||
pdfioDictSetObj(type2, "FontDescriptor", desc_obj);
|
|
||||||
pdfioDictSetArray(type2, "W", w_array);
|
|
||||||
|
|
||||||
if ((type2_obj = pdfioFileCreateObj(pdf, type2)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
pdfioObjClose(type2_obj);
|
|
||||||
|
|
||||||
// Create a Type 0 font object...
|
|
||||||
if ((descendants = pdfioArrayCreate(pdf)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
pdfioArrayAppendObj(descendants, type2_obj);
|
|
||||||
|
|
||||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
pdfioDictSetName(dict, "Type", "Font");
|
|
||||||
pdfioDictSetName(dict, "Subtype", "Type0");
|
|
||||||
pdfioDictSetName(dict, "BaseFont", basefont);
|
|
||||||
pdfioDictSetArray(dict, "DescendantFonts", descendants);
|
|
||||||
pdfioDictSetName(dict, "Encoding", "Identity-H");
|
|
||||||
pdfioDictSetObj(dict, "ToUnicode", to_unicode_obj);
|
|
||||||
|
|
||||||
if ((obj = pdfioFileCreateObj(pdf, dict)) != NULL)
|
|
||||||
pdfioObjClose(obj);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Simple (CP1282 or custom encoding) 8-bit font...
|
|
||||||
int ch; // Character
|
|
||||||
pdfio_array_t *w_array; // Widths array
|
|
||||||
|
|
||||||
if (ttfGetMaxChar(font) >= 255 && !pdf->cp1252_obj && !create_cp1252(pdf))
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
// Create a TrueType font object...
|
|
||||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
pdfioDictSetName(dict, "Type", "Font");
|
|
||||||
pdfioDictSetName(dict, "Subtype", "TrueType");
|
|
||||||
pdfioDictSetName(dict, "BaseFont", basefont);
|
|
||||||
pdfioDictSetNumber(dict, "FirstChar", 32);
|
|
||||||
if (ttfGetMaxChar(font) >= 255)
|
|
||||||
{
|
|
||||||
pdfioDictSetObj(dict, "Encoding", pdf->cp1252_obj);
|
|
||||||
pdfioDictSetNumber(dict, "LastChar", 255);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pdfioDictSetNumber(dict, "LastChar", ttfGetMaxChar(font));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build a Widths array for CP1252/WinAnsiEncoding
|
|
||||||
if ((w_array = pdfioArrayCreate(pdf)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
for (ch = 32; ch < 256 && ch < ttfGetMaxChar(font); ch ++)
|
|
||||||
{
|
|
||||||
if (ch >= 0x80 && ch < 0xa0)
|
|
||||||
pdfioArrayAppendNumber(w_array, ttfGetWidth(font, _pdfio_cp1252[ch - 0x80]));
|
|
||||||
else
|
|
||||||
pdfioArrayAppendNumber(w_array, ttfGetWidth(font, ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfioDictSetArray(dict, "Widths", w_array);
|
|
||||||
|
|
||||||
pdfioDictSetObj(dict, "FontDescriptor", desc_obj);
|
|
||||||
|
|
||||||
if ((obj = pdfioFileCreateObj(pdf, dict)) != NULL)
|
|
||||||
pdfioObjClose(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
|
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
_pdfioObjSetExtension(obj, font, (_pdfio_extfree_t)ttfDelete);
|
if (st)
|
||||||
|
pdfioStreamClose(st);
|
||||||
|
else
|
||||||
|
pdfioObjClose(file_obj);
|
||||||
|
|
||||||
return (obj);
|
ttfDelete(font);
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2233,7 +1993,7 @@ pdfioFileCreateImageObjFromFile(
|
|||||||
// 'pdfioImageGetBytesPerLine()' - Get the number of bytes to read for each line.
|
// 'pdfioImageGetBytesPerLine()' - Get the number of bytes to read for each line.
|
||||||
//
|
//
|
||||||
|
|
||||||
size_t // O - Number of bytes per line
|
size_t // O - Number of bytes per line or `0` on error
|
||||||
pdfioImageGetBytesPerLine(
|
pdfioImageGetBytesPerLine(
|
||||||
pdfio_obj_t *obj) // I - Image object
|
pdfio_obj_t *obj) // I - Image object
|
||||||
{
|
{
|
||||||
@ -2279,7 +2039,25 @@ pdfioImageGetBytesPerLine(
|
|||||||
colors = 1;
|
colors = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (width < 0)
|
||||||
|
{
|
||||||
|
_pdfioFileError(obj->pdf, "Invalid image width %d.", width);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
else if (bpc != 1 && bpc != 2 && bpc != 4 && bpc != 8 && bpc != 16)
|
||||||
|
{
|
||||||
|
_pdfioFileError(obj->pdf, "Invalid image bits per component %d.", bpc);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
else if (colors < 1 || colors > 4)
|
||||||
|
{
|
||||||
|
_pdfioFileError(obj->pdf, "Invalid image number of colors %d.", colors);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return ((size_t)((width * colors * bpc + 7) / 8));
|
return ((size_t)((width * colors * bpc + 7) / 8));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3289,6 +3067,351 @@ create_cp1252(pdfio_file_t *pdf) // I - PDF file
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'create_font()' - Create the object for a TrueType font.
|
||||||
|
//
|
||||||
|
|
||||||
|
static pdfio_obj_t * // O - Font object
|
||||||
|
create_font(pdfio_obj_t *file_obj, // I - Font file object
|
||||||
|
ttf_t *font, // I - TrueType font
|
||||||
|
bool unicode) // I - Force Unicode
|
||||||
|
{
|
||||||
|
ttf_rect_t bounds; // Font bounds
|
||||||
|
pdfio_dict_t *dict, // Font dictionary
|
||||||
|
*desc; // Font descriptor
|
||||||
|
pdfio_obj_t *obj = NULL, // Font object
|
||||||
|
*desc_obj; // Font descriptor object
|
||||||
|
const char *basefont; // Base font name
|
||||||
|
pdfio_array_t *bbox; // Font bounding box array
|
||||||
|
pdfio_stream_t *st; // Font stream
|
||||||
|
|
||||||
|
|
||||||
|
// Create the font descriptor dictionary and object...
|
||||||
|
if ((bbox = pdfioArrayCreate(file_obj->pdf)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
ttfGetBounds(font, &bounds);
|
||||||
|
|
||||||
|
pdfioArrayAppendNumber(bbox, bounds.left);
|
||||||
|
pdfioArrayAppendNumber(bbox, bounds.bottom);
|
||||||
|
pdfioArrayAppendNumber(bbox, bounds.right);
|
||||||
|
pdfioArrayAppendNumber(bbox, bounds.top);
|
||||||
|
|
||||||
|
if ((desc = pdfioDictCreate(file_obj->pdf)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if ((basefont = pdfioStringCreate(file_obj->pdf, ttfGetPostScriptName(font))) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pdfioDictSetName(desc, "Type", "FontDescriptor");
|
||||||
|
pdfioDictSetName(desc, "FontName", basefont);
|
||||||
|
pdfioDictSetObj(desc, "FontFile2", file_obj);
|
||||||
|
pdfioDictSetNumber(desc, "Flags", ttfIsFixedPitch(font) ? 0x21 : 0x20);
|
||||||
|
pdfioDictSetArray(desc, "FontBBox", bbox);
|
||||||
|
pdfioDictSetNumber(desc, "ItalicAngle", ttfGetItalicAngle(font));
|
||||||
|
pdfioDictSetNumber(desc, "Ascent", ttfGetAscent(font));
|
||||||
|
pdfioDictSetNumber(desc, "Descent", ttfGetDescent(font));
|
||||||
|
pdfioDictSetNumber(desc, "CapHeight", ttfGetCapHeight(font));
|
||||||
|
pdfioDictSetNumber(desc, "XHeight", ttfGetXHeight(font));
|
||||||
|
// Note: No TrueType value exists for this but PDF requires it, so we
|
||||||
|
// calculate a generic value from 50 to 250 based on the weight...
|
||||||
|
pdfioDictSetNumber(desc, "StemV", ttfGetWeight(font) / 4 + 25);
|
||||||
|
|
||||||
|
if ((desc_obj = pdfioFileCreateObj(file_obj->pdf, desc)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pdfioObjClose(desc_obj);
|
||||||
|
|
||||||
|
if (unicode)
|
||||||
|
{
|
||||||
|
// Unicode (CID) font...
|
||||||
|
pdfio_dict_t *cid2gid, // CIDToGIDMap dictionary
|
||||||
|
*to_unicode; // ToUnicode dictionary
|
||||||
|
pdfio_obj_t *cid2gid_obj, // CIDToGIDMap object
|
||||||
|
*to_unicode_obj;// ToUnicode object
|
||||||
|
size_t i, j, // Looping vars
|
||||||
|
num_cmap; // Number of CMap entries
|
||||||
|
const int *cmap; // CMap entries
|
||||||
|
int min_glyph, // First glyph
|
||||||
|
max_glyph; // Last glyph
|
||||||
|
unsigned short glyphs[65536]; // Glyph to Unicode mapping
|
||||||
|
unsigned char buffer[16384], // Read buffer
|
||||||
|
*bufptr, // Pointer into buffer
|
||||||
|
*bufend; // End of buffer
|
||||||
|
pdfio_dict_t *type2; // CIDFontType2 font dictionary
|
||||||
|
pdfio_obj_t *type2_obj; // CIDFontType2 font object
|
||||||
|
pdfio_array_t *descendants; // Decendant font list
|
||||||
|
pdfio_dict_t *sidict; // CIDSystemInfo dictionary
|
||||||
|
pdfio_array_t *w_array, // Width array
|
||||||
|
*temp_array; // Temporary width sub-array
|
||||||
|
int w0, w1; // Widths
|
||||||
|
|
||||||
|
// Create a CIDSystemInfo mapping to Adobe UCS2 v0 (Unicode)
|
||||||
|
if ((sidict = pdfioDictCreate(file_obj->pdf)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pdfioDictSetString(sidict, "Registry", "Adobe");
|
||||||
|
pdfioDictSetString(sidict, "Ordering", "Identity");
|
||||||
|
pdfioDictSetNumber(sidict, "Supplement", 0);
|
||||||
|
|
||||||
|
// Create a CIDToGIDMap object for the Unicode font...
|
||||||
|
if ((cid2gid = pdfioDictCreate(file_obj->pdf)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
#ifndef DEBUG
|
||||||
|
pdfioDictSetName(cid2gid, "Filter", "FlateDecode");
|
||||||
|
#endif // !DEBUG
|
||||||
|
|
||||||
|
if ((cid2gid_obj = pdfioFileCreateObj(file_obj->pdf, cid2gid)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_NONE)) == NULL)
|
||||||
|
#else
|
||||||
|
if ((st = pdfioObjCreateStream(cid2gid_obj, PDFIO_FILTER_FLATE)) == NULL)
|
||||||
|
#endif // DEBUG
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
cmap = ttfGetCMap(font, &num_cmap);
|
||||||
|
min_glyph = 65536;
|
||||||
|
max_glyph = 0;
|
||||||
|
memset(glyphs, 0, sizeof(glyphs));
|
||||||
|
|
||||||
|
PDFIO_DEBUG("create_font: num_cmap=%u\n", (unsigned)num_cmap);
|
||||||
|
|
||||||
|
for (i = 0, bufptr = buffer, bufend = buffer + sizeof(buffer); i < num_cmap; i ++)
|
||||||
|
{
|
||||||
|
PDFIO_DEBUG("create_font: cmap[%u]=%d\n", (unsigned)i, cmap[i]);
|
||||||
|
if (cmap[i] < 0 || cmap[i] >= (int)(sizeof(glyphs) / sizeof(glyphs[0])))
|
||||||
|
{
|
||||||
|
// Map undefined glyph to .notdef...
|
||||||
|
*bufptr++ = 0;
|
||||||
|
*bufptr++ = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Map to specified glyph...
|
||||||
|
*bufptr++ = (unsigned char)(cmap[i] >> 8);
|
||||||
|
*bufptr++ = (unsigned char)(cmap[i] & 255);
|
||||||
|
|
||||||
|
glyphs[cmap[i]] = (unsigned short)i;
|
||||||
|
if (cmap[i] < min_glyph)
|
||||||
|
min_glyph = cmap[i];
|
||||||
|
if (cmap[i] > max_glyph)
|
||||||
|
max_glyph = cmap[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufptr >= bufend)
|
||||||
|
{
|
||||||
|
// Flush buffer...
|
||||||
|
if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer)))
|
||||||
|
{
|
||||||
|
pdfioStreamClose(st);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufptr = buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufptr > buffer)
|
||||||
|
{
|
||||||
|
// Flush buffer...
|
||||||
|
if (!pdfioStreamWrite(st, buffer, (size_t)(bufptr - buffer)))
|
||||||
|
{
|
||||||
|
pdfioStreamClose(st);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfioStreamClose(st);
|
||||||
|
|
||||||
|
// ToUnicode mapping object
|
||||||
|
to_unicode = pdfioDictCreate(file_obj->pdf);
|
||||||
|
pdfioDictSetName(to_unicode, "Type", "CMap");
|
||||||
|
pdfioDictSetName(to_unicode, "CMapName", "Adobe-Identity-UCS2");
|
||||||
|
pdfioDictSetDict(to_unicode, "CIDSystemInfo", sidict);
|
||||||
|
|
||||||
|
#ifndef DEBUG
|
||||||
|
pdfioDictSetName(to_unicode, "Filter", "FlateDecode");
|
||||||
|
#endif // !DEBUG
|
||||||
|
|
||||||
|
if ((to_unicode_obj = pdfioFileCreateObj(file_obj->pdf, to_unicode)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
if ((st = pdfioObjCreateStream(to_unicode_obj, PDFIO_FILTER_NONE)) == NULL)
|
||||||
|
#else
|
||||||
|
if ((st = pdfioObjCreateStream(to_unicode_obj, PDFIO_FILTER_FLATE)) == NULL)
|
||||||
|
#endif // DEBUG
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pdfioStreamPuts(st,
|
||||||
|
"stream\n"
|
||||||
|
"/CIDInit /ProcSet findresource begin\n"
|
||||||
|
"12 dict begin\n"
|
||||||
|
"begincmap\n"
|
||||||
|
"/CIDSystemInfo<<\n"
|
||||||
|
"/Registry (Adobe)\n"
|
||||||
|
"/Ordering (UCS2)\n"
|
||||||
|
"/Supplement 0\n"
|
||||||
|
">> def\n"
|
||||||
|
"/CMapName /Adobe-Identity-UCS2 def\n"
|
||||||
|
"/CMapType 2 def\n"
|
||||||
|
"1 begincodespacerange\n"
|
||||||
|
"<0000> <FFFF>\n"
|
||||||
|
"endcodespacerange\n"
|
||||||
|
"endcmap\n"
|
||||||
|
"CMapName currentdict /CMap defineresource pop\n"
|
||||||
|
"end\n"
|
||||||
|
"end\n");
|
||||||
|
|
||||||
|
pdfioStreamClose(st);
|
||||||
|
|
||||||
|
// Create a CIDFontType2 dictionary for the Unicode font...
|
||||||
|
if ((type2 = pdfioDictCreate(file_obj->pdf)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
// Width array
|
||||||
|
if ((w_array = pdfioArrayCreate(file_obj->pdf)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
for (i = 0, w0 = ttfGetWidth(font, 0), w1 = 0; i < 65536; w0 = w1)
|
||||||
|
{
|
||||||
|
for (j = 1; (i + j) < 65536; j ++)
|
||||||
|
{
|
||||||
|
if ((w1 = ttfGetWidth(font, (int)(i + j))) != w0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j >= 4)
|
||||||
|
{
|
||||||
|
// Encode a long sequence of zeros...
|
||||||
|
// Encode a repeating sequence...
|
||||||
|
pdfioArrayAppendNumber(w_array, (double)i);
|
||||||
|
pdfioArrayAppendNumber(w_array, (double)(i + j - 1));
|
||||||
|
pdfioArrayAppendNumber(w_array, w0);
|
||||||
|
|
||||||
|
i += j;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Encode a non-repeating sequence...
|
||||||
|
pdfioArrayAppendNumber(w_array, (double)i);
|
||||||
|
|
||||||
|
if ((temp_array = pdfioArrayCreate(file_obj->pdf)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pdfioArrayAppendNumber(temp_array, w0);
|
||||||
|
for (i ++; i < 65536 && pdfioArrayGetSize(temp_array) < 8191; i ++, w0 = w1)
|
||||||
|
{
|
||||||
|
if ((w1 = ttfGetWidth(font, (int)i)) == w0 && i < 65530)
|
||||||
|
{
|
||||||
|
for (j = 1; j < 4; j ++)
|
||||||
|
{
|
||||||
|
if (ttfGetWidth(font, (int)(i + j)) != w0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j >= 4)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfioArrayAppendNumber(temp_array, w1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfioArrayAppendArray(w_array, temp_array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then the dictionary for the CID base font...
|
||||||
|
pdfioDictSetName(type2, "Type", "Font");
|
||||||
|
pdfioDictSetName(type2, "Subtype", "CIDFontType2");
|
||||||
|
pdfioDictSetName(type2, "BaseFont", basefont);
|
||||||
|
pdfioDictSetDict(type2, "CIDSystemInfo", sidict);
|
||||||
|
pdfioDictSetObj(type2, "CIDToGIDMap", cid2gid_obj);
|
||||||
|
pdfioDictSetObj(type2, "FontDescriptor", desc_obj);
|
||||||
|
pdfioDictSetArray(type2, "W", w_array);
|
||||||
|
|
||||||
|
if ((type2_obj = pdfioFileCreateObj(file_obj->pdf, type2)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pdfioObjClose(type2_obj);
|
||||||
|
|
||||||
|
// Create a Type 0 font object...
|
||||||
|
if ((descendants = pdfioArrayCreate(file_obj->pdf)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pdfioArrayAppendObj(descendants, type2_obj);
|
||||||
|
|
||||||
|
if ((dict = pdfioDictCreate(file_obj->pdf)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pdfioDictSetName(dict, "Type", "Font");
|
||||||
|
pdfioDictSetName(dict, "Subtype", "Type0");
|
||||||
|
pdfioDictSetName(dict, "BaseFont", basefont);
|
||||||
|
pdfioDictSetArray(dict, "DescendantFonts", descendants);
|
||||||
|
pdfioDictSetName(dict, "Encoding", "Identity-H");
|
||||||
|
pdfioDictSetObj(dict, "ToUnicode", to_unicode_obj);
|
||||||
|
|
||||||
|
if ((obj = pdfioFileCreateObj(file_obj->pdf, dict)) != NULL)
|
||||||
|
pdfioObjClose(obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Simple (CP1282 or custom encoding) 8-bit font...
|
||||||
|
int ch; // Character
|
||||||
|
pdfio_array_t *w_array; // Widths array
|
||||||
|
|
||||||
|
if (ttfGetMaxChar(font) >= 255 && !file_obj->pdf->cp1252_obj && !create_cp1252(file_obj->pdf))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
// Create a TrueType font object...
|
||||||
|
if ((dict = pdfioDictCreate(file_obj->pdf)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pdfioDictSetName(dict, "Type", "Font");
|
||||||
|
pdfioDictSetName(dict, "Subtype", "TrueType");
|
||||||
|
pdfioDictSetName(dict, "BaseFont", basefont);
|
||||||
|
pdfioDictSetNumber(dict, "FirstChar", 32);
|
||||||
|
if (ttfGetMaxChar(font) >= 255)
|
||||||
|
{
|
||||||
|
pdfioDictSetObj(dict, "Encoding", file_obj->pdf->cp1252_obj);
|
||||||
|
pdfioDictSetNumber(dict, "LastChar", 255);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pdfioDictSetNumber(dict, "LastChar", ttfGetMaxChar(font));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a Widths array for CP1252/WinAnsiEncoding
|
||||||
|
if ((w_array = pdfioArrayCreate(file_obj->pdf)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
for (ch = 32; ch < 256 && ch < ttfGetMaxChar(font); ch ++)
|
||||||
|
{
|
||||||
|
if (ch >= 0x80 && ch < 0xa0)
|
||||||
|
pdfioArrayAppendNumber(w_array, ttfGetWidth(font, _pdfio_cp1252[ch - 0x80]));
|
||||||
|
else
|
||||||
|
pdfioArrayAppendNumber(w_array, ttfGetWidth(font, ch));
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfioDictSetArray(dict, "Widths", w_array);
|
||||||
|
|
||||||
|
pdfioDictSetObj(dict, "FontDescriptor", desc_obj);
|
||||||
|
|
||||||
|
if ((obj = pdfioFileCreateObj(file_obj->pdf, dict)) != NULL)
|
||||||
|
pdfioObjClose(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
_pdfioObjSetExtension(obj, font, (_pdfio_extfree_t)ttfDelete);
|
||||||
|
|
||||||
|
return (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'create_image()' - Create an image object from some data.
|
// 'create_image()' - Create an image object from some data.
|
||||||
//
|
//
|
||||||
|
@ -128,6 +128,7 @@ extern bool pdfioContentTextShowJustified(pdfio_stream_t *st, bool unicode, siz
|
|||||||
|
|
||||||
// Resource helpers...
|
// Resource helpers...
|
||||||
extern pdfio_obj_t *pdfioFileCreateFontObjFromBase(pdfio_file_t *pdf, const char *name) _PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileCreateFontObjFromBase(pdfio_file_t *pdf, const char *name) _PDFIO_PUBLIC;
|
||||||
|
extern pdfio_obj_t *pdfioFileCreateFontObjFromData(pdfio_file_t *pdf, const void *data, size_t datasize, bool unicode) _PDFIO_PUBLIC;
|
||||||
extern pdfio_obj_t *pdfioFileCreateFontObjFromFile(pdfio_file_t *pdf, const char *filename, bool unicode) _PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileCreateFontObjFromFile(pdfio_file_t *pdf, const char *filename, bool unicode) _PDFIO_PUBLIC;
|
||||||
extern pdfio_obj_t *pdfioFileCreateICCObjFromData(pdfio_file_t *pdf, const unsigned char *data, size_t datalen, size_t num_colors) _PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileCreateICCObjFromData(pdfio_file_t *pdf, const unsigned char *data, size_t datalen, size_t num_colors) _PDFIO_PUBLIC;
|
||||||
extern pdfio_obj_t *pdfioFileCreateICCObjFromFile(pdfio_file_t *pdf, const char *filename, size_t num_colors) _PDFIO_PUBLIC;
|
extern pdfio_obj_t *pdfioFileCreateICCObjFromFile(pdfio_file_t *pdf, const char *filename, size_t num_colors) _PDFIO_PUBLIC;
|
||||||
|
4
pdfio.h
4
pdfio.h
@ -23,9 +23,9 @@ extern "C" {
|
|||||||
// Version numbers...
|
// Version numbers...
|
||||||
//
|
//
|
||||||
|
|
||||||
# define PDFIO_VERSION "1.5.2"
|
# define PDFIO_VERSION "1.6.0"
|
||||||
# define PDFIO_VERSION_MAJOR 1
|
# define PDFIO_VERSION_MAJOR 1
|
||||||
# define PDFIO_VERSION_MINOR 5
|
# define PDFIO_VERSION_MINOR 6
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<metadata>
|
<metadata>
|
||||||
<id>pdfio_native</id>
|
<id>pdfio_native</id>
|
||||||
<title>PDFio Library for VS2019+</title>
|
<title>PDFio Library for VS2019+</title>
|
||||||
<version>1.5.1</version>
|
<version>1.6.0</version>
|
||||||
<authors>Michael R Sweet</authors>
|
<authors>Michael R Sweet</authors>
|
||||||
<owners>michaelrsweet</owners>
|
<owners>michaelrsweet</owners>
|
||||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
<copyright>Copyright © 2019-2025 by Michael R Sweet</copyright>
|
<copyright>Copyright © 2019-2025 by Michael R Sweet</copyright>
|
||||||
<tags>pdf file native</tags>
|
<tags>pdf file native</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="pdfio_native.redist" version="1.5.1" />
|
<dependency id="pdfio_native.redist" version="1.6.0" />
|
||||||
<dependency id="libpng_native.redist" version="1.6.30" />
|
<dependency id="libpng_native.redist" version="1.6.30" />
|
||||||
<dependency id="zlib_native.redist" version="1.2.11" />
|
<dependency id="zlib_native.redist" version="1.2.11" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<metadata>
|
<metadata>
|
||||||
<id>pdfio_native.redist</id>
|
<id>pdfio_native.redist</id>
|
||||||
<title>PDFio Library for VS2019+</title>
|
<title>PDFio Library for VS2019+</title>
|
||||||
<version>1.5.1</version>
|
<version>1.6.0</version>
|
||||||
<authors>Michael R Sweet</authors>
|
<authors>Michael R Sweet</authors>
|
||||||
<owners>michaelrsweet</owners>
|
<owners>michaelrsweet</owners>
|
||||||
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
<projectUrl>https://github.com/michaelrsweet/pappl</projectUrl>
|
||||||
|
93
testttf.c
93
testttf.c
@ -3,7 +3,7 @@
|
|||||||
//
|
//
|
||||||
// https://github.com/michaelrsweet/ttf
|
// https://github.com/michaelrsweet/ttf
|
||||||
//
|
//
|
||||||
// Copyright © 2018-2024 by Michael R Sweet.
|
// Copyright © 2018-2025 by Michael R Sweet.
|
||||||
//
|
//
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
// information.
|
// information.
|
||||||
@ -14,6 +14,10 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include "ttf.h"
|
#include "ttf.h"
|
||||||
|
|
||||||
|
|
||||||
@ -81,9 +85,13 @@ test_font(const char *filename) // I - Font filename
|
|||||||
int i, // Looping var
|
int i, // Looping var
|
||||||
errors = 0; // Number of errors
|
errors = 0; // Number of errors
|
||||||
ttf_t *font; // Font
|
ttf_t *font; // Font
|
||||||
|
struct stat fileinfo; // Font file information
|
||||||
|
FILE *fp = NULL; // File pointer
|
||||||
|
void *data = NULL; // Memory buffer for font file
|
||||||
const char *value; // Font (string) value
|
const char *value; // Font (string) value
|
||||||
int intvalue; // Font (integer) value
|
int intvalue; // Font (integer) value
|
||||||
float realvalue; // Font (real) value
|
float realvalue; // Font (real) value
|
||||||
|
char psname[1024]; // Postscript font name
|
||||||
ttf_rect_t bounds; // Bounds
|
ttf_rect_t bounds; // Bounds
|
||||||
ttf_rect_t extents; // Extents
|
ttf_rect_t extents; // Extents
|
||||||
size_t num_fonts; // Number of fonts
|
size_t num_fonts; // Number of fonts
|
||||||
@ -220,6 +228,9 @@ test_font(const char *filename) // I - Font filename
|
|||||||
if ((value = ttfGetPostScriptName(font)) != NULL)
|
if ((value = ttfGetPostScriptName(font)) != NULL)
|
||||||
{
|
{
|
||||||
printf("PASS (%s)\n", value);
|
printf("PASS (%s)\n", value);
|
||||||
|
|
||||||
|
strncpy(psname, value, sizeof(psname) - 1);
|
||||||
|
psname[sizeof(psname) - 1] = '\0';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -300,6 +311,86 @@ test_font(const char *filename) // I - Font filename
|
|||||||
puts("PASS (false)");
|
puts("PASS (false)");
|
||||||
|
|
||||||
ttfDelete(font);
|
ttfDelete(font);
|
||||||
|
font = NULL;
|
||||||
|
|
||||||
|
// Now copy the font to memory and open it that way...
|
||||||
|
printf("fopen(\"%s\", \"rb\"): ", filename);
|
||||||
|
if ((fp = fopen(filename, "rb")) == NULL)
|
||||||
|
{
|
||||||
|
printf("FAIL (%s)\n", strerror(errno));
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("PASS (%d)\n", fileno(fp));
|
||||||
|
printf("fstat(%d): ", fileno(fp));
|
||||||
|
if (fstat(fileno(fp), &fileinfo))
|
||||||
|
{
|
||||||
|
printf("FAIL (%s)\n", strerror(errno));
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("PASS (%lu bytes)\n", (unsigned long)fileinfo.st_size);
|
||||||
|
|
||||||
|
fputs("malloc(): ", stdout);
|
||||||
|
if ((data = malloc((size_t)fileinfo.st_size)) == NULL)
|
||||||
|
{
|
||||||
|
printf("FAIL (%s)\n", strerror(errno));
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("PASS");
|
||||||
|
fputs("fread(): ", stdout);
|
||||||
|
if (fread(data, (size_t)fileinfo.st_size, 1, fp) != 1)
|
||||||
|
{
|
||||||
|
printf("FAIL (%s)\n", strerror(errno));
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("PASS");
|
||||||
|
fputs("ttfCreateData(): ", stdout);
|
||||||
|
if ((font = ttfCreateData(data, (size_t)fileinfo.st_size, /*idx*/0, error_cb, /*err_data*/NULL)) == NULL)
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("PASS");
|
||||||
|
|
||||||
|
fputs("ttfGetPostScriptName: ", stdout);
|
||||||
|
if ((value = ttfGetPostScriptName(font)) != NULL)
|
||||||
|
{
|
||||||
|
if (!strcmp(value, psname))
|
||||||
|
{
|
||||||
|
printf("PASS (%s)\n", value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL (got \"%s\", expected \"%s\")\n", value, psname);
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts("FAIL");
|
||||||
|
errors ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fp)
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
ttfDelete(font);
|
||||||
|
}
|
||||||
|
|
||||||
return (errors);
|
return (errors);
|
||||||
}
|
}
|
||||||
|
564
ttf.c
564
ttf.c
@ -177,9 +177,19 @@ typedef struct _ttf_off_names_s // OFF/TTF naming table
|
|||||||
unsigned storage_size; // Size of storage area
|
unsigned storage_size; // Size of storage area
|
||||||
} _ttf_off_names_t;
|
} _ttf_off_names_t;
|
||||||
|
|
||||||
|
typedef size_t (*_ttf_read_cb_t)(ttf_t *font, void *buffer, size_t bytes);
|
||||||
|
// Font read callback, returns number of bytes read
|
||||||
|
typedef bool (*_ttf_seek_cb_t)(ttf_t *font, size_t offset);
|
||||||
|
// Font seek callback, returns `true` on success
|
||||||
|
|
||||||
struct _ttf_s
|
struct _ttf_s
|
||||||
{
|
{
|
||||||
int fd; // File descriptor
|
_ttf_read_cb_t read_cb; // Read callback
|
||||||
|
_ttf_seek_cb_t seek_cb; // Seek callback
|
||||||
|
int file_fd; // File descriptor for ttfCreate
|
||||||
|
const char *data; // Font data for ttfCreateData
|
||||||
|
size_t data_size; // Size of font data for ttfCreateData
|
||||||
|
size_t data_offset; // Offset within input
|
||||||
size_t idx; // Font number in file
|
size_t idx; // Font number in file
|
||||||
ttf_err_cb_t err_cb; // Error callback, if any
|
ttf_err_cb_t err_cb; // Error callback, if any
|
||||||
void *err_data; // Error callback data
|
void *err_data; // Error callback data
|
||||||
@ -282,7 +292,12 @@ typedef struct _ttf_off_post_s // PostScript information
|
|||||||
//
|
//
|
||||||
|
|
||||||
static char *copy_name(ttf_t *font, unsigned name_id);
|
static char *copy_name(ttf_t *font, unsigned name_id);
|
||||||
|
static ttf_t *create_font(const char *filename, const void *data, size_t datasize, size_t idx, ttf_err_cb_t err_cb, void *err_data);
|
||||||
static void errorf(ttf_t *font, const char *message, ...) TTF_FORMAT_ARGS(2,3);
|
static void errorf(ttf_t *font, const char *message, ...) TTF_FORMAT_ARGS(2,3);
|
||||||
|
static size_t fd_read_cb(ttf_t *font, void *buffer, size_t bytes);
|
||||||
|
static bool fd_seek_cb(ttf_t *font, size_t offset);
|
||||||
|
static size_t mem_read_cb(ttf_t *font, void *buffer, size_t bytes);
|
||||||
|
static bool mem_seek_cb(ttf_t *font, size_t offset);
|
||||||
static bool read_cmap(ttf_t *font);
|
static bool read_cmap(ttf_t *font);
|
||||||
static bool read_head(ttf_t *font, _ttf_off_head_t *head);
|
static bool read_head(ttf_t *font, _ttf_off_head_t *head);
|
||||||
static bool read_hhea(ttf_t *font, _ttf_off_hhea_t *hhea);
|
static bool read_hhea(ttf_t *font, _ttf_off_hhea_t *hhea);
|
||||||
@ -329,15 +344,6 @@ ttfCreate(const char *filename, // I - Filename
|
|||||||
ttf_err_cb_t err_cb, // I - Error callback or `NULL` to log to stderr
|
ttf_err_cb_t err_cb, // I - Error callback or `NULL` to log to stderr
|
||||||
void *err_data) // I - Error callback data
|
void *err_data) // I - Error callback data
|
||||||
{
|
{
|
||||||
ttf_t *font = NULL; // New font object
|
|
||||||
size_t i; // Looping var
|
|
||||||
_ttf_metric_t *widths = NULL; // Glyph metrics
|
|
||||||
_ttf_off_head_t head; // head table
|
|
||||||
_ttf_off_hhea_t hhea; // hhea table
|
|
||||||
_ttf_off_os_2_t os_2; // OS/2 table
|
|
||||||
_ttf_off_post_t post; // PostScript table
|
|
||||||
|
|
||||||
|
|
||||||
TTF_DEBUG("ttfCreate(filename=\"%s\", idx=%u, err_cb=%p, err_data=%p)\n", filename, (unsigned)idx, err_cb, err_data);
|
TTF_DEBUG("ttfCreate(filename=\"%s\", idx=%u, err_cb=%p, err_data=%p)\n", filename, (unsigned)idx, err_cb, err_data);
|
||||||
|
|
||||||
// Range check input..
|
// Range check input..
|
||||||
@ -347,178 +353,57 @@ ttfCreate(const char *filename, // I - Filename
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate memory...
|
// Open and return the font...
|
||||||
if ((font = (ttf_t *)calloc(1, sizeof(ttf_t))) == NULL)
|
return (create_font(filename, /*data*/NULL, /*datasize*/0, idx, err_cb, err_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'ttfCreateData()' - Create a new font object from a memory buffer.
|
||||||
|
//
|
||||||
|
// This function creates a new font object from a memory buffer. The "data"
|
||||||
|
// argument specifies a pointer to the first byte of data and the "datasize"
|
||||||
|
// argument specifies the length of the memory buffer in bytes.
|
||||||
|
//
|
||||||
|
// > Note: The caller is responsible for ensuring that the memory buffer is
|
||||||
|
// > available until the font object is deleted with @link ttfDelete@.
|
||||||
|
//
|
||||||
|
// The "idx" argument specifies the font to load from a collection - the first
|
||||||
|
// font is number `0`. Once created, you can call the @link ttfGetNumFonts@
|
||||||
|
// function to determine whether the loaded font file is a collection with more
|
||||||
|
// than one font.
|
||||||
|
//
|
||||||
|
// The "err_cb" and "err_data" arguments specify a callback function and data
|
||||||
|
// pointer for receiving error messages. If `NULL`, errors are sent to the
|
||||||
|
// `stderr` file. The callback function receives the data pointer and a text
|
||||||
|
// message string, for example:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// void my_err_cb(void *err_data, const char *message)
|
||||||
|
// {
|
||||||
|
// fprintf(stderr, "ERROR: %s\n", message);
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
|
||||||
|
ttf_t * // O - New font object
|
||||||
|
ttfCreateData(const void *data, // I - Buffer
|
||||||
|
size_t datasize, // I - Size of buffer in bytes
|
||||||
|
size_t idx, // I - Font number to create in collection (0-based)
|
||||||
|
ttf_err_cb_t err_cb, // I - Error callback or `NULL` to log to stderr
|
||||||
|
void *err_data) // I - Error callback data
|
||||||
|
{
|
||||||
|
TTF_DEBUG("ttfCreateData(data=%p, datasize=%lu, idx=%u, err_cb=%p, err_data=%p)\n", data, (unsigned long)datasize, (unsigned)idx, err_cb, err_data);
|
||||||
|
|
||||||
|
// Range check input..
|
||||||
|
if (!data || datasize == 0)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
font->idx = idx;
|
|
||||||
font->err_cb = err_cb;
|
|
||||||
font->err_data = err_data;
|
|
||||||
|
|
||||||
// Open the font file...
|
|
||||||
if ((font->fd = open(filename, O_RDONLY | O_BINARY)) < 0)
|
|
||||||
{
|
|
||||||
errorf(font, "Unable to open '%s': %s", filename, strerror(errno));
|
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TTF_DEBUG("ttfCreate: fd=%d\n", font->fd);
|
// Open and return the font...
|
||||||
|
return (create_font(/*filename*/NULL, data, datasize, idx, err_cb, err_data));
|
||||||
// Read the table of contents and the identifying names...
|
|
||||||
if (!read_table(font))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
TTF_DEBUG("ttfCreate: num_entries=%d\n", font->table.num_entries);
|
|
||||||
|
|
||||||
if (!read_names(font))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
TTF_DEBUG("ttfCreate: num_names=%d\n", font->names.num_names);
|
|
||||||
|
|
||||||
// Copy key font meta data strings...
|
|
||||||
font->copyright = copy_name(font, TTF_OFF_Copyright);
|
|
||||||
font->family = copy_name(font, TTF_OFF_FontFamily);
|
|
||||||
font->postscript_name = copy_name(font, TTF_OFF_PostScriptName);
|
|
||||||
font->version = copy_name(font, TTF_OFF_FontVersion);
|
|
||||||
|
|
||||||
if (read_post(font, &post))
|
|
||||||
{
|
|
||||||
font->italic_angle = post.italicAngle;
|
|
||||||
font->is_fixed = post.isFixedPitch != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
TTF_DEBUG("ttfCreate: copyright=\"%s\"\n", font->copyright);
|
|
||||||
TTF_DEBUG("ttfCreate: family=\"%s\"\n", font->family);
|
|
||||||
TTF_DEBUG("ttfCreate: postscript_name=\"%s\"\n", font->postscript_name);
|
|
||||||
TTF_DEBUG("ttfCreate: version=\"%s\"\n", font->version);
|
|
||||||
TTF_DEBUG("ttfCreate: italic_angle=%g\n", font->italic_angle);
|
|
||||||
TTF_DEBUG("ttfCreate: is_fixed=%s\n", font->is_fixed ? "true" : "false");
|
|
||||||
|
|
||||||
if (!read_cmap(font))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (!read_head(font, &head))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
font->units = (float)head.unitsPerEm;
|
|
||||||
font->x_max = head.xMax;
|
|
||||||
font->x_min = head.xMin;
|
|
||||||
font->y_max = head.yMax;
|
|
||||||
font->y_min = head.yMin;
|
|
||||||
|
|
||||||
if (head.macStyle & TTF_OFF_macStyle_Italic)
|
|
||||||
{
|
|
||||||
if (font->postscript_name && strstr(font->postscript_name, "Oblique"))
|
|
||||||
font->style = TTF_STYLE_OBLIQUE;
|
|
||||||
else
|
|
||||||
font->style = TTF_STYLE_ITALIC;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
font->style = TTF_STYLE_NORMAL;
|
|
||||||
|
|
||||||
if (!read_hhea(font, &hhea))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
font->ascent = hhea.ascender;
|
|
||||||
font->descent = hhea.descender;
|
|
||||||
|
|
||||||
if (read_maxp(font) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (hhea.numberOfHMetrics > 0)
|
|
||||||
{
|
|
||||||
if ((widths = read_hmtx(font, &hhea)) == NULL)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
errorf(font, "Number of horizontal metrics is 0.");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read_os_2(font, &os_2))
|
|
||||||
{
|
|
||||||
// Copy key values from OS/2 table...
|
|
||||||
static const ttf_stretch_t stretches[] =
|
|
||||||
{
|
|
||||||
TTF_STRETCH_ULTRA_CONDENSED, // ultra-condensed
|
|
||||||
TTF_STRETCH_EXTRA_CONDENSED, // extra-condensed
|
|
||||||
TTF_STRETCH_CONDENSED, // condensed
|
|
||||||
TTF_STRETCH_SEMI_CONDENSED, // semi-condensed
|
|
||||||
TTF_STRETCH_NORMAL, // normal
|
|
||||||
TTF_STRETCH_SEMI_EXPANDED, // semi-expanded
|
|
||||||
TTF_STRETCH_EXPANDED, // expanded
|
|
||||||
TTF_STRETCH_EXTRA_EXPANDED, // extra-expanded
|
|
||||||
TTF_STRETCH_ULTRA_EXPANDED // ultra-expanded
|
|
||||||
};
|
|
||||||
|
|
||||||
if (os_2.usWidthClass >= 1 && os_2.usWidthClass <= (int)(sizeof(stretches) / sizeof(stretches[0])))
|
|
||||||
font->stretch = stretches[os_2.usWidthClass - 1];
|
|
||||||
|
|
||||||
font->weight = (short)os_2.usWeightClass;
|
|
||||||
font->cap_height = os_2.sCapHeight;
|
|
||||||
font->x_height = os_2.sxHeight;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Default key values since there isn't an OS/2 table...
|
|
||||||
TTF_DEBUG("ttfCreate: Unable to read OS/2 table.\n");
|
|
||||||
|
|
||||||
font->weight = 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (font->cap_height == 0)
|
|
||||||
font->cap_height = font->ascent;
|
|
||||||
|
|
||||||
if (font->x_height == 0)
|
|
||||||
font->x_height = 3 * font->ascent / 5;
|
|
||||||
|
|
||||||
// Build a sparse glyph widths table...
|
|
||||||
font->min_char = -1;
|
|
||||||
|
|
||||||
for (i = 0; i < font->num_cmap; i ++)
|
|
||||||
{
|
|
||||||
if (font->cmap[i] >= 0)
|
|
||||||
{
|
|
||||||
int bin = (int)i / 256, // Sub-array bin
|
|
||||||
glyph = font->cmap[i]; // Glyph index
|
|
||||||
|
|
||||||
// Update min/max...
|
|
||||||
if (font->min_char < 0)
|
|
||||||
font->min_char = (int)i;
|
|
||||||
|
|
||||||
font->max_char = (int)i;
|
|
||||||
|
|
||||||
// Allocate a sub-array as needed...
|
|
||||||
if (!font->widths[bin])
|
|
||||||
font->widths[bin] = (_ttf_metric_t *)calloc(256, sizeof(_ttf_metric_t));
|
|
||||||
|
|
||||||
// Copy the width of the specified glyph or the last one if we are past
|
|
||||||
// the end of the table...
|
|
||||||
if (glyph >= hhea.numberOfHMetrics)
|
|
||||||
font->widths[bin][i & 255] = widths[hhea.numberOfHMetrics - 1];
|
|
||||||
else
|
|
||||||
font->widths[bin][i & 255] = widths[glyph];
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (i >= ' ' && i < 127 && font->widths[0])
|
|
||||||
TTF_DEBUG("ttfCreate: width['%c']=%d(%d)\n", (char)i, font->widths[0][i].width, font->widths[0][i].left_bearing);
|
|
||||||
#endif // DEBUG
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup and return the font...
|
|
||||||
free(widths);
|
|
||||||
|
|
||||||
return (font);
|
|
||||||
|
|
||||||
// If we get here something bad happened...
|
|
||||||
error:
|
|
||||||
|
|
||||||
free(widths);
|
|
||||||
ttfDelete(font);
|
|
||||||
|
|
||||||
return (NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -537,8 +422,8 @@ ttfDelete(ttf_t *font) // I - Font
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Close the font file...
|
// Close the font file...
|
||||||
if (font->fd >= 0)
|
if (font->file_fd >= 0)
|
||||||
close(font->fd);
|
close(font->file_fd);
|
||||||
|
|
||||||
// Free all memory used...
|
// Free all memory used...
|
||||||
free(font->copyright);
|
free(font->copyright);
|
||||||
@ -1043,6 +928,219 @@ copy_name(ttf_t *font, // I - Font
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'create_font()' - Create a font object from the file or data.
|
||||||
|
//
|
||||||
|
|
||||||
|
static ttf_t *
|
||||||
|
create_font(const char *filename, // I - Filename of `NULL`
|
||||||
|
const void *data, // I - Data pointer or `NULL`
|
||||||
|
size_t datasize, // I - Size of data or 0
|
||||||
|
size_t idx, // I - Font index
|
||||||
|
ttf_err_cb_t err_cb, // I - Error callback function
|
||||||
|
void *err_data) // I - Error callback data
|
||||||
|
{
|
||||||
|
ttf_t *font = NULL; // New font object
|
||||||
|
size_t i; // Looping var
|
||||||
|
_ttf_metric_t *widths = NULL; // Glyph metrics
|
||||||
|
_ttf_off_head_t head; // head table
|
||||||
|
_ttf_off_hhea_t hhea; // hhea table
|
||||||
|
_ttf_off_os_2_t os_2; // OS/2 table
|
||||||
|
_ttf_off_post_t post; // PostScript table
|
||||||
|
|
||||||
|
|
||||||
|
TTF_DEBUG("create_font(filename=\"%s\", data=%p, datasize=%lu, idx=%u, err_cb=%p, err_data=%p)\n", filename, data, (unsigned long)datasize, (unsigned)idx, err_cb, err_data);
|
||||||
|
|
||||||
|
// Allocate memory...
|
||||||
|
if ((font = (ttf_t *)calloc(1, sizeof(ttf_t))) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
font->idx = idx;
|
||||||
|
font->err_cb = err_cb;
|
||||||
|
font->err_data = err_data;
|
||||||
|
|
||||||
|
if (filename)
|
||||||
|
{
|
||||||
|
// Open the font file...
|
||||||
|
if ((font->file_fd = open(filename, O_RDONLY | O_BINARY)) < 0)
|
||||||
|
{
|
||||||
|
errorf(font, "Unable to open '%s': %s", filename, strerror(errno));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
TTF_DEBUG("create_font: file_fd=%d\n", font->file_fd);
|
||||||
|
|
||||||
|
font->read_cb = fd_read_cb;
|
||||||
|
font->seek_cb = fd_seek_cb;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Read from memory...
|
||||||
|
font->file_fd = -1;
|
||||||
|
font->data = (const char *)data;
|
||||||
|
font->data_size = datasize;
|
||||||
|
font->read_cb = mem_read_cb;
|
||||||
|
font->seek_cb = mem_seek_cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the table of contents and the identifying names...
|
||||||
|
if (!read_table(font))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
TTF_DEBUG("create_font: num_entries=%d\n", font->table.num_entries);
|
||||||
|
|
||||||
|
if (!read_names(font))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
TTF_DEBUG("create_font: num_names=%d\n", font->names.num_names);
|
||||||
|
|
||||||
|
// Copy key font meta data strings...
|
||||||
|
font->copyright = copy_name(font, TTF_OFF_Copyright);
|
||||||
|
font->family = copy_name(font, TTF_OFF_FontFamily);
|
||||||
|
font->postscript_name = copy_name(font, TTF_OFF_PostScriptName);
|
||||||
|
font->version = copy_name(font, TTF_OFF_FontVersion);
|
||||||
|
|
||||||
|
if (read_post(font, &post))
|
||||||
|
{
|
||||||
|
font->italic_angle = post.italicAngle;
|
||||||
|
font->is_fixed = post.isFixedPitch != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TTF_DEBUG("create_font: copyright=\"%s\"\n", font->copyright);
|
||||||
|
TTF_DEBUG("create_font: family=\"%s\"\n", font->family);
|
||||||
|
TTF_DEBUG("create_font: postscript_name=\"%s\"\n", font->postscript_name);
|
||||||
|
TTF_DEBUG("create_font: version=\"%s\"\n", font->version);
|
||||||
|
TTF_DEBUG("create_font: italic_angle=%g\n", font->italic_angle);
|
||||||
|
TTF_DEBUG("create_font: is_fixed=%s\n", font->is_fixed ? "true" : "false");
|
||||||
|
|
||||||
|
if (!read_cmap(font))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!read_head(font, &head))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
font->units = (float)head.unitsPerEm;
|
||||||
|
font->x_max = head.xMax;
|
||||||
|
font->x_min = head.xMin;
|
||||||
|
font->y_max = head.yMax;
|
||||||
|
font->y_min = head.yMin;
|
||||||
|
|
||||||
|
if (head.macStyle & TTF_OFF_macStyle_Italic)
|
||||||
|
{
|
||||||
|
if (font->postscript_name && strstr(font->postscript_name, "Oblique"))
|
||||||
|
font->style = TTF_STYLE_OBLIQUE;
|
||||||
|
else
|
||||||
|
font->style = TTF_STYLE_ITALIC;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
font->style = TTF_STYLE_NORMAL;
|
||||||
|
|
||||||
|
if (!read_hhea(font, &hhea))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
font->ascent = hhea.ascender;
|
||||||
|
font->descent = hhea.descender;
|
||||||
|
|
||||||
|
if (read_maxp(font) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (hhea.numberOfHMetrics > 0)
|
||||||
|
{
|
||||||
|
if ((widths = read_hmtx(font, &hhea)) == NULL)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errorf(font, "Number of horizontal metrics is 0.");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read_os_2(font, &os_2))
|
||||||
|
{
|
||||||
|
// Copy key values from OS/2 table...
|
||||||
|
static const ttf_stretch_t stretches[] =
|
||||||
|
{
|
||||||
|
TTF_STRETCH_ULTRA_CONDENSED, // ultra-condensed
|
||||||
|
TTF_STRETCH_EXTRA_CONDENSED, // extra-condensed
|
||||||
|
TTF_STRETCH_CONDENSED, // condensed
|
||||||
|
TTF_STRETCH_SEMI_CONDENSED, // semi-condensed
|
||||||
|
TTF_STRETCH_NORMAL, // normal
|
||||||
|
TTF_STRETCH_SEMI_EXPANDED, // semi-expanded
|
||||||
|
TTF_STRETCH_EXPANDED, // expanded
|
||||||
|
TTF_STRETCH_EXTRA_EXPANDED, // extra-expanded
|
||||||
|
TTF_STRETCH_ULTRA_EXPANDED // ultra-expanded
|
||||||
|
};
|
||||||
|
|
||||||
|
if (os_2.usWidthClass >= 1 && os_2.usWidthClass <= (int)(sizeof(stretches) / sizeof(stretches[0])))
|
||||||
|
font->stretch = stretches[os_2.usWidthClass - 1];
|
||||||
|
|
||||||
|
font->weight = (short)os_2.usWeightClass;
|
||||||
|
font->cap_height = os_2.sCapHeight;
|
||||||
|
font->x_height = os_2.sxHeight;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Default key values since there isn't an OS/2 table...
|
||||||
|
TTF_DEBUG("create_font: Unable to read OS/2 table.\n");
|
||||||
|
|
||||||
|
font->weight = 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font->cap_height == 0)
|
||||||
|
font->cap_height = font->ascent;
|
||||||
|
|
||||||
|
if (font->x_height == 0)
|
||||||
|
font->x_height = 3 * font->ascent / 5;
|
||||||
|
|
||||||
|
// Build a sparse glyph widths table...
|
||||||
|
font->min_char = -1;
|
||||||
|
|
||||||
|
for (i = 0; i < font->num_cmap; i ++)
|
||||||
|
{
|
||||||
|
if (font->cmap[i] >= 0)
|
||||||
|
{
|
||||||
|
int bin = (int)i / 256, // Sub-array bin
|
||||||
|
glyph = font->cmap[i]; // Glyph index
|
||||||
|
|
||||||
|
// Update min/max...
|
||||||
|
if (font->min_char < 0)
|
||||||
|
font->min_char = (int)i;
|
||||||
|
|
||||||
|
font->max_char = (int)i;
|
||||||
|
|
||||||
|
// Allocate a sub-array as needed...
|
||||||
|
if (!font->widths[bin])
|
||||||
|
font->widths[bin] = (_ttf_metric_t *)calloc(256, sizeof(_ttf_metric_t));
|
||||||
|
|
||||||
|
// Copy the width of the specified glyph or the last one if we are past
|
||||||
|
// the end of the table...
|
||||||
|
if (glyph >= hhea.numberOfHMetrics)
|
||||||
|
font->widths[bin][i & 255] = widths[hhea.numberOfHMetrics - 1];
|
||||||
|
else
|
||||||
|
font->widths[bin][i & 255] = widths[glyph];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (i >= ' ' && i < 127 && font->widths[0])
|
||||||
|
TTF_DEBUG("create_font: width['%c']=%d(%d)\n", (char)i, font->widths[0][i].width, font->widths[0][i].left_bearing);
|
||||||
|
#endif // DEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup and return the font...
|
||||||
|
free(widths);
|
||||||
|
|
||||||
|
return (font);
|
||||||
|
|
||||||
|
// If we get here something bad happened...
|
||||||
|
error:
|
||||||
|
|
||||||
|
free(widths);
|
||||||
|
ttfDelete(font);
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 'errorf()' - Show an error message.
|
// 'errorf()' - Show an error message.
|
||||||
//
|
//
|
||||||
@ -1070,9 +1168,85 @@ errorf(ttf_t *font, // I - Font
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
//
|
||||||
* 'read_cmap()' - Read the cmap table, getting the Unicode mapping table.
|
// 'fd_read_cb()' - Read from a file.
|
||||||
*/
|
//
|
||||||
|
|
||||||
|
static size_t // O - Number of bytes read
|
||||||
|
fd_read_cb(ttf_t *font, // I - Font
|
||||||
|
void *buffer, // I - Read buffer
|
||||||
|
size_t bytes) // I - Number of bytes to read
|
||||||
|
{
|
||||||
|
ssize_t rbytes; // Bytes read
|
||||||
|
|
||||||
|
|
||||||
|
if ((rbytes = read(font->file_fd, buffer, bytes)) < 0)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
return ((size_t)rbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'fd_seek_cb()' - Seek in a file.
|
||||||
|
//
|
||||||
|
|
||||||
|
static bool // O - `true` on success, `false` on failure
|
||||||
|
fd_seek_cb(ttf_t *font, // I - Font
|
||||||
|
size_t offset) // I - Offset in data
|
||||||
|
{
|
||||||
|
return (lseek(font->file_fd, offset, SEEK_SET) == offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'mem_read_cb()' - Read from a memory buffer.
|
||||||
|
//
|
||||||
|
|
||||||
|
static size_t // O - Number of bytes read
|
||||||
|
mem_read_cb(ttf_t *font, // I - Font
|
||||||
|
void *buffer, // I - Read buffer
|
||||||
|
size_t bytes) // I - Number of bytes to read
|
||||||
|
{
|
||||||
|
size_t rbytes; // Bytes to copy
|
||||||
|
|
||||||
|
|
||||||
|
if (font->data_offset >= font->data_size)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
if ((rbytes = font->data_size - font->data_offset) > bytes)
|
||||||
|
rbytes = bytes;
|
||||||
|
|
||||||
|
memcpy(buffer, font->data + font->data_offset, rbytes);
|
||||||
|
font->data_offset += rbytes;
|
||||||
|
|
||||||
|
return (rbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'mem_seek_cb()' - Seek in a memory buffer.
|
||||||
|
//
|
||||||
|
|
||||||
|
static bool // O - `true` on success, `false` on error
|
||||||
|
mem_seek_cb(ttf_t *font, // I - Font
|
||||||
|
size_t offset) // I - Offset in data
|
||||||
|
{
|
||||||
|
if (offset >= font->data_size)
|
||||||
|
{
|
||||||
|
errno = ENXIO;
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
font->data_offset = offset;
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 'read_cmap()' - Read the cmap table, getting the Unicode mapping table.
|
||||||
|
//
|
||||||
|
|
||||||
static bool // O - `true` on success, `false` on error
|
static bool // O - `true` on success, `false` on error
|
||||||
read_cmap(ttf_t *font) // I - Font
|
read_cmap(ttf_t *font) // I - Font
|
||||||
@ -1219,7 +1393,7 @@ read_cmap(ttf_t *font) // I - Font
|
|||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read(font->fd, bmap, font->num_cmap) != (ssize_t)font->num_cmap)
|
if ((font->read_cb)(font, bmap, font->num_cmap) != font->num_cmap)
|
||||||
{
|
{
|
||||||
errorf(font, "Unable to read cmap table length at offset %u.", coffset);
|
errorf(font, "Unable to read cmap table length at offset %u.", coffset);
|
||||||
return (false);
|
return (false);
|
||||||
@ -1646,9 +1820,9 @@ read_hhea(ttf_t *font, // I - Font
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
//
|
||||||
* 'read_hmtx()' - Read the horizontal metrics from the font.
|
// 'read_hmtx()' - Read the horizontal metrics from the font.
|
||||||
*/
|
//
|
||||||
|
|
||||||
static _ttf_metric_t * // O - Array of glyph metrics
|
static _ttf_metric_t * // O - Array of glyph metrics
|
||||||
read_hmtx(ttf_t *font, // I - Font
|
read_hmtx(ttf_t *font, // I - Font
|
||||||
@ -1774,7 +1948,7 @@ read_names(ttf_t *font) // I - Font
|
|||||||
|
|
||||||
length -= (unsigned)offset;
|
length -= (unsigned)offset;
|
||||||
|
|
||||||
if (read(font->fd, font->names.storage, length) < 0)
|
if ((font->read_cb)(font, font->names.storage, length) == 0)
|
||||||
{
|
{
|
||||||
errorf(font, "Unable to read name table: %s", strerror(errno));
|
errorf(font, "Unable to read name table: %s", strerror(errno));
|
||||||
return (false);
|
return (false);
|
||||||
@ -1823,7 +1997,7 @@ read_os_2(ttf_t *font, // I - Font
|
|||||||
/* yStrikeoutOffset */ read_short(font);
|
/* yStrikeoutOffset */ read_short(font);
|
||||||
/* sFamilyClass */ read_short(font);
|
/* sFamilyClass */ read_short(font);
|
||||||
/* panose[10] */
|
/* panose[10] */
|
||||||
if (read(font->fd, panose, sizeof(panose)) != (ssize_t)sizeof(panose))
|
if ((font->read_cb)(font, panose, sizeof(panose)) != sizeof(panose))
|
||||||
return (false);
|
return (false);
|
||||||
/* ulUnicodeRange1 */ read_ulong(font);
|
/* ulUnicodeRange1 */ read_ulong(font);
|
||||||
/* ulUnicodeRange2 */ read_ulong(font);
|
/* ulUnicodeRange2 */ read_ulong(font);
|
||||||
@ -1885,7 +2059,7 @@ read_short(ttf_t *font) // I - Font
|
|||||||
unsigned char buffer[2]; // Read buffer
|
unsigned char buffer[2]; // Read buffer
|
||||||
|
|
||||||
|
|
||||||
if (read(font->fd, buffer, sizeof(buffer)) != sizeof(buffer))
|
if ((font->read_cb)(font, buffer, sizeof(buffer)) != sizeof(buffer))
|
||||||
return (EOF);
|
return (EOF);
|
||||||
else if (buffer[0] & 0x80)
|
else if (buffer[0] & 0x80)
|
||||||
return (((buffer[0] << 8) | buffer[1]) - 65536);
|
return (((buffer[0] << 8) | buffer[1]) - 65536);
|
||||||
@ -1958,7 +2132,7 @@ read_table(ttf_t *font) // I - Font
|
|||||||
|
|
||||||
TTF_DEBUG("read_table: Offset for font %u is %u.\n", (unsigned)font->idx, temp);
|
TTF_DEBUG("read_table: Offset for font %u is %u.\n", (unsigned)font->idx, temp);
|
||||||
|
|
||||||
if (lseek(font->fd, temp + 4, SEEK_SET) < 0)
|
if (!(font->seek_cb)(font, temp + 4))
|
||||||
{
|
{
|
||||||
errorf(font, "Unable to seek to font %u: %s", (unsigned)font->idx, strerror(errno));
|
errorf(font, "Unable to seek to font %u: %s", (unsigned)font->idx, strerror(errno));
|
||||||
return (false);
|
return (false);
|
||||||
@ -2034,7 +2208,7 @@ read_ulong(ttf_t *font) // I - Font
|
|||||||
unsigned char buffer[4]; // Read buffer
|
unsigned char buffer[4]; // Read buffer
|
||||||
|
|
||||||
|
|
||||||
if (read(font->fd, buffer, sizeof(buffer)) != sizeof(buffer))
|
if ((font->read_cb)(font, buffer, sizeof(buffer)) != sizeof(buffer))
|
||||||
return ((unsigned)EOF);
|
return ((unsigned)EOF);
|
||||||
else
|
else
|
||||||
return ((unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]));
|
return ((unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]));
|
||||||
@ -2051,7 +2225,7 @@ read_ushort(ttf_t *font) // I - Font
|
|||||||
unsigned char buffer[2]; // Read buffer
|
unsigned char buffer[2]; // Read buffer
|
||||||
|
|
||||||
|
|
||||||
if (read(font->fd, buffer, sizeof(buffer)) != sizeof(buffer))
|
if ((font->read_cb)(font, buffer, sizeof(buffer)) != sizeof(buffer))
|
||||||
return (EOF);
|
return (EOF);
|
||||||
else
|
else
|
||||||
return ((buffer[0] << 8) | buffer[1]);
|
return ((buffer[0] << 8) | buffer[1]);
|
||||||
@ -2078,7 +2252,7 @@ seek_table(ttf_t *font, // I - Font
|
|||||||
if (current->tag == tag)
|
if (current->tag == tag)
|
||||||
{
|
{
|
||||||
// Found it, seek and return...
|
// Found it, seek and return...
|
||||||
if (lseek(font->fd, current->offset + offset, SEEK_SET) == (current->offset + offset))
|
if ((font->seek_cb)(font, current->offset + offset))
|
||||||
{
|
{
|
||||||
// Successful seek...
|
// Successful seek...
|
||||||
return (current->length - offset);
|
return (current->length - offset);
|
||||||
|
3
ttf.h
3
ttf.h
@ -3,7 +3,7 @@
|
|||||||
//
|
//
|
||||||
// https://github.com/michaelrsweet/ttf
|
// https://github.com/michaelrsweet/ttf
|
||||||
//
|
//
|
||||||
// Copyright © 2018-2024 by Michael R Sweet.
|
// Copyright © 2018-2025 by Michael R Sweet.
|
||||||
//
|
//
|
||||||
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more
|
||||||
// information.
|
// information.
|
||||||
@ -81,6 +81,7 @@ typedef struct ttf_rect_s // Bounding rectangle
|
|||||||
//
|
//
|
||||||
|
|
||||||
extern ttf_t *ttfCreate(const char *filename, size_t idx, ttf_err_cb_t err_cb, void *err_data);
|
extern ttf_t *ttfCreate(const char *filename, size_t idx, ttf_err_cb_t err_cb, void *err_data);
|
||||||
|
extern ttf_t *ttfCreateData(const void *data, size_t data_size, size_t idx, ttf_err_cb_t err_cb, void *err_data);
|
||||||
extern void ttfDelete(ttf_t *font);
|
extern void ttfDelete(ttf_t *font);
|
||||||
extern int ttfGetAscent(ttf_t *font);
|
extern int ttfGetAscent(ttf_t *font);
|
||||||
extern ttf_rect_t *ttfGetBounds(ttf_t *font, ttf_rect_t *bounds);
|
extern ttf_rect_t *ttfGetBounds(ttf_t *font, ttf_rect_t *bounds);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user