diff --git a/Makefile.in b/Makefile.in index fb1a25f..21a742e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -233,8 +233,7 @@ DOCFLAGS = \ doc: echo Generating documentation... codedoc $(DOCFLAGS) --title "PDFio Programming Manual v$(PDFIO_VERSION)" $(PUBHEADERS) $(PUBOBJS:.o=.c) --body doc/pdfio.md --coverimage doc/pdfio-512.png pdfio.xml >doc/pdfio.html - codedoc $(DOCFLAGS) --title "PDFio Programming Manual v$(PDFIO_VERSIONmc6809e - )" --body doc/pdfio.md --coverimage doc/pdfio-epub.png pdfio.xml --epub doc/pdfio.epub + codedoc $(DOCFLAGS) --title "PDFio Programming Manual v$(PDFIO_VERSION)" --body doc/pdfio.md --coverimage doc/pdfio-epub.png pdfio.xml --epub doc/pdfio.epub codedoc $(DOCFLAGS) --title "pdf read/write library" --man pdfio --section 3 --body doc/pdfio.md pdfio.xml >doc/pdfio.3 rm -f pdfio.xml diff --git a/pdfio-content.c b/pdfio-content.c index 7c591b9..8517166 100644 --- a/pdfio-content.c +++ b/pdfio-content.c @@ -1061,20 +1061,97 @@ pdfioContentTextEnd(pdfio_stream_t *st) // I - Stream // -// 'pdfioContextTextMeasure()' - Measure a text string and return its width. +// 'pdfioContentTextMeasure()' - Measure a text string and return its width. +// +// This function measures the given text string "s" and returns its width based +// on "size". The text string must always use the UTF-8 (Unicode) encoding but +// any control characters (such as newlines) are ignored. // double // O - Width -pdfioContextTextMeasure( +pdfioContentTextMeasure( pdfio_obj_t *font, // I - Font object created by @link pdfioFileCreateFontObjFromFile@ const char *s, // I - UTF-8 string double size) // I - Font size/height { + const char *subtype; // Font sub-type ttf_t *ttf = (ttf_t *)_pdfioObjGetExtension(font); // TrueType font data ttf_rect_t extents; // Text extents + int ch; // Unicode character + char temp[1024], // Temporary string + *tempptr; // Pointer into temporary string + if ((subtype = pdfioObjGetSubtype(font)) == NULL || strcmp(subtype, "Type0")) + { + // Map non-CP1282 characters to '?', everything else as-is... + tempptr = temp; + + while (*s && tempptr < (temp + sizeof(temp) - 3)) + { + if ((*s & 0xe0) == 0xc0) + { + // Two-byte UTF-8 + ch = ((s[0] & 0x1f) << 6) | (s[1] & 0x3f); + s += 2; + } + else if ((*s & 0xf0) == 0xe0) + { + // Three-byte UTF-8 + ch = ((s[0] & 0x0f) << 12) | ((s[1] & 0x3f) << 6) | (s[2] & 0x3f); + s += 3; + } + else if ((*s & 0xf8) == 0xf0) + { + // Four-byte UTF-8 + ch = ((s[0] & 0x07) << 18) | ((s[1] & 0x3f) << 12) | ((s[2] & 0x3f) << 6) | (s[3] & 0x3f); + s += 4; + } + else + { + ch = *s++; + } + + if (ch > 255) + { + // Try mapping from Unicode to CP1252... + size_t i; // Looping var + + for (i = 0; i < (sizeof(_pdfio_cp1252) / sizeof(_pdfio_cp1252[0])); i ++) + { + if (ch == _pdfio_cp1252[i]) + break; + } + + if (i >= (sizeof(_pdfio_cp1252) / sizeof(_pdfio_cp1252[0]))) + ch = '?'; // Unsupported chars map to ? + } + + if (ch < 128) + { + // ASCII + *tempptr++ = ch; + } + else if (ch < 2048) + { + // 2-byte UTF-8 + *tempptr++ = 0xc0 | ((ch >> 6) & 0x1f); + *tempptr++ = 0x80 | (ch & 0x3f); + } + else + { + // 3-byte UTF-8 + *tempptr++ = 0xe0 | ((ch >> 12) & 0x0f); + *tempptr++ = 0x80 | ((ch >> 6) & 0x3f); + *tempptr++ = 0x80 | (ch & 0x3f); + } + } + + *tempptr = '\0'; + s = temp; + } + ttfGetExtents(ttf, size, s, &extents); return (extents.right - extents.left); @@ -1654,7 +1731,7 @@ pdfioFileCreateFontObjFromFile( if (fd >= 0) close(fd); - ttfDelete(font); + _pdfioObjSetExtension(obj, font, (_pdfio_extfree_t)ttfDelete); return (obj); } diff --git a/pdfio-content.h b/pdfio-content.h index deb9341..24403d2 100644 --- a/pdfio-content.h +++ b/pdfio-content.h @@ -115,7 +115,7 @@ extern bool pdfioContentSetTextXScaling(pdfio_stream_t *st, double percent) _PD extern bool pdfioContentStroke(pdfio_stream_t *st) _PDFIO_PUBLIC; extern bool pdfioContentTextBegin(pdfio_stream_t *st) _PDFIO_PUBLIC; extern bool pdfioContentTextEnd(pdfio_stream_t *st) _PDFIO_PUBLIC; -extern double pdfioContextTextMeasure(pdfio_obj_t *font, const char *s, double size) _PDFIO_PUBLIC; +extern double pdfioContentTextMeasure(pdfio_obj_t *font, const char *s, double size) _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; diff --git a/pdfio-object.c b/pdfio-object.c index baa62f3..a24b2fb 100644 --- a/pdfio-object.c +++ b/pdfio-object.c @@ -217,8 +217,13 @@ void _pdfioObjDelete(pdfio_obj_t *obj) // I - Object { if (obj) + { pdfioStreamClose(obj->stream); + if (obj->datafree) + (obj->datafree)(obj->data); + } + free(obj); } @@ -511,9 +516,9 @@ pdfioObjOpenStream(pdfio_obj_t *obj, // I - Object void _pdfioObjSetExtension( - pdfio_obj_t *obj, // I - Object - void *data, // I - Data - void (*datafree)(void *)) // I - Free function + pdfio_obj_t *obj, // I - Object + void *data, // I - Data + _pdfio_extfree_t datafree) // I - Free function { obj->data = data; obj->datafree = datafree; diff --git a/pdfio-private.h b/pdfio-private.h index 92b002b..fc77148 100644 --- a/pdfio-private.h +++ b/pdfio-private.h @@ -92,6 +92,9 @@ # define PDFIO_MAX_DEPTH 32 // Maximum nesting depth for values +typedef void (*_pdfio_extfree_t)(void *); + // Extension data free function + typedef enum _pdfio_mode_e // Read/write mode { _PDFIO_MODE_READ, // Read a PDF file @@ -288,7 +291,7 @@ struct _pdfio_obj_s // Object _pdfio_value_t value; // Dictionary/number/etc. value pdfio_stream_t *stream; // Open stream, if any void *data; // Extension data, if any - void (*datafree)(void *); // Free callback for extension data + _pdfio_extfree_t datafree; // Free callback for extension data }; struct _pdfio_stream_s // Stream @@ -369,7 +372,7 @@ extern bool _pdfioFileWrite(pdfio_file_t *pdf, const void *buffer, size_t bytes extern void _pdfioObjDelete(pdfio_obj_t *obj) _PDFIO_INTERNAL; extern void *_pdfioObjGetExtension(pdfio_obj_t *obj) _PDFIO_INTERNAL; extern bool _pdfioObjLoad(pdfio_obj_t *obj) _PDFIO_INTERNAL; -extern void _pdfioObjSetExtension(pdfio_obj_t *obj, void *data, void (*datafree)(void *)) _PDFIO_INTERNAL; +extern void _pdfioObjSetExtension(pdfio_obj_t *obj, void *data, _pdfio_extfree_t datafree) _PDFIO_INTERNAL; extern pdfio_stream_t *_pdfioStreamCreate(pdfio_obj_t *obj, pdfio_obj_t *length_obj, pdfio_filter_t compression) _PDFIO_INTERNAL; extern pdfio_stream_t *_pdfioStreamOpen(pdfio_obj_t *obj, bool decode) _PDFIO_INTERNAL; diff --git a/testpdfio.c b/testpdfio.c index 002e74a..b507e08 100644 --- a/testpdfio.c +++ b/testpdfio.c @@ -2242,6 +2242,7 @@ write_font_test( char title[256], // Page title textname[256], // Name of text font *ptr; // Pointer into name + double width; // Text width int i; // Looping var static const char * const welcomes[] =// "Welcome" in many languages { @@ -2463,8 +2464,8 @@ write_font_test( else goto error; - fputs("pdfioContentTextMoveTo(36.0, 702.0): ", stdout); - if (pdfioContentTextMoveTo(st, 36.0, 702.0)) + fputs("pdfioContentTextMoveTo(198.0, 702.0): ", stdout); + if (pdfioContentTextMoveTo(st, 198.0, 702.0)) puts("PASS"); else return (1); @@ -2473,18 +2474,36 @@ write_font_test( { if (i > 0 && (i % 50) == 0) { - fputs("pdfioContentTextMoveTo(200.0, 600.0): ", stdout); - if (pdfioContentTextMoveTo(st, 200.0, 600.0)) + fputs("pdfioContentTextMoveTo(162.0, 600.0): ", stdout); + if (pdfioContentTextMoveTo(st, 162.0, 600.0)) puts("PASS"); else return (1); } + printf("pdfioContentTextMeasure(\"%s\"): ", welcomes[i]); + if ((width = pdfioContentTextMeasure(textfont, welcomes[i], 10.0)) >= 0.0) + puts("PASS"); + else + return (1); + + printf("pdfioContextTextMoveTo(%g, 0.0): ", -width); + if (pdfioContentTextMoveTo(st, -width, 0.0)) + puts("PASS"); + else + return (1); + printf("pdfioContentTextShowf(\"%s\"): ", welcomes[i]); if (pdfioContentTextShowf(st, unicode, "%s\n", welcomes[i])) puts("PASS"); else return (1); + + printf("pdfioContextTextMoveTo(%g, 0.0): ", width); + if (pdfioContentTextMoveTo(st, width, 0.0)) + puts("PASS"); + else + return (1); } fputs("pdfioContentTextEnd(): ", stdout);