Basic text support.

This commit is contained in:
Michael R Sweet 2021-05-31 19:41:02 -04:00
parent c4e0421f62
commit 82e62ae852
No known key found for this signature in database
GPG Key ID: 999559A027815955
3 changed files with 355 additions and 53 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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
"<</Annots 5457 0 R/Contents 5469 0 R/CropBox[0 0 595.4 842]/Group 725 0 R"
@ -217,6 +218,13 @@ do_unit_tests(void)
else
return (1);
// Create fonts...
fputs("pdfioFileCreateBaseFontObject(\"Helvetica\"): ", stdout);
if ((helvetica = pdfioFileCreateBaseFontObject(outpdf, "Helvetica")) != NULL)
puts("PASS");
else
return (1);
// Copy the first page from the test PDF file...
fputs("pdfioFileGetPage(0): ", stdout);
if ((page = pdfioFileGetPage(pdf, 0)) != NULL)
@ -231,7 +239,7 @@ do_unit_tests(void)
return (1);
// Write a page with a color image...
if (write_page(outpdf, 2, color_jpg))
if (write_page(outpdf, 2, helvetica, color_jpg))
return (1);
// Copy the third page from the test PDF file...
@ -248,11 +256,11 @@ do_unit_tests(void)
return (1);
// Write a page with a grayscale image...
if (write_page(outpdf, 4, gray_jpg))
if (write_page(outpdf, 4, helvetica, gray_jpg))
return (1);
// Write a page that tests multiple color spaces...
if (write_color_test(outpdf, 5))
if (write_color_test(outpdf, 5, helvetica))
return (1);
// Close the test PDF file...
@ -489,7 +497,8 @@ write_color_patch(pdfio_stream_t *st, // I - Content stream
static int // O - 1 on failure, 0 on success
write_color_test(pdfio_file_t *pdf, // I - PDF file
int number) // I - Page number
int number, // I - Page number
pdfio_obj_t *font) // I - Text font
{
pdfio_dict_t *dict; // Page dictionary
pdfio_stream_t *st; // Page contents stream
@ -519,6 +528,12 @@ write_color_test(pdfio_file_t *pdf, // I - PDF file
else
return (1);
fputs("pdfioPageDictAddFont(F1): ", stdout);
if (pdfioPageDictAddFont(dict, "F1", font))
puts("PASS");
else
return (1);
printf("pdfioFileCreatePage(%d): ", number);
if ((st = pdfioFileCreatePage(pdf, dict)) != NULL)
@ -526,6 +541,108 @@ write_color_test(pdfio_file_t *pdf, // I - PDF file
else
return (1);
fputs("pdfioContentSetStrokeColorDeviceGray(0.0): ", stdout);
if (pdfioContentSetStrokeColorDeviceGray(st, 0.0))
puts("PASS");
else
return (1);
fputs("pdfioContentTextBegin(): ", stdout);
if (pdfioContentTextBegin(st))
puts("PASS");
else
return (1);
fputs("pdfioContentSetTextFont(\"F1\", 12.0): ", stdout);
if (pdfioContentSetTextFont(st, "F1", 12.0))
puts("PASS");
else
return (1);
fputs("pdfioContentTextMoveTo(550.0, 36.0): ", stdout);
if (pdfioContentTextMoveTo(st, 550.0, 36.0))
puts("PASS");
else
return (1);
printf("pdfioContentTextShowf(\"%d\"): ", number);
if (pdfioContentTextShowf(st, "%d", number))
puts("PASS");
else
return (1);
fputs("pdfioContentTextEnd(): ", stdout);
if (pdfioContentTextEnd(st))
puts("PASS");
else
return (1);
fputs("pdfioContentTextBegin(): ", stdout);
if (pdfioContentTextBegin(st))
puts("PASS");
else
return (1);
fputs("pdfioContentSetTextFont(\"F1\", 18.0): ", stdout);
if (pdfioContentSetTextFont(st, "F1", 18.0))
puts("PASS");
else
return (1);
fputs("pdfioContentTextMoveTo(82, 360): ", stdout);
if (pdfioContentTextMoveTo(st, 82, 360))
puts("PASS");
else
return (1);
fputs("pdfioContentTextShow(\"AdobeRGB\"): ", stdout);
if (pdfioContentTextShow(st, "AdobeRGB"))
puts("PASS");
else
return (1);
fputs("pdfioContentTextMoveTo(234, 0): ", stdout);
if (pdfioContentTextMoveTo(st, 234, 0))
puts("PASS");
else
return (1);
fputs("pdfioContentTextShow(\"DisplayP3\"): ", stdout);
if (pdfioContentTextShow(st, "DisplayP3"))
puts("PASS");
else
return (1);
fputs("pdfioContentTextMoveTo(-234, 252): ", stdout);
if (pdfioContentTextMoveTo(st, -234, 252))
puts("PASS");
else
return (1);
fputs("pdfioContentTextShow(\"sRGB\"): ", stdout);
if (pdfioContentTextShow(st, "sRGB"))
puts("PASS");
else
return (1);
fputs("pdfioContentTextMoveTo(234, 0): ", stdout);
if (pdfioContentTextMoveTo(st, 234, 0))
puts("PASS");
else
return (1);
fputs("pdfioContentTextShow(\"DeviceCMYK\"): ", stdout);
if (pdfioContentTextShow(st, "DeviceCMYK"))
puts("PASS");
else
return (1);
fputs("pdfioContentTextEnd(): ", stdout);
if (pdfioContentTextEnd(st))
puts("PASS");
else
return (1);
fputs("pdfioContentSave(): ", stdout);
if (pdfioContentSave(st))
puts("PASS");
@ -538,8 +655,8 @@ write_color_test(pdfio_file_t *pdf, // I - PDF file
else
return (1);
fputs("pdfioContentMatrixTranslate(82, 180): ", stdout);
if (pdfioContentMatrixTranslate(st, 82, 180))
fputs("pdfioContentMatrixTranslate(82, 162): ", stdout);
if (pdfioContentMatrixTranslate(st, 82, 162))
puts("PASS");
else
return (1);
@ -565,8 +682,8 @@ write_color_test(pdfio_file_t *pdf, // I - PDF file
else
return (1);
fputs("pdfioContentMatrixTranslate(316, 180): ", stdout);
if (pdfioContentMatrixTranslate(st, 316, 180))
fputs("pdfioContentMatrixTranslate(316, 162): ", stdout);
if (pdfioContentMatrixTranslate(st, 316, 162))
puts("PASS");
else
return (1);
@ -645,6 +762,7 @@ write_color_test(pdfio_file_t *pdf, // I - PDF file
static int // O - 1 on failure, 0 on success
write_page(pdfio_file_t *pdf, // I - PDF file
int number, // I - Page number
pdfio_obj_t *font, // I - Text font
pdfio_obj_t *image) // I - Image to draw
{
// TODO: Add font object support...
@ -658,6 +776,8 @@ write_page(pdfio_file_t *pdf, // I - PDF file
ty; // Y offset
(void)font;
fputs("pdfioDictCreate: ", stdout);
if ((dict = pdfioDictCreate(pdf)) != NULL)
puts("PASS");
@ -670,6 +790,12 @@ write_page(pdfio_file_t *pdf, // I - PDF file
else
return (1);
fputs("pdfioPageDictAddFont(F1): ", stdout);
if (pdfioPageDictAddFont(dict, "F1", font))
puts("PASS");
else
return (1);
printf("pdfioFileCreatePage(%d): ", number);
if ((st = pdfioFileCreatePage(pdf, dict)) != NULL)
@ -680,7 +806,43 @@ write_page(pdfio_file_t *pdf, // I - PDF file
fputs("pdfioStreamPuts(...): ", stdout);
if (pdfioStreamPuts(st,
"1 0 0 RG 0 g 5 w\n"
"18 18 559 760 re 72 72 451 648 re B*\n"))
"54 54 487 688 re 90 90 415 612 re B*\n"))
puts("PASS");
else
return (1);
fputs("pdfioContentSetStrokeColorDeviceGray(0.0): ", stdout);
if (pdfioContentSetStrokeColorDeviceGray(st, 0.0))
puts("PASS");
else
return (1);
fputs("pdfioContentTextBegin(): ", stdout);
if (pdfioContentTextBegin(st))
puts("PASS");
else
return (1);
fputs("pdfioContentSetTextFont(\"F1\", 12.0): ", stdout);
if (pdfioContentSetTextFont(st, "F1", 12.0))
puts("PASS");
else
return (1);
fputs("pdfioContentTextMoveTo(550.0, 36.0): ", stdout);
if (pdfioContentTextMoveTo(st, 550.0, 36.0))
puts("PASS");
else
return (1);
printf("pdfioContentTextShowf(\"%d\"): ", number);
if (pdfioContentTextShowf(st, "%d", number))
puts("PASS");
else
return (1);
fputs("pdfioContentTextEnd(): ", stdout);
if (pdfioContentTextEnd(st))
puts("PASS");
else
return (1);