From 82e62ae852e4f4ce81195404c3fb0e3d8373ffd7 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Mon, 31 May 2021 19:41:02 -0400 Subject: [PATCH] Basic text support. --- pdfio-content.c | 214 +++++++++++++++++++++++++++++++++++++++--------- pdfio-content.h | 10 ++- testpdfio.c | 184 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 355 insertions(+), 53 deletions(-) diff --git a/pdfio-content.c b/pdfio-content.c index 0052036..ad2a44f 100644 --- a/pdfio-content.c +++ b/pdfio-content.c @@ -45,19 +45,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_png(pdfio_dict_t *dict, int fd); static pdfio_array_t *create_calcolor(pdfio_file_t *pdf, size_t num_colors, double gamma, const double matrix[3][3], const double white_point[3]); -static bool write_string(pdfio_stream_t *st, const char *s); - - -// -// 'pdfioContentBeginText()' - Begin a text block. -// - -bool // O - `true` on success, `false` on failure -pdfioContentBeginText( - pdfio_stream_t *st) // I - Stream -{ - return (pdfioStreamPuts(st, "BT\n")); -} +static bool write_string(pdfio_stream_t *st, const char *s, bool *newline); // @@ -93,17 +81,6 @@ pdfioContentDrawImage( } -// -// 'pdfioContentEndText()' - End a text block. -// - -bool // O - `true` on success, `false` on failure -pdfioContentEndText(pdfio_stream_t *st) // I - Stream -{ - return (pdfioStreamPuts(st, "ET\n")); -} - - // // 'pdfioContentFill()' - Fill the current path. // @@ -683,6 +660,29 @@ pdfioContentStroke(pdfio_stream_t *st) // I - Stream } +// +// 'pdfioContentTextBegin()' - Begin a text block. +// + +bool // O - `true` on success, `false` on failure +pdfioContentTextBegin( + pdfio_stream_t *st) // I - Stream +{ + return (pdfioStreamPuts(st, "BT\n")); +} + + +// +// 'pdfioContentTextEnd()' - End a text block. +// + +bool // O - `true` on success, `false` on failure +pdfioContentTextEnd(pdfio_stream_t *st) // I - Stream +{ + return (pdfioStreamPuts(st, "ET\n")); +} + + // // 'pdfioContentTextMoveLine()' - Move to the next line and offset. // @@ -730,12 +730,49 @@ pdfioContentTextNextLine( bool // O - `true` on success, `false` on failure pdfioContentTextShow( pdfio_stream_t *st, // I - Stream - const char *s, // I - String to show - bool new_line) // I - Advance to the next line afterwards + const char *s) // I - String to show { - write_string(st, s); + bool newline = false; // New line? - if (new_line) + + // Write the string... + if (!write_string(st, s, &newline)) + return (false); + + // Draw it... + if (newline) + return (pdfioStreamPuts(st, "\'\n")); + else + return (pdfioStreamPuts(st, "Tj\n")); +} + + +// +// 'pdfioContentTextShowf()' - Show formatted text. +// + +bool +pdfioContentTextShowf( + pdfio_stream_t *st, // I - Stream + const char *format, // I - `printf`-style format string + ...) // I - Additional arguments as needed +{ + bool newline = false; // New line? + char buffer[8192]; // Text buffer + va_list ap; // Argument pointer + + + // Format the string... + va_start(ap, format); + vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + + // Write the string... + if (!write_string(st, buffer, &newline)) + return (false); + + // Draw it... + if (newline) return (pdfioStreamPuts(st, "\'\n")); else return (pdfioStreamPuts(st, "Tj\n")); @@ -770,7 +807,7 @@ pdfioContentTextShowJustified( if (fragments[i]) { - if (!write_string(st, fragments[i])) + if (!write_string(st, fragments[i], NULL)) return (false); } } @@ -854,11 +891,36 @@ pdfioPageDictAddFont( const char *name, // I - Font name pdfio_obj_t *obj) // I - Font object { - (void)dict; - (void)name; - (void)obj; + pdfio_dict_t *resources; // Resource dictionary + pdfio_dict_t *font; // Font dictionary - return (false); + + // Range check input... + if (!dict || !name || !obj) + return (false); + + // Get the Resources dictionary... + if ((resources = pdfioDictGetDict(dict, "Resources")) == NULL) + { + if ((resources = pdfioDictCreate(dict->pdf)) == NULL) + return (false); + + if (!pdfioDictSetDict(dict, "Resources", resources)) + return (false); + } + + // Get the Font dictionary... + if ((font = pdfioDictGetDict(resources, "Font")) == NULL) + { + if ((font = pdfioDictCreate(dict->pdf)) == NULL) + return (false); + + if (!pdfioDictSetDict(resources, "Font", font)) + return (false); + } + + // Now set the image reference in the Font resource dictionary and return... + return (pdfioDictSetObject(font, name, obj)); } @@ -905,17 +967,74 @@ pdfioPageDictAddImage( } +// +// 'pdfioFileCreateBaseFontObject()' - Create one of the base 14 PDF fonts. +// +// This function creates one of the base 14 PDF fonts. The "name" parameter +// specifies the font nane: +// +// - `Courier` +// - `Courier-Bold` +// - `Courier-BoldItalic` +// - `Courier-Italic` +// - `Helvetica` +// - `Helvetica-Bold` +// - `Helvetica-BoldOblique` +// - `Helvetica-Oblique` +// - `Symbol` +// - `Times-Bold` +// - `Times-BoldItalic` +// - `Times-Italic` +// - `Times-Roman` +// - `ZapfDingbats` +// + +pdfio_obj_t * // O - Font object +pdfioFileCreateBaseFontObject( + pdfio_file_t *pdf, // I - PDF file + const char *name) // I - Font name +{ + pdfio_dict_t *dict; // Font dictionary + pdfio_obj_t *obj; // Font object + + + if ((dict = pdfioDictCreate(pdf)) == NULL) + return (NULL); + + pdfioDictSetName(dict, "Type", "Font"); + pdfioDictSetName(dict, "Subtype", "Type1"); + pdfioDictSetName(dict, "BaseFont", pdfioStringCreate(pdf, name)); + pdfioDictSetName(dict, "Encoding", "WinAnsiEncoding"); + + if ((obj = pdfioFileCreateObject(dict->pdf, dict)) != NULL) + pdfioObjClose(obj); + + return (obj); +} + + // // 'pdfioFileCreateFontObject()' - Add a font object to a PDF file. // -pdfio_obj_t * // O - Object +pdfio_obj_t * // O - Font object pdfioFileCreateFontObject( pdfio_file_t *pdf, // I - PDF file - const char *filename) // I - Filename + const char *filename, // I - Filename + bool unicode) // I - Unicode font? { +#if 0 + pdfio_dict_t *dict; // Font dictionary + pdfio_obj_t *obj; // Font object + pdfio_st_t *st; // Content stream + int fd; // File + char buffer[16384]; // Copy buffer + ssize_t bytes; // Bytes read +#endif // 0 + (void)pdf; (void)filename; + (void)unicode; return (NULL); } @@ -1274,7 +1393,8 @@ create_calcolor( static bool // O - `true` on success, `false` otherwise write_string(pdfio_stream_t *st, // I - Stream - const char *s) // I - String + const char *s, // I - String + bool *newline) // O - Ends with a newline? { const char *ptr; // Pointer into string @@ -1291,7 +1411,7 @@ write_string(pdfio_stream_t *st, // I - Stream // Unicode string... int ch; // Unicode character - if (!pdfioStreamPuts(st, "(")) + if (!pdfioStreamPuts(st, "<")) return (false); for (ptr = s; *ptr; ptr ++) @@ -1314,6 +1434,11 @@ write_string(pdfio_stream_t *st, // I - Stream 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; @@ -1321,7 +1446,7 @@ write_string(pdfio_stream_t *st, // I - Stream if (!pdfioStreamPrintf(st, "%04X", ch)) return (false); } - if (!pdfioStreamPuts(st, ")")) + if (!pdfioStreamPuts(st, ">")) return (false); } else @@ -1357,6 +1482,19 @@ write_string(pdfio_stream_t *st, // I - Stream level ++; else if (*ptr == ')') level --; + else if (*ptr == '\n' && newline) + { + if (ptr > start) + { + if (!pdfioStreamWrite(st, start, (size_t)(ptr - start))) + return (false); + + start = ptr + 1; + } + + *newline = true; + break; + } } if (ptr > start) diff --git a/pdfio-content.h b/pdfio-content.h index 4612d1f..7323111 100644 --- a/pdfio-content.h +++ b/pdfio-content.h @@ -84,10 +84,8 @@ extern const double pdfioSRGBWhitePoint[3] PDFIO_PUBLIC; // // PDF content drawing functions... -extern bool pdfioContentBeginText(pdfio_stream_t *st) PDFIO_PUBLIC; extern bool pdfioContentClip(pdfio_stream_t *st, bool even_odd) PDFIO_PUBLIC; extern bool pdfioContentDrawImage(pdfio_stream_t *st, const char *name, double x, double y, double w, double h) PDFIO_PUBLIC; -extern bool pdfioContentEndText(pdfio_stream_t *st) PDFIO_PUBLIC; extern bool pdfioContentFill(pdfio_stream_t *st, bool even_odd) PDFIO_PUBLIC; extern bool pdfioContentFillAndStroke(pdfio_stream_t *st, bool even_odd) PDFIO_PUBLIC; extern bool pdfioContentMatrixConcat(pdfio_stream_t *st, pdfio_matrix_t m) PDFIO_PUBLIC; @@ -130,14 +128,18 @@ extern bool pdfioContentSetTextRise(pdfio_stream_t *st, double rise) PDFIO_PUBL extern bool pdfioContentSetTextWordSpacing(pdfio_stream_t *st, double spacing) PDFIO_PUBLIC; extern bool pdfioContentSetTextXScaling(pdfio_stream_t *st, double percent) PDFIO_PUBLIC; 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 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, bool new_line) 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; // Resource helpers... -extern pdfio_obj_t *pdfioFileCreateFontObject(pdfio_file_t *pdf, const char *filename) PDFIO_PUBLIC; +extern pdfio_obj_t *pdfioFileCreateBaseFontObject(pdfio_file_t *pdf, const char *name) PDFIO_PUBLIC; +extern pdfio_obj_t *pdfioFileCreateFontObject(pdfio_file_t *pdf, const char *filename, bool unicode) PDFIO_PUBLIC; extern pdfio_obj_t *pdfioFileCreateICCProfileObject(pdfio_file_t *pdf, const char *filename) PDFIO_PUBLIC; extern pdfio_obj_t *pdfioFileCreateImageObject(pdfio_file_t *pdf, const char *filename, bool interpolate) PDFIO_PUBLIC; diff --git a/testpdfio.c b/testpdfio.c index beb89de..ab36368 100644 --- a/testpdfio.c +++ b/testpdfio.c @@ -26,8 +26,8 @@ static bool error_cb(pdfio_file_t *pdf, const char *message, bool *error); static ssize_t token_consume_cb(const char **s, size_t bytes); static ssize_t token_peek_cb(const char **s, char *buffer, size_t bytes); static int write_color_patch(pdfio_stream_t *st, bool device); -static int write_color_test(pdfio_file_t *pdf, int number); -static int write_page(pdfio_file_t *pdf, int number, pdfio_obj_t *image); +static int write_color_test(pdfio_file_t *pdf, int number, pdfio_obj_t *font); +static int write_page(pdfio_file_t *pdf, int number, pdfio_obj_t *font, pdfio_obj_t *image); // @@ -160,6 +160,7 @@ do_unit_tests(void) _pdfio_value_t value; // Value pdfio_obj_t *color_jpg, // color.jpg image *gray_jpg, // gray.jpg image + *helvetica, // Helvetica font *page; // Page from test PDF file static const char *complex_dict = // Complex dictionary value "<