From d3d668304197e632173fcbed8798834e0c26383a Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Fri, 13 Dec 2024 17:39:16 -0500 Subject: [PATCH] Add support for measuring base fonts (Issue #84) Update md2pdf example code to support using embedded TrueType or PDF base fonts. --- CHANGES.md | 2 + examples/md2pdf.c | 21 ++- pdfio-base-font-widths.h | 308 +++++++++++++++++++++++++++++++++++++++ pdfio-content.c | 169 +++++++++++++-------- 4 files changed, 439 insertions(+), 61 deletions(-) create mode 100644 pdfio-base-font-widths.h diff --git a/CHANGES.md b/CHANGES.md index 73ac375..ac9b37a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,8 @@ v1.4.0 - YYYY-MM-DD - Added new `pdfioFileCreateNameObj` and `pdfioObjGetName` APIs for creating and getting name object values (Issue #76) - Updated documentation (Issue #78) +- Updated `pdfioContentTextMeasure` to support measuring PDF base fonts created + with `pdfioFileCreateFontObjFromBase` (Issue #84) - Fixed reading of PDF files whose trailer is missing a newline (Issue #80) - Fixed builds with some versions of VC++ (Issue #81) diff --git a/examples/md2pdf.c b/examples/md2pdf.c index c6e27b1..9699c05 100644 --- a/examples/md2pdf.c +++ b/examples/md2pdf.c @@ -138,6 +138,10 @@ typedef struct tablerow_s // Table row // Constants... // +#define USE_TRUETYPE 1 // Set to 1 to use Roboto TrueType fonts + +#if USE_TRUETYPE +# define UNICODE_VALUE true // `true` for Unicode text, `false` for ISO-8859-1 static const char * const docfont_filenames[] = { "Roboto-Regular.ttf", @@ -145,6 +149,16 @@ static const char * const docfont_filenames[] = "Roboto-Italic.ttf", "RobotoMono-Regular.ttf" }; +#else +# define UNICODE_VALUE false // `true` for Unicode text, `false` for ISO-8859-1 +static const char * const docfont_filenames[] = +{ + "Helvetica", + "Helvetica-Bold", + "Helvetica-Oblique", + "Courier" +}; +#endif // USE_TRUETYPE static const char * const docfont_names[] = { @@ -183,8 +197,6 @@ static const char * const docfont_names[] = #define TABLE_PADDING 4.5 // Table padding value -#define UNICODE_VALUE true // `true` for Unicode text, `false` for ISO-8859-1 - // // 'mmd_walk_next()' - Find the next markdown node. @@ -1333,8 +1345,13 @@ main(int argc, // I - Number of command-line arguments // Add fonts... for (fontface = DOCFONT_REGULAR; fontface < DOCFONT_MAX; fontface ++) { +#if USE_TRUETYPE if ((dd.fonts[fontface] = pdfioFileCreateFontObjFromFile(dd.pdf, docfont_filenames[fontface], UNICODE_VALUE)) == NULL) return (1); +#else + if ((dd.fonts[fontface] = pdfioFileCreateFontObjFromBase(dd.pdf, docfont_filenames[fontface])) == NULL) + return (1); +#endif // USE_TRUETYPE } // Add images... diff --git a/pdfio-base-font-widths.h b/pdfio-base-font-widths.h new file mode 100644 index 0000000..f311da9 --- /dev/null +++ b/pdfio-base-font-widths.h @@ -0,0 +1,308 @@ +// +// PDF base font widths for PDFio. +// +// Copyright © 2024 by Michael R Sweet. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// + +#ifndef PDFIO_BASE_FONT_WIDTHS_H +# define PDFIO_BASE_FONT_WIDTHS_H 1 + + +static short courier_bold_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, + 600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0, + 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600, + 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600 +}; + + +static short courier_boldoblique_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, + 600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0, + 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600, + 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600 +}; + + +static short courier_oblique_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, + 600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0, + 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600, + 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600 +}; + + +static short courier_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, + 600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0, + 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600, + 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600 +}; + + +static short helvetica_bold_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, + 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, + 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, + 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, + 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, + 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 0, + 556, 0, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0, + 0, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 0, 500, 667, + 0, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 584, 737, 333, + 606, 584, 351, 351, 333, 611, 556, 278, 333, 351, 365, 556, 869, 869, 869, 611, + 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, + 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, + 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, + 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556 +}; + + +static short helvetica_boldoblique_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, + 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, + 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, + 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, + 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, + 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 0, + 556, 0, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0, + 0, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 0, 500, 667, + 0, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 584, 737, 333, + 606, 584, 444, 444, 333, 611, 556, 278, 333, 444, 365, 556, 1055, 1055, 1055, 611, + 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, + 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, + 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, + 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556 +}; + + +static short helvetica_oblique_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, + 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, + 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, + 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, + 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, + 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 0, + 556, 0, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0, + 0, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 0, 500, 667, + 0, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 584, 737, 333, + 606, 584, 390, 390, 333, 556, 537, 278, 333, 390, 365, 556, 947, 947, 947, 611, + 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, + 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, + 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, + 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500 +}; + + +static short helvetica_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, + 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, + 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, + 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, + 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, + 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 0, + 556, 0, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0, + 0, 222, 221, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 0, 500, 667, + 0, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 584, 737, 333, + 606, 584, 351, 351, 333, 556, 537, 278, 333, 351, 365, 556, 869, 869, 869, 611, + 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, + 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 666, 666, 611, + 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, + 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 555, 500 +}; + + +static short symbol_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 250, 333, 713, 500, 549, 833, 778, 439, 333, 333, 500, 549, 250, 549, 250, 278, + 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 549, 549, 549, 444, + 549, 722, 667, 722, 612, 611, 763, 603, 722, 333, 631, 722, 686, 889, 722, 722, + 768, 741, 556, 592, 611, 690, 439, 768, 645, 795, 611, 333, 863, 333, 658, 500, + 500, 631, 549, 549, 494, 439, 521, 411, 603, 329, 603, 549, 549, 576, 521, 549, + 549, 521, 549, 603, 439, 576, 713, 686, 493, 686, 494, 480, 200, 480, 549, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 762, 620, 247, 549, 167, 713, 500, 753, 753, 753, 753, 1042, 987, 603, 987, 603, + 400, 549, 411, 549, 549, 713, 494, 460, 549, 549, 549, 549, 1000, 603, 1000, 658, + 823, 686, 795, 987, 768, 768, 823, 768, 768, 713, 713, 713, 713, 713, 713, 713, + 768, 713, 790, 790, 890, 823, 549, 250, 713, 603, 603, 1042, 987, 603, 987, 603, + 494, 329, 790, 790, 786, 713, 384, 384, 384, 384, 384, 384, 494, 494, 494, 494, + 0, 329, 274, 686, 686, 686, 384, 384, 384, 384, 384, 384, 494, 494, 494, 0 +}; + + +static short times_bold_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 250, 333, 555, 500, 500, 1000, 833, 278, 333, 333, 500, 570, 250, 333, 250, 278, + 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, + 930, 722, 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667, 944, 722, 778, + 611, 778, 722, 556, 667, 722, 722, 1000, 722, 722, 667, 333, 278, 333, 581, 500, + 333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833, 556, 500, + 556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520, 0, + 500, 0, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 1000, 0, 667, 0, + 0, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 0, 444, 722, + 0, 333, 500, 500, 500, 500, 220, 500, 333, 747, 300, 500, 570, 570, 747, 333, + 400, 570, 300, 300, 333, 556, 540, 250, 333, 300, 330, 500, 750, 750, 750, 500, + 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 389, 389, 389, 389, + 722, 722, 778, 778, 778, 778, 778, 570, 778, 722, 722, 722, 722, 722, 611, 556, + 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, + 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 500, 556, 500 +}; + + +static short times_bolditalic_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 250, 389, 555, 500, 500, 833, 778, 278, 333, 333, 500, 570, 250, 333, 250, 278, + 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, + 832, 667, 667, 667, 722, 667, 667, 722, 778, 389, 500, 667, 611, 889, 722, 722, + 611, 722, 667, 556, 611, 722, 667, 889, 667, 611, 611, 333, 278, 333, 570, 500, + 333, 500, 500, 444, 500, 444, 333, 500, 556, 278, 278, 500, 278, 778, 556, 500, + 500, 500, 389, 389, 278, 556, 444, 667, 500, 444, 389, 348, 220, 348, 570, 0, + 500, 0, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 944, 0, 611, 0, + 0, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 0, 389, 611, + 0, 389, 500, 500, 500, 500, 220, 500, 333, 747, 266, 500, 606, 606, 747, 333, + 400, 570, 300, 300, 333, 576, 500, 250, 333, 300, 300, 500, 750, 750, 750, 500, + 667, 667, 667, 667, 667, 667, 944, 667, 667, 667, 667, 667, 389, 389, 389, 389, + 722, 722, 722, 722, 722, 722, 722, 570, 722, 722, 722, 722, 722, 611, 611, 500, + 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, + 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 444, 500, 444 +}; + + +static short times_italic_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 250, 333, 420, 500, 500, 833, 778, 214, 333, 333, 500, 675, 250, 333, 250, 278, + 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 675, 675, 675, 500, + 920, 611, 611, 667, 722, 611, 611, 722, 722, 333, 444, 667, 556, 833, 667, 722, + 611, 722, 611, 500, 556, 722, 611, 833, 611, 556, 556, 389, 278, 389, 422, 500, + 333, 500, 500, 444, 500, 444, 278, 500, 500, 278, 278, 444, 278, 722, 500, 500, + 500, 500, 389, 389, 278, 500, 444, 667, 444, 444, 389, 400, 275, 400, 541, 0, + 500, 0, 333, 500, 556, 889, 500, 500, 333, 1000, 500, 333, 944, 0, 556, 0, + 0, 333, 333, 556, 556, 350, 500, 889, 333, 980, 389, 333, 667, 0, 389, 556, + 0, 389, 500, 500, 500, 500, 275, 500, 333, 760, 276, 500, 675, 675, 760, 333, + 400, 675, 300, 300, 333, 500, 523, 250, 333, 300, 310, 500, 750, 750, 750, 500, + 611, 611, 611, 611, 611, 611, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, + 722, 667, 722, 722, 722, 722, 722, 675, 722, 722, 722, 722, 722, 556, 611, 500, + 500, 500, 500, 500, 500, 500, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, + 500, 500, 500, 500, 500, 500, 500, 675, 500, 500, 500, 500, 500, 444, 500, 444 +}; + + +static short times_roman_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 250, 333, 408, 500, 500, 833, 778, 180, 333, 333, 500, 564, 250, 333, 250, 278, + 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444, + 921, 722, 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611, 889, 722, 722, + 556, 722, 667, 556, 611, 722, 722, 944, 722, 722, 611, 333, 278, 333, 469, 500, + 333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778, 500, 500, + 500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541, 0, + 500, 0, 333, 500, 444, 1000, 500, 500, 333, 1000, 556, 333, 889, 0, 611, 0, + 0, 333, 333, 444, 444, 350, 500, 1000, 333, 980, 389, 333, 722, 0, 444, 722, + 0, 333, 500, 500, 500, 500, 200, 500, 333, 760, 276, 500, 564, 564, 760, 333, + 400, 564, 300, 300, 333, 500, 453, 250, 333, 300, 310, 500, 750, 750, 750, 444, + 722, 722, 722, 722, 722, 722, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, + 722, 722, 722, 722, 722, 722, 722, 564, 722, 722, 722, 722, 722, 722, 556, 500, + 444, 444, 444, 444, 444, 444, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, + 500, 500, 500, 500, 500, 500, 500, 564, 500, 500, 500, 500, 500, 500, 500, 500 +}; + + +static short zapf_dingbats_widths[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 278, 974, 961, 974, 980, 719, 789, 790, 791, 690, 960, 939, 549, 855, 911, 933, + 911, 945, 974, 755, 846, 762, 761, 571, 677, 763, 760, 759, 754, 494, 552, 537, + 577, 692, 786, 788, 788, 790, 793, 794, 816, 823, 789, 841, 823, 833, 816, 831, + 923, 744, 723, 749, 790, 792, 695, 776, 768, 792, 759, 707, 708, 682, 701, 826, + 815, 789, 789, 707, 687, 696, 689, 786, 787, 713, 791, 785, 791, 873, 761, 762, + 762, 759, 759, 892, 892, 788, 784, 438, 138, 277, 415, 392, 392, 668, 668, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 732, 544, 544, 910, 667, 760, 760, 776, 595, 694, 626, 788, 788, 788, 788, + 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, + 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, + 788, 788, 788, 788, 894, 838, 1016, 458, 748, 924, 748, 918, 927, 928, 928, 834, + 873, 828, 924, 924, 917, 930, 931, 463, 883, 836, 836, 867, 867, 696, 696, 874, + 0, 874, 760, 946, 771, 865, 771, 888, 967, 888, 831, 873, 927, 970, 918, 0 +}; + + +#endif // !PDFIO_BASE_FONT_WIDTHS_H diff --git a/pdfio-content.c b/pdfio-content.c index 936404c..3009636 100644 --- a/pdfio-content.c +++ b/pdfio-content.c @@ -1,7 +1,7 @@ // // Content helper functions for PDFio. // -// Copyright © 2021-2023 by Michael R Sweet. +// Copyright © 2021-2024 by Michael R Sweet. // // Licensed under Apache License v2.0. See the file "LICENSE" for more // information. @@ -9,6 +9,7 @@ #include "pdfio-private.h" #include "pdfio-content.h" +#include "pdfio-base-font-widths.h" #include "ttf.h" #include #ifndef M_PI @@ -1074,7 +1075,7 @@ pdfioContentTextMeasure( const char *s, // I - UTF-8 string double size) // I - Font size/height { - const char *subtype; // Font sub-type + const char *basefont; // Base font name ttf_t *ttf = (ttf_t *)_pdfioObjGetExtension(font); // TrueType font data ttf_rect_t extents; // Text extents @@ -1083,75 +1084,124 @@ pdfioContentTextMeasure( *tempptr; // Pointer into temporary string - if ((subtype = pdfioObjGetSubtype(font)) == NULL || strcmp(subtype, "Type0")) + if (!ttf && (basefont = pdfioDictGetName(pdfioObjGetDict(font), "BaseFont")) != NULL) { - // Map non-CP1282 characters to '?', everything else as-is... - tempptr = temp; + // Measure the width using the compiled-in base font tables... + const short *widths; // Widths + int width = 0; // Current width - while (*s && tempptr < (temp + sizeof(temp) - 3)) + if (strcmp(basefont, "Symbol") && strcmp(basefont, "Zapf-Dingbats")) { - 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++; - } + // Map non-CP1282 characters to '?', everything else as-is... + tempptr = temp; - if (ch > 255) + while (*s && tempptr < (temp + sizeof(temp) - 3)) { - // Try mapping from Unicode to CP1252... - size_t i; // Looping var - - for (i = 0; i < (sizeof(_pdfio_cp1252) / sizeof(_pdfio_cp1252[0])); i ++) + if ((*s & 0xe0) == 0xc0) { - if (ch == _pdfio_cp1252[i]) - break; + // 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 (i >= (sizeof(_pdfio_cp1252) / sizeof(_pdfio_cp1252[0]))) - ch = '?'; // Unsupported chars map to ? + 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++ = (char)ch; + } + else if (ch < 2048) + { + // 2-byte UTF-8 + *tempptr++ = (char)(0xc0 | ((ch >> 6) & 0x1f)); + *tempptr++ = (char)(0x80 | (ch & 0x3f)); + } + else + { + // 3-byte UTF-8 + *tempptr++ = (char)(0xe0 | ((ch >> 12) & 0x0f)); + *tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f)); + *tempptr++ = (char)(0x80 | (ch & 0x3f)); + } } - if (ch < 128) - { - // ASCII - *tempptr++ = (char)ch; - } - else if (ch < 2048) - { - // 2-byte UTF-8 - *tempptr++ = (char)(0xc0 | ((ch >> 6) & 0x1f)); - *tempptr++ = (char)(0x80 | (ch & 0x3f)); - } - else - { - // 3-byte UTF-8 - *tempptr++ = (char)(0xe0 | ((ch >> 12) & 0x0f)); - *tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f)); - *tempptr++ = (char)(0x80 | (ch & 0x3f)); - } + *tempptr = '\0'; + s = temp; } - *tempptr = '\0'; - s = temp; + // Choose the appropriate table... + if (!strcmp(basefont, "Courier")) + widths = courier_widths; + else if (!strcmp(basefont, "Courier-Bold")) + widths = courier_bold_widths; + else if (!strcmp(basefont, "Courier-BoldOblique")) + widths = courier_boldoblique_widths; + else if (!strcmp(basefont, "Courier-Oblique")) + widths = courier_oblique_widths; + else if (!strcmp(basefont, "Helvetica")) + widths = helvetica_widths; + else if (!strcmp(basefont, "Helvetica-Bold")) + widths = helvetica_bold_widths; + else if (!strcmp(basefont, "Helvetica-BoldOblique")) + widths = helvetica_boldoblique_widths; + else if (!strcmp(basefont, "Helvetica-Oblique")) + widths = helvetica_oblique_widths; + else if (!strcmp(basefont, "Symbol")) + widths = symbol_widths; + else if (!strcmp(basefont, "Times-Bold")) + widths = times_bold_widths; + else if (!strcmp(basefont, "Times-BoldItalic")) + widths = times_bolditalic_widths; + else if (!strcmp(basefont, "Times-Italic")) + widths = times_italic_widths; + else if (!strcmp(basefont, "Times-Roman")) + widths = times_roman_widths; + else if (!strcmp(basefont, "Zapf-Dingbats")) + widths = zapf_dingbats_widths; + else + return (0.0); + + // Calculate the width using the corresponding table... + while (*s) + { + width += widths[*s & 255]; + s ++; + } + + return (size * 0.001 * width); } + // If we get here then we need to measure using the TrueType library... ttfGetExtents(ttf, (float)size, s, &extents); return (extents.right - extents.left); @@ -1421,8 +1471,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. +// Aside from "Symbol" and "Zapf-Dingbats", Base fonts use the Windows CP1252 +// (ISO-8859-1 with additional characters such as the Euro symbol) subset of +// Unicode. // pdfio_obj_t * // O - Font object