Add proper TrueType font support (Issue #2)

Still need to implement proper Unicode support (currently only writes WinAnsi
font descriptor and handles UTF-8 for 0-255...)
This commit is contained in:
Michael R Sweet 2021-06-17 10:18:55 -04:00
parent d1f199c7ae
commit bbdf0cdb18
No known key found for this signature in database
GPG Key ID: 999559A027815955
6 changed files with 2140 additions and 15 deletions

View File

@ -47,7 +47,8 @@ LIBOBJS = \
pdfio-stream.o \
pdfio-string.o \
pdfio-token.o \
pdfio-value.o
pdfio-value.o \
ttf.o
OBJS = \
$(LIBOBJS) \
testpdfio.o
@ -133,8 +134,8 @@ testpdfio: testpdfio.o libpdfio.a
# Dependencies
$(OBJS): pdfio.h Makefile
$(LIBOBJS): pdfio-private.h
pdfio-content.o: pdfio-content.h
pdfio-content.o: pdfio-content.h ttf.h
ttf.o: ttf.h
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
DOCFLAGS = \

View File

@ -13,6 +13,7 @@
#include "pdfio-content.h"
#include "pdfio-private.h"
#include "ttf.h"
#include <math.h>
@ -64,6 +65,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 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);
@ -1159,9 +1161,19 @@ pdfioFileCreateFontObjFromFile(
const char *filename, // I - Filename
bool unicode) // I - Unicode font?
{
pdfio_dict_t *dict; // ICC profile dictionary
pdfio_obj_t *obj; // ICC profile object
pdfio_stream_t *st; // ICC profile stream
ttf_t *font; // TrueType font
int ch, // Current character
firstch, // First character
lastch; // Last character
ttf_rect_t bounds; // Font bounds
pdfio_dict_t *dict, // Font dictionary
*desc; // Font descriptor
pdfio_obj_t *obj, // Font object
*desc_obj, // Font descriptor object
*widths_obj; // Font widths object
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
ssize_t bytes; // Bytes read
@ -1183,26 +1195,100 @@ pdfioFileCreateFontObjFromFile(
return (NULL);
}
if ((font = ttfCreate(filename, 0, (ttf_err_cb_t)ttf_error_cb, pdf)) == NULL)
{
close(fd);
return (NULL);
}
// Create the font descriptor dictionary and object...
if ((bbox = pdfioArrayCreate(pdf)) == NULL)
{
ttfDelete(font);
close(fd);
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);
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", "Bogus"); // TODO: Fix BaseFont value
(void)unicode;
pdfioDictSetName(dict, "Encoding", "WinAnsiEncoding"); // TODO: Fix encoding
pdfioDictSetName(dict, "BaseFont", pdfioStringCreate(pdf, ttfGetPostScriptName(font)));
pdfioDictSetName(dict, "Encoding", "WinAnsiEncoding"); // TODO: Fix encoding for unicode
pdfioDictSetName(dict, "Filter", "FlateDecode");
#if 0
pdfioDictSetObject(dict, "FontDescriptor", descriptor);
pdfioDictSetNumber(dict, "FirstChar", firstchar);
pdfioDictSetNumber(dict, "LastChar", lastchar);
pdfioDictSetArray(dict, "Widths", widths);
#endif // 0
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)
{
@ -2104,6 +2190,18 @@ copy_png(pdfio_dict_t *dict, // I - Dictionary
}
//
// 'ttf_error_cb()' - Relay a message from the TTF functions.
//
static void
ttf_error_cb(pdfio_file_t *pdf, // I - PDF file
const char *message) // I - Error message
{
(pdf->error_cb)(pdf, message, pdf->error_data);
}
//
// 'update_png_crc()' - Update the CRC-32 value for a PNG chunk.
//

View File

@ -273,6 +273,32 @@ pdfioFileCreate(
}
//
// 'pdfioFileCreateArrayObj()' - Create a new object in a PDF file containing an array.
//
// This function creates a new object with an array value in a PDF file.
// You must call @link pdfioObjClose@ to write the object to the file.
//
pdfio_obj_t * // O - New object
pdfioFileCreateArrayObj(
pdfio_file_t *pdf, // I - PDF file
pdfio_array_t *array) // I - Object array
{
_pdfio_value_t value; // Object value
// Range check input...
if (!pdf || !array)
return (NULL);
value.type = PDFIO_VALTYPE_ARRAY;
value.value.array = array;
return (_pdfioFileCreateObj(pdf, array->pdf, &value));
}
//
// 'pdfioFileCreateObj()' - Create a new object in a PDF file.
//

View File

@ -146,6 +146,7 @@ extern bool pdfioDictSetStringf(pdfio_dict_t *dict, const char *key, const char
extern bool pdfioFileClose(pdfio_file_t *pdf) PDFIO_PUBLIC;
extern pdfio_file_t *pdfioFileCreate(const char *filename, const char *version, pdfio_rect_t *media_box, pdfio_rect_t *crop_box, pdfio_error_cb_t error_cb, void *error_data) PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileCreateArrayObj(pdfio_file_t *pdf, pdfio_array_t *array) PDFIO_PUBLIC;
extern pdfio_obj_t *pdfioFileCreateObj(pdfio_file_t *pdf, pdfio_dict_t *dict) PDFIO_PUBLIC;
// TODO: Add number, array, string, etc. versions of pdfioFileCreateObject?
extern pdfio_stream_t *pdfioFileCreatePage(pdfio_file_t *pdf, pdfio_dict_t *dict) PDFIO_PUBLIC;

1886
ttf.c Normal file

File diff suppressed because it is too large Load Diff

113
ttf.h Normal file
View File

@ -0,0 +1,113 @@
//
// Header file for TTF library
//
// https://github.com/michaelrsweet/ttf
//
// Copyright © 2018-2021 by Michael R Sweet.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
//
#ifndef TTF_H
# define TTF_H
//
// Include necessary headers...
//
# include <stdbool.h>
# include <sys/types.h>
# ifdef __cplusplus
extern "C" {
# endif //
//
// Types...
//
typedef struct _ttf_s ttf_t; //// Font object
typedef void (*ttf_err_cb_t)(void *data, const char *message);
//// Font error callback
typedef enum ttf_stretch_e //// Font stretch
{
TTF_STRETCH_NORMAL, // normal
TTF_STRETCH_ULTRA_CONDENSED, // ultra-condensed
TTF_STRETCH_EXTRA_CONDENSED, // extra-condensed
TTF_STRETCH_CONDENSED, // condensed
TTF_STRETCH_SEMI_CONDENSED, // semi-condensed
TTF_STRETCH_SEMI_EXPANDED, // semi-expanded
TTF_STRETCH_EXPANDED, // expanded
TTF_STRETCH_EXTRA_EXPANDED, // extra-expanded
TTF_STRETCH_ULTRA_EXPANDED // ultra-expanded
} ttf_stretch_t;
typedef enum ttf_style_e //// Font style
{
TTF_STYLE_NORMAL, // Normal font
TTF_STYLE_ITALIC, // Italic font
TTF_STYLE_OBLIQUE // Oblique (angled) font
} ttf_style_t;
typedef enum ttf_variant_e //// Font variant
{
TTF_VARIANT_NORMAL, // Normal font
TTF_VARIANT_SMALL_CAPS // Font whose lowercase letters are small capitals
} ttf_variant_t;
typedef enum ttf_weight_e //// Font weight
{
TTF_WEIGHT_100 = 100, // Weight 100 (Thin)
TTF_WEIGHT_200 = 200, // Weight 200 (Extra/Ultra-Light)
TTF_WEIGHT_300 = 300, // Weight 300 (Light)
TTF_WEIGHT_400 = 400, // Weight 400 (Normal/Regular)
TTF_WEIGHT_500 = 500, // Weight 500 (Medium)
TTF_WEIGHT_600 = 600, // Weight 600 (Semi/Demi-Bold)
TTF_WEIGHT_700 = 700, // Weight 700 (Bold)
TTF_WEIGHT_800 = 800, // Weight 800 (Extra/Ultra-Bold)
TTF_WEIGHT_900 = 900 // Weight 900 (Black/Heavy)
} ttf_weight_t;
typedef struct ttf_rect_s //// Bounding rectangle
{
float left; // Left offset
float top; // Top offset
float right; // Right offset
float bottom; // Bottom offset
} ttf_rect_t;
//
// Functions...
//
extern ttf_t *ttfCreate(const char *filename, size_t idx, ttf_err_cb_t err_cb, void *err_data);
extern void ttfDelete(ttf_t *font);
extern int ttfGetAscent(ttf_t *font);
extern ttf_rect_t *ttfGetBounds(ttf_t *font, ttf_rect_t *bounds);
extern int ttfGetCapHeight(ttf_t *font);
extern const char *ttfGetCopyright(ttf_t *font);
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 size_t ttfGetNumFonts(ttf_t *font);
extern const char *ttfGetPostScriptName(ttf_t *font);
extern ttf_stretch_t ttfGetStretch(ttf_t *font);
extern ttf_style_t ttfGetStyle(ttf_t *font);
extern const char *ttfGetVersion(ttf_t *font);
extern int ttfGetWidth(ttf_t *font, int ch);
extern ttf_weight_t ttfGetWeight(ttf_t *font);
extern int ttfGetXHeight(ttf_t *font);
extern bool ttfIsFixedPitch(ttf_t *font);
# ifdef __cplusplus
}
# endif // __cplusplus
#endif // !TTF_H