Save work on Unicode font support - still something isn't quite right.

This commit is contained in:
Michael R Sweet 2021-06-21 07:58:23 -04:00
parent a2da67c415
commit e9d5e082af
No known key found for this signature in database
GPG Key ID: 999559A027815955
7 changed files with 417 additions and 244 deletions

View File

@ -51,6 +51,42 @@ const double pdfioSRGBWhitePoint[3] = { 0.9505, 1.0, 1.0890 };
#define _PDFIO_PNG_TYPE_GRAYA 4 // Grayscale + alpha
#define _PDFIO_PNG_TYPE_RGBA 6 // RGB + alpha
static int _pdfio_cp1252[] = // CP1252-specific character mapping
{
0x20AC,
0x0000,
0x201A,
0x0192,
0x201E,
0x2026,
0x2020,
0x2021,
0x02C6,
0x2030,
0x0160,
0x2039,
0x0152,
0x0000,
0x017D,
0x0000,
0x0000,
0x2018,
0x2019,
0x201C,
0x201D,
0x2022,
0x2013,
0x2014,
0x02DC,
0x2122,
0x0161,
0x203A,
0x0153,
0x0000,
0x017E,
0x0178
};
//
// Local types...
@ -67,7 +103,7 @@ 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 void ttf_error_cb(pdfio_file_t *pdf, const char *message);
static unsigned update_png_crc(unsigned crc, const unsigned char *buffer, size_t length);
static bool write_string(pdfio_stream_t *st, const char *s, bool *newline);
static bool write_string(pdfio_stream_t *st, bool unicode, const char *s, bool *newline);
//
@ -1015,17 +1051,22 @@ pdfioContentTextNextLine(
//
// 'pdfioContentTextShow()' - Show text.
//
// This function shows some text in a PDF content stream. The "unicode" argument
// specifies that the current font maps to full Unicode. The "s" argument
// specifies a UTF-8 encoded string.
//
bool // O - `true` on success, `false` on failure
pdfioContentTextShow(
pdfio_stream_t *st, // I - Stream
bool unicode, // I - Unicode text?
const char *s) // I - String to show
{
bool newline = false; // New line?
// Write the string...
if (!write_string(st, s, &newline))
if (!write_string(st, unicode, s, &newline))
return (false);
// Draw it...
@ -1039,10 +1080,15 @@ pdfioContentTextShow(
//
// 'pdfioContentTextShowf()' - Show formatted text.
//
// This function shows some text in a PDF content stream. The "unicode" argument
// specifies that the current font maps to full Unicode. The "format" argument
// specifies a UTF-8 encoded `printf`-style format string.
//
bool
pdfioContentTextShowf(
pdfio_stream_t *st, // I - Stream
bool unicode, // I - Unicode text?
const char *format, // I - `printf`-style format string
...) // I - Additional arguments as needed
{
@ -1057,7 +1103,7 @@ pdfioContentTextShowf(
va_end(ap);
// Write the string...
if (!write_string(st, buffer, &newline))
if (!write_string(st, unicode, buffer, &newline))
return (false);
// Draw it...
@ -1071,10 +1117,15 @@ pdfioContentTextShowf(
//
// 'pdfioContentTextShowJustified()' - Show justified text.
//
// This function shows some text in a PDF content stream. The "unicode" argument
// specifies that the current font maps to full Unicode. The "fragments"
// argument specifies an array of UTF-8 encoded strings.
//
bool // O - `true` on success, `false` on failure
pdfioContentTextShowJustified(
pdfio_stream_t *st, // I - Stream
bool unicode, // I - Unicode text?
size_t num_fragments, // I - Number of text fragments
const double *offsets, // I - Text offsets before fragments
const char * const *fragments) // I - Text fragments
@ -1096,7 +1147,7 @@ pdfioContentTextShowJustified(
if (fragments[i])
{
if (!write_string(st, fragments[i], NULL))
if (!write_string(st, unicode, fragments[i], NULL))
return (false);
}
}
@ -1126,6 +1177,9 @@ pdfioContentTextShowJustified(
// - `Times-Roman`
// - `ZapfDingbats`
//
// Base fonts always use the Windows CP1252 (ISO-8859-1 with additional
// characters such as the Euro symbol) subset of Unicode.
//
pdfio_obj_t * // O - Font object
pdfioFileCreateFontObjFromBase(
@ -1154,12 +1208,18 @@ pdfioFileCreateFontObjFromBase(
//
// 'pdfioFileCreateFontObjFromFile()' - Add a font object to a PDF file.
//
// This function embeds a TrueType/OpenType font 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
pdfioFileCreateFontObjFromFile(
pdfio_file_t *pdf, // I - PDF file
const char *filename, // I - Filename
bool unicode) // I - Unicode font?
bool unicode) // I - Force Unicode
{
ttf_t *font; // TrueType font
int ch, // Current character
@ -1167,12 +1227,13 @@ pdfioFileCreateFontObjFromFile(
lastch; // Last character
ttf_rect_t bounds; // Font bounds
pdfio_dict_t *dict, // Font dictionary
*desc; // Font descriptor
*desc, // Font descriptor
*file; // Font file dictionary
pdfio_obj_t *obj, // Font object
*desc_obj, // Font descriptor object
*widths_obj; // Font widths object
*file_obj; // Font file object
const char *basefont; // Base font name
pdfio_array_t *bbox; // Font bounding box array
pdfio_array_t *widths; // Font widths array
pdfio_stream_t *st; // Font stream
int fd; // File
unsigned char buffer[16384]; // Read buffer
@ -1201,102 +1262,23 @@ pdfioFileCreateFontObjFromFile(
return (NULL);
}
// Create the font descriptor dictionary and object...
if ((bbox = pdfioArrayCreate(pdf)) == NULL)
// Create the font file dictionary and object...
if ((file = pdfioDictCreate(pdf)) == NULL)
{
ttfDelete(font);
close(fd);
return (NULL);
}
ttfGetBounds(font, &bounds);
pdfioDictSetName(file, "Filter", "FlateDecode");
pdfioArrayAppendNumber(bbox, bounds.left);
pdfioArrayAppendNumber(bbox, bounds.bottom);
pdfioArrayAppendNumber(bbox, bounds.right);
pdfioArrayAppendNumber(bbox, bounds.top);
if ((desc = pdfioDictCreate(pdf)) == NULL)
{
ttfDelete(font);
close(fd);
return (NULL);
}
pdfioDictSetName(desc, "Type", "FontDescriptor");
pdfioDictSetName(desc, "FontName", pdfioStringCreate(pdf, ttfGetPostScriptName(font)));
pdfioDictSetName(desc, "FontFamily", pdfioStringCreate(pdf, ttfGetFamily(font)));
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 value from 50 to 250...
pdfioDictSetNumber(desc, "StemV", ttfGetWeight(font) / 4 + 25);
if ((desc_obj = pdfioFileCreateObj(pdf, desc)) == NULL)
{
ttfDelete(font);
close(fd);
return (NULL);
}
pdfioObjClose(desc_obj);
// Create the widths array and object...
if ((widths = pdfioArrayCreate(pdf)) == NULL)
{
ttfDelete(font);
close(fd);
return (NULL);
}
firstch = 32;
lastch = unicode ? 65535 : 255;
for (ch = firstch; ch <= lastch; ch ++)
pdfioArrayAppendNumber(widths, ttfGetWidth(font, ch));
if ((widths_obj = pdfioFileCreateArrayObj(pdf, widths)) == NULL)
{
ttfDelete(font);
close(fd);
return (NULL);
}
pdfioObjClose(widths_obj);
// Create the font object...
if ((dict = pdfioDictCreate(pdf)) == NULL)
{
ttfDelete(font);
close(fd);
return (NULL);
}
pdfioDictSetName(dict, "Type", "Font");
pdfioDictSetName(dict, "Subtype", "TrueType");
pdfioDictSetName(dict, "BaseFont", pdfioStringCreate(pdf, ttfGetPostScriptName(font)));
pdfioDictSetName(dict, "Encoding", "WinAnsiEncoding"); // TODO: Fix encoding for unicode
pdfioDictSetName(dict, "Filter", "FlateDecode");
pdfioDictSetObj(dict, "FontDescriptor", desc_obj);
pdfioDictSetNumber(dict, "FirstChar", firstch);
pdfioDictSetNumber(dict, "LastChar", lastch);
pdfioDictSetObj(dict, "Widths", widths_obj);
ttfDelete(font);
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL)
if ((file_obj = pdfioFileCreateObj(pdf, file)) == NULL)
{
close(fd);
return (NULL);
}
if ((st = pdfioObjCreateStream(obj, PDFIO_FILTER_FLATE)) == NULL)
if ((st = pdfioObjCreateStream(file_obj, PDFIO_FILTER_FLATE)) == NULL)
{
close(fd);
return (NULL);
@ -1315,6 +1297,189 @@ pdfioFileCreateFontObjFromFile(
close(fd);
pdfioStreamClose(st);
// Create the font descriptor dictionary and object...
if ((bbox = pdfioArrayCreate(pdf)) == NULL)
{
ttfDelete(font);
return (NULL);
}
ttfGetBounds(font, &bounds);
pdfioArrayAppendNumber(bbox, bounds.left);
pdfioArrayAppendNumber(bbox, bounds.bottom);
pdfioArrayAppendNumber(bbox, bounds.right);
pdfioArrayAppendNumber(bbox, bounds.top);
if ((desc = pdfioDictCreate(pdf)) == NULL)
{
ttfDelete(font);
return (NULL);
}
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 value from 50 to 250...
pdfioDictSetNumber(desc, "StemV", ttfGetWeight(font) / 4 + 25);
if ((desc_obj = pdfioFileCreateObj(pdf, desc)) == NULL)
{
ttfDelete(font);
return (NULL);
}
pdfioObjClose(desc_obj);
if (unicode)
{
// Unicode (CID) font...
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
// Create a CIDFontType2 dictionary for the Unicode font...
if ((type2 = pdfioDictCreate(pdf)) == NULL)
{
ttfDelete(font);
return (NULL);
}
if ((sidict = pdfioDictCreate(pdf)) == NULL)
{
ttfDelete(font);
return (NULL);
}
// CIDSystemInfo mapping to Adobe Identity (Unicode)
pdfioDictSetString(sidict, "Registry", "Adobe");
pdfioDictSetString(sidict, "Ordering", "Identity");
pdfioDictSetNumber(sidict, "Supplement", 0);
// Then the dictionary for the CID base font...
pdfioDictSetName(type2, "Type", "Font");
pdfioDictSetName(type2, "Subtype", "CIDFontType2");
pdfioDictSetName(type2, "BaseFont", basefont);
pdfioDictSetDict(type2, "CIDSystemInfo", sidict);
pdfioDictSetName(type2, "CIDToGIDMap", "Identity");
pdfioDictSetObj(type2, "FontDescriptor", desc_obj);
if ((type2_obj = pdfioFileCreateObj(pdf, type2)) == NULL)
{
ttfDelete(font);
return (NULL);
}
pdfioObjClose(type2_obj);
// Create a Type 0 font object...
if ((descendants = pdfioArrayCreate(pdf)) == NULL)
{
ttfDelete(font);
return (NULL);
}
pdfioArrayAppendObj(descendants, type2_obj);
if ((dict = pdfioDictCreate(pdf)) == NULL)
{
ttfDelete(font);
return (NULL);
}
pdfioDictSetName(dict, "Type", "Font");
pdfioDictSetName(dict, "Subtype", "Type0");
pdfioDictSetName(dict, "BaseFont", basefont);
pdfioDictSetArray(dict, "DescendantFonts", descendants);
pdfioDictSetName(dict, "Encoding", "Identity-H");
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL)
return (NULL);
pdfioObjClose(obj);
}
else
{
// Simple (CP1282 or custom encoding) 8-bit font...
pdfio_array_t *widths; // Font widths array
pdfio_obj_t *widths_obj; // Font widths object
// Create the widths array and object...
if ((widths = pdfioArrayCreate(pdf)) == NULL)
{
ttfDelete(font);
return (NULL);
}
firstch = ttfGetMinChar(font);
lastch = ttfGetMaxChar(font);
if (lastch < 255)
{
// Provide widths for all characters...
for (ch = firstch; ch <= lastch; ch ++)
pdfioArrayAppendNumber(widths, ttfGetWidth(font, ch));
}
else
{
// Provide widths only for CP1252 characters...
lastch = 255;
for (ch = firstch; ch < 128; ch ++)
pdfioArrayAppendNumber(widths, ttfGetWidth(font, ch));
for (; ch < 160; ch ++)
pdfioArrayAppendNumber(widths, ttfGetWidth(font, _pdfio_cp1252[ch - 128]));
for (; ch <= lastch && ch < 128; ch ++)
pdfioArrayAppendNumber(widths, ttfGetWidth(font, ch));
}
if ((widths_obj = pdfioFileCreateArrayObj(pdf, widths)) == NULL)
{
ttfDelete(font);
return (NULL);
}
pdfioObjClose(widths_obj);
// Create a TrueType font object...
if ((dict = pdfioDictCreate(pdf)) == NULL)
{
ttfDelete(font);
return (NULL);
}
pdfioDictSetName(dict, "Type", "Font");
pdfioDictSetName(dict, "Subtype", "TrueType");
pdfioDictSetName(dict, "BaseFont", basefont);
pdfioDictSetName(dict, "Encoding", "WinAnsi");
pdfioDictSetObj(dict, "FontDescriptor", desc_obj);
pdfioDictSetNumber(dict, "FirstChar", firstch);
pdfioDictSetNumber(dict, "LastChar", lastch);
pdfioDictSetObj(dict, "Widths", widths_obj);
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL)
{
ttfDelete(font);
return (NULL);
}
pdfioObjClose(obj);
}
ttfDelete(font);
return (obj);
}
@ -2229,140 +2394,93 @@ update_png_crc(
static bool // O - `true` on success, `false` otherwise
write_string(pdfio_stream_t *st, // I - Stream
bool unicode, // I - Unicode text?
const char *s, // I - String
bool *newline) // O - Ends with a newline?
{
int ch; // Unicode character
const char *ptr; // Pointer into string
// Determine whether this is Unicode or just ASCII...
// Start the string...
if (!pdfioStreamPuts(st, unicode ? "<" : "("))
return (false);
// Loop through the string, handling UTF-8 as needed...
for (ptr = s; *ptr; ptr ++)
{
if (*ptr & 0x80)
if ((*ptr & 0xe0) == 0xc0)
{
// UTF-8, allow Unicode up to 255...
if ((*ptr & 0xe0) == 0xc0 && (*ptr & 0x3f) <= 3 && (ptr[1] & 0xc0) == 0x80)
{
ptr ++;
continue;
}
// Two-byte UTF-8
ch = ((ptr[0] & 0x1f) << 6) | (ptr[1] & 0x3f);
ptr ++;
}
else if ((*ptr & 0xf0) == 0xe0)
{
// Three-byte UTF-8
ch = ((ptr[0] & 0x0f) << 12) | ((ptr[1] & 0x3f) << 6) | (ptr[2] & 0x3f);
ptr += 2;
}
else if ((*ptr & 0xf8) == 0xf0)
{
// Four-byte UTF-8
ch = ((ptr[0] & 0x07) << 18) | ((ptr[1] & 0x3f) << 12) | ((ptr[2] & 0x3f) << 6) | (ptr[3] & 0x3f);
ptr += 3;
}
else if (*ptr == '\n' && newline)
{
*newline = true;
break;
}
}
else
ch = *ptr & 255;
if (*ptr)
{
// Unicode string...
int ch; // Unicode character
if (!pdfioStreamPuts(st, "<"))
return (false);
for (ptr = s; *ptr; ptr ++)
if (unicode)
{
if ((*ptr & 0xe0) == 0xc0)
{
// Two-byte UTF-8
ch = ((ptr[0] & 0x1f) << 6) | (ptr[1] & 0x3f);
ptr ++;
}
else if ((*ptr & 0xf0) == 0xe0)
{
// Three-byte UTF-8
ch = ((ptr[0] & 0x0f) << 12) | ((ptr[1] & 0x3f) << 6) | (ptr[2] & 0x3f);
ptr += 2;
}
else if ((*ptr & 0xf8) == 0xf0)
{
// Four-byte UTF-8
ch = ((ptr[0] & 0x07) << 18) | ((ptr[1] & 0x3f) << 12) | ((ptr[2] & 0x3f) << 6) | (ptr[3] & 0x3f);
ptr += 3;
}
else if (*ptr == '\n' && newline)
{
*newline = true;
break;
}
else
ch = *ptr & 255;
// Write a two-byte character...
if (!pdfioStreamPrintf(st, "%04X", ch))
return (false);
return (false);
}
if (!pdfioStreamPuts(st, ">"))
return (false);
}
else
{
// ASCII string...
const char *start = s; // Start of fragment
if (!pdfioStreamPuts(st, "("))
return (false);
for (ptr = start; *ptr; ptr ++)
else
{
if (*ptr == '\n' && newline)
// Write a one-byte character...
if (ch == '\\' || ch == '(' || ch == ')' || ch < ' ')
{
if (ptr > start)
// Escaped character...
if (ch < ' ')
{
if (!pdfioStreamWrite(st, start, (size_t)(ptr - start)))
return (false);
start = ptr + 1;
}
*newline = true;
break;
}
else if ((*ptr & 0xe0) == 0xc0)
{
// Two-byte UTF-8
unsigned char ch = (unsigned char)(((ptr[0] & 0x1f) << 6) | (ptr[1] & 0x3f));
// Unicode character
if (ptr > start)
{
if (!pdfioStreamWrite(st, start, (size_t)(ptr - start)))
return (false);
}
if (!pdfioStreamWrite(st, &ch, 1))
return (false);
ptr ++;
start = ptr + 1;
}
else if (*ptr == '\\' || *ptr == '(' || *ptr == ')' || *ptr < ' ')
{
if (ptr > start)
{
if (!pdfioStreamWrite(st, start, (size_t)(ptr - start)))
return (false);
}
start = ptr + 1;
if (*ptr < ' ')
{
if (!pdfioStreamPrintf(st, "\\%03o", *ptr))
if (!pdfioStreamPrintf(st, "\\%03o", ch))
return (false);
}
else if (!pdfioStreamPrintf(st, "\\%c", *ptr))
else if (!pdfioStreamPrintf(st, "\\%c", ch))
return (false);
}
}
else
{
// Non-escaped character...
if (ch > 255)
{
// Try mapping from Unicode to CP1252...
int i; // Looping var
if (ptr > start)
{
if (!pdfioStreamPrintf(st, "%s)", start))
return (false);
for (i = 0; i < (int)(sizeof(_pdfio_cp1252) / sizeof(_pdfio_cp1252[0])); i ++)
{
if (ch == _pdfio_cp1252[i])
{
ch = i + 128;
break;
}
}
if (ch > 255)
ch = '?'; // Unsupported chars map to ?
}
// Write the character...
pdfioStreamPutChar(st, ch);
}
}
else if (!pdfioStreamPuts(st, ")"))
return (false);
}
return (true);
return (pdfioStreamPuts(st, unicode ? ">" : ")"));
}

View File

@ -139,9 +139,9 @@ extern bool pdfioContentTextEnd(pdfio_stream_t *st) PDFIO_PUBLIC;
extern bool pdfioContentTextMoveLine(pdfio_stream_t *st, double tx, double ty) PDFIO_PUBLIC;
extern bool pdfioContentTextMoveTo(pdfio_stream_t *st, double tx, double ty) PDFIO_PUBLIC;
extern bool pdfioContentTextNextLine(pdfio_stream_t *st) PDFIO_PUBLIC;
extern bool pdfioContentTextShow(pdfio_stream_t *st, const char *s) PDFIO_PUBLIC;
extern bool pdfioContentTextShowf(pdfio_stream_t *st, const char *format, ...) PDFIO_PUBLIC PDFIO_FORMAT(2,3);
extern bool pdfioContentTextShowJustified(pdfio_stream_t *st, size_t num_fragments, const double *offsets, const char * const *fragments) PDFIO_PUBLIC;
extern bool pdfioContentTextShow(pdfio_stream_t *st, bool unicode, const char *s) PDFIO_PUBLIC;
extern bool pdfioContentTextShowf(pdfio_stream_t *st, bool unicode, const char *format, ...) PDFIO_PUBLIC PDFIO_FORMAT(3,4);
extern bool pdfioContentTextShowJustified(pdfio_stream_t *st, bool unicode, size_t num_fragments, const double *offsets, const char * const *fragments) PDFIO_PUBLIC;
// Resource helpers...
extern pdfio_obj_t *pdfioFileCreateFontObjFromBase(pdfio_file_t *pdf, const char *name) PDFIO_PUBLIC;

View File

@ -556,6 +556,26 @@ pdfioStreamPrintf(
}
//
// '()' - Write a single character to a stream.
//
bool // O - `true` on success, `false` on failure
pdfioStreamPutChar(pdfio_stream_t *st, // I - Stream
int ch) // I - Character
{
char buffer[1]; // Write buffer
if (!st || st->pdf->mode != _PDFIO_MODE_WRITE)
return (false);
buffer[0] = (char)ch;
return (pdfioStreamWrite(st, buffer, 1));
}
//
// 'pdfioStreamPuts()' - Write a literal string to a stream.
//

View File

@ -181,6 +181,7 @@ extern bool pdfioStreamConsume(pdfio_stream_t *st, size_t bytes) PDFIO_PUBLIC;
extern bool pdfioStreamGetToken(pdfio_stream_t *st, char *buffer, size_t bufsize) PDFIO_PUBLIC;
extern ssize_t pdfioStreamPeek(pdfio_stream_t *st, void *buffer, size_t bytes) PDFIO_PUBLIC;
extern bool pdfioStreamPrintf(pdfio_stream_t *st, const char *format, ...) PDFIO_PUBLIC PDFIO_FORMAT(2,3);
extern bool pdfioStreamPutChar(pdfio_stream_t *st, int ch) PDFIO_PUBLIC;
extern bool pdfioStreamPuts(pdfio_stream_t *st, const char *s) PDFIO_PUBLIC;
extern ssize_t pdfioStreamRead(pdfio_stream_t *st, void *buffer, size_t bytes) PDFIO_PUBLIC;
extern bool pdfioStreamWrite(pdfio_stream_t *st, const void *buffer, size_t bytes) PDFIO_PUBLIC;

View File

@ -388,7 +388,7 @@ draw_image(pdfio_stream_t *st,
return (1);
printf("pdfioContentTextShow(\"%s\"): ", label);
if (pdfioContentTextShow(st, label))
if (pdfioContentTextShow(st, false, label))
puts("PASS");
else
return (1);
@ -829,7 +829,7 @@ write_color_test(pdfio_file_t *pdf, // I - PDF file
goto error;
fputs("pdfioContentTextShow(\"AdobeRGB\"): ", stdout);
if (pdfioContentTextShow(st, "AdobeRGB"))
if (pdfioContentTextShow(st, false, "AdobeRGB"))
puts("PASS");
else
goto error;
@ -841,7 +841,7 @@ write_color_test(pdfio_file_t *pdf, // I - PDF file
goto error;
fputs("pdfioContentTextShow(\"DisplayP3\"): ", stdout);
if (pdfioContentTextShow(st, "DisplayP3"))
if (pdfioContentTextShow(st, false, "DisplayP3"))
puts("PASS");
else
goto error;
@ -853,7 +853,7 @@ write_color_test(pdfio_file_t *pdf, // I - PDF file
goto error;
fputs("pdfioContentTextShow(\"sRGB\"): ", stdout);
if (pdfioContentTextShow(st, "sRGB"))
if (pdfioContentTextShow(st, false, "sRGB"))
puts("PASS");
else
goto error;
@ -865,7 +865,7 @@ write_color_test(pdfio_file_t *pdf, // I - PDF file
goto error;
fputs("pdfioContentTextShow(\"ProPhotoRGB\"): ", stdout);
if (pdfioContentTextShow(st, "ProPhotoRGB"))
if (pdfioContentTextShow(st, false, "ProPhotoRGB"))
puts("PASS");
else
goto error;
@ -877,7 +877,7 @@ write_color_test(pdfio_file_t *pdf, // I - PDF file
goto error;
fputs("pdfioContentTextShow(\"DeviceCMYK\"): ", stdout);
if (pdfioContentTextShow(st, "DeviceCMYK"))
if (pdfioContentTextShow(st, false, "DeviceCMYK"))
puts("PASS");
else
goto error;
@ -1049,7 +1049,7 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
{
"Welcome\n",
"Welkom\n",
// "ḫaṣānu\n",
"ḫaṣānu\n",
"Mayad-ayad nga pad-abot\n",
"Mir se vjên\n",
"Mirë se vjen\n",
@ -1058,15 +1058,15 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
"Ghini vinit!\n",
"Bienveníu\n",
"Miro peicak\n",
// "Xoş gəlmişsiniz!\n",
"Xoş gəlmişsiniz!\n",
"Salamat datang\n",
// "Сәләм бирем!\n",
"Сәләм бирем!\n",
"Menjuah-juah!\n",
// "Še das d' kemma bisd\n",
"Še das d' kemma bisd\n",
"Mwaiseni\n",
"Maogmáng Pag-abót\n",
"Welkam\n",
// "Dobrodošli\n",
"Dobrodošli\n",
"Degemer mat\n",
"Benvingut\n",
"Maayong pag-abot\n",
@ -1074,7 +1074,7 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
"Bienvenida\n",
"Bien binidu\n",
"Bienbenidu\n",
// "Hóʔą\n",
"ʔą\n",
"Boolkhent!\n",
"Kopivosian do kinoikatan\n",
"Malipayeng Pag-abot!\n",
@ -1085,7 +1085,7 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
"Emedi\n",
"Welkumin\n",
"Tere tulemast\n",
// "Woé zɔ\n",
"Woé zɔ\n",
"Bienveníu\n",
"Vælkomin\n",
"Bula\n",
@ -1098,8 +1098,8 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
"Benvignût\n",
"Benvido\n",
"Willkommen\n",
// "Ἀσπάζομαι!\n",
// "Καλώς Ήρθες\n",
"Ἀσπάζομαι!\n",
"Καλώς Ήρθες\n",
"Tikilluarit\n",
"Byen venu\n",
"Sannu da zuwa\n",
@ -1110,7 +1110,7 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
"Üdvözlet\n",
"Selamat datai\n",
"Velkomin\n",
// "Nnọọ\n",
"Nnọọ\n",
"Selamat datang\n",
"Qaimarutin\n",
"Fáilte\n",
@ -1119,11 +1119,11 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
"Murakaza neza\n",
"Mauri\n",
"Tu be xér hatî ye!\n",
// "Taŋyáŋ yahí\n",
"Taŋyáŋ yahí\n",
"Salve\n",
// "Laipni lūdzam\n",
"Laipni lūdzam\n",
"Wilkóm\n",
// "Sveiki atvykę\n",
"Sveiki atvykę\n",
"Willkamen\n",
"Mu amuhezwi\n",
"Tukusanyukidde\n",
@ -1131,15 +1131,15 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
"Swagatam\n",
"Tonga soa\n",
"Selamat datang\n",
// "Merħba\n",
// "Bantulena\n",
"Merħba\n",
"Bantulena\n",
"Failt ort\n",
"Haere mai\n",
"mai\n",
// "Pjilasi\n",
"Pjilasi\n",
"Benvegnüu\n",
"Ne y kena\n",
// "Ximopanōltih\n",
"Ximopanōltih\n",
"Yá'át'ééh\n",
"Siyalemukela\n",
"Siyalemukela\n",
@ -1148,7 +1148,7 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
"Velkommen\n",
"Benvengut!\n",
"Bon bini\n",
// "Witam Cię\n",
"Witam Cię\n",
"Bem-vindo\n",
"Haykuykuy!\n",
"T'aves baxtalo\n",
@ -1160,7 +1160,7 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
"Mauya\n",
"Bon vinutu\n",
"Vitaj\n",
// "Dobrodošli\n",
"Dobrodošli\n",
"Soo dhowow\n",
"Witaj\n",
"Bienvenido\n",
@ -1179,8 +1179,8 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
"Lek oy li la tale\n",
"amogetswe\n",
"Tempokani\n",
// "Hoş geldin\n",
// "Koş geldiniz\n",
"Hoş geldin\n",
"Koş geldiniz\n",
"Ulufale mai!\n",
"Xush kelibsiz\n",
"Benvignùo\n",
@ -1191,14 +1191,14 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
"Croeso\n",
"Merhbe\n",
"Wamkelekile\n",
// "Märr-ŋamathirri\n",
// "Ẹ ku abọ\n",
"Märr-ŋamathirri\n",
"Ẹ ku abọ\n",
"Kíimak 'oolal\n",
"Ngiyakwemukela\n"
};
fputs("pdfioFileCreateFontObjFromFile(OpenSans-Regular.ttf): ", stdout);
if ((opensans = pdfioFileCreateFontObjFromFile(pdf, "testfiles/OpenSans-Regular.ttf", false)) != NULL)
if ((opensans = pdfioFileCreateFontObjFromFile(pdf, "testfiles/OpenSans-Regular.ttf", true)) != NULL)
puts("PASS");
else
return (1);
@ -1267,7 +1267,7 @@ write_font_test(pdfio_file_t *pdf, // I - PDF file
}
printf("pdfioContentTextShow(\"%s\"): ", welcomes[i]);
if (pdfioContentTextShow(st, welcomes[i]))
if (pdfioContentTextShow(st, true, welcomes[i]))
puts("PASS");
else
return (1);
@ -1329,7 +1329,7 @@ write_header_footer(
return (1);
printf("pdfioContentTextShow(\"%s\"): ", title);
if (pdfioContentTextShow(st, title))
if (pdfioContentTextShow(st, false, title))
puts("PASS");
else
return (1);
@ -1347,7 +1347,7 @@ write_header_footer(
return (1);
printf("pdfioContentTextShowf(\"%d\"): ", number);
if (pdfioContentTextShowf(st, "%d", number))
if (pdfioContentTextShowf(st, false, "%d", number))
puts("PASS");
else
return (1);
@ -1740,7 +1740,7 @@ write_png_test(pdfio_file_t *pdf, // I - PDF file
goto error;
fputs("pdfioContentTextShow(\"PNG RGB Color\"): ", stdout);
if (pdfioContentTextShow(st, "PNG RGB Color"))
if (pdfioContentTextShow(st, false, "PNG RGB Color"))
puts("PASS");
else
goto error;
@ -1752,7 +1752,7 @@ write_png_test(pdfio_file_t *pdf, // I - PDF file
goto error;
fputs("pdfioContentTextShow(\"PNG Gray\"): ", stdout);
if (pdfioContentTextShow(st, "PNG Gray"))
if (pdfioContentTextShow(st, false, "PNG Gray"))
puts("PASS");
else
goto error;
@ -1764,7 +1764,7 @@ write_png_test(pdfio_file_t *pdf, // I - PDF file
goto error;
fputs("pdfioContentTextShow(\"PNG Indexed\"): ", stdout);
if (pdfioContentTextShow(st, "PNG Indexed"))
if (pdfioContentTextShow(st, false, "PNG Indexed"))
puts("PASS");
else
goto error;
@ -1936,7 +1936,7 @@ write_text_test(pdfio_file_t *pdf, // I - PDF file
if (!pdfioContentSetFillColorDeviceGray(st, 0.75))
goto error;
if (!pdfioContentTextShowf(st, "%3d ", flinenum))
if (!pdfioContentTextShowf(st, false, "%3d ", flinenum))
goto error;
if (!pdfioContentSetFillColorDeviceGray(st, 0.0))
goto error;
@ -1948,15 +1948,15 @@ write_text_test(pdfio_file_t *pdf, // I - PDF file
temp[80] = '\n';
temp[81] = '\0';
if (!pdfioContentTextShow(st, temp))
if (!pdfioContentTextShow(st, false, temp))
goto error;
if (!pdfioContentTextShowf(st, " %s", line + 80))
if (!pdfioContentTextShowf(st, false, " %s", line + 80))
goto error;
plinenum ++;
}
else if (!pdfioContentTextShow(st, line))
else if (!pdfioContentTextShow(st, false, line))
goto error;
plinenum ++;

32
ttf.c
View File

@ -187,6 +187,8 @@ struct _ttf_s
char *postscript_name; // PostScript name string
char *version; // Font version string
bool is_fixed; // Is this a fixed-width font?
int max_char, // Last character in font
min_char; // First character in font
_ttf_metric_t *widths[TTF_FONT_MAX_CHAR / 256];
// Character metrics (sparse array)
float units; // Width units
@ -447,6 +449,8 @@ ttfCreate(const char *filename, // I - Filename
font->x_height = 3 * font->ascent / 5;
// Build a sparse glyph widths table...
font->min_char = -1;
for (i = 0; i < num_cmap; i ++)
{
if (cmap[i] >= 0)
@ -454,6 +458,12 @@ ttfCreate(const char *filename, // I - Filename
int bin = i / 256, // Sub-array bin
glyph = cmap[i]; // Glyph index
// Update min/max...
if (font->min_char < 0)
font->min_char = i;
font->max_char = i;
// Allocate a sub-array as needed...
if (!font->widths[bin])
font->widths[bin] = (_ttf_metric_t *)calloc(256, sizeof(_ttf_metric_t));
@ -720,6 +730,28 @@ ttfGetItalicAngle(ttf_t *font) // I - Font
}
//
// 'ttfGetMaxChar()' - Get the last character in the font.
//
int // O - Last character in font
ttfGetMaxChar(ttf_t *font) // I - Font
{
return (font ? font->max_char : 0);
}
//
// 'ttfGetMinChar()' - Get the first character in the font.
//
int // O - First character in font
ttfGetMinChar(ttf_t *font) // I - Font
{
return (font ? font->min_char : 0);
}
//
// 'ttfGetNumFonts()' - Get the number of fonts in this collection.
//

2
ttf.h
View File

@ -95,6 +95,8 @@ extern int ttfGetDescent(ttf_t *font);
extern ttf_rect_t *ttfGetExtents(ttf_t *font, float size, const char *s, ttf_rect_t *extents);
extern const char *ttfGetFamily(ttf_t *font);
extern float ttfGetItalicAngle(ttf_t *font);
extern int ttfGetMaxChar(ttf_t *font);
extern int ttfGetMinChar(ttf_t *font);
extern size_t ttfGetNumFonts(ttf_t *font);
extern const char *ttfGetPostScriptName(ttf_t *font);
extern ttf_stretch_t ttfGetStretch(ttf_t *font);