mirror of
https://github.com/michaelrsweet/pdfio.git
synced 2024-12-27 05:48:20 +01:00
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:
parent
d1f199c7ae
commit
bbdf0cdb18
7
Makefile
7
Makefile
@ -47,7 +47,8 @@ LIBOBJS = \
|
|||||||
pdfio-stream.o \
|
pdfio-stream.o \
|
||||||
pdfio-string.o \
|
pdfio-string.o \
|
||||||
pdfio-token.o \
|
pdfio-token.o \
|
||||||
pdfio-value.o
|
pdfio-value.o \
|
||||||
|
ttf.o
|
||||||
OBJS = \
|
OBJS = \
|
||||||
$(LIBOBJS) \
|
$(LIBOBJS) \
|
||||||
testpdfio.o
|
testpdfio.o
|
||||||
@ -133,8 +134,8 @@ testpdfio: testpdfio.o libpdfio.a
|
|||||||
# Dependencies
|
# Dependencies
|
||||||
$(OBJS): pdfio.h Makefile
|
$(OBJS): pdfio.h Makefile
|
||||||
$(LIBOBJS): pdfio-private.h
|
$(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>
|
# Make documentation using Codedoc <https://www.msweet.org/codedoc>
|
||||||
DOCFLAGS = \
|
DOCFLAGS = \
|
||||||
|
122
pdfio-content.c
122
pdfio-content.c
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "pdfio-content.h"
|
#include "pdfio-content.h"
|
||||||
#include "pdfio-private.h"
|
#include "pdfio-private.h"
|
||||||
|
#include "ttf.h"
|
||||||
#include <math.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_jpeg(pdfio_dict_t *dict, int fd);
|
||||||
static pdfio_obj_t *copy_png(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 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);
|
static bool write_string(pdfio_stream_t *st, const char *s, bool *newline);
|
||||||
|
|
||||||
@ -1159,9 +1161,19 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
const char *filename, // I - Filename
|
const char *filename, // I - Filename
|
||||||
bool unicode) // I - Unicode font?
|
bool unicode) // I - Unicode font?
|
||||||
{
|
{
|
||||||
pdfio_dict_t *dict; // ICC profile dictionary
|
ttf_t *font; // TrueType font
|
||||||
pdfio_obj_t *obj; // ICC profile object
|
int ch, // Current character
|
||||||
pdfio_stream_t *st; // ICC profile stream
|
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
|
int fd; // File
|
||||||
unsigned char buffer[16384]; // Read buffer
|
unsigned char buffer[16384]; // Read buffer
|
||||||
ssize_t bytes; // Bytes read
|
ssize_t bytes; // Bytes read
|
||||||
@ -1183,26 +1195,100 @@ pdfioFileCreateFontObjFromFile(
|
|||||||
return (NULL);
|
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...
|
// Create the font object...
|
||||||
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
if ((dict = pdfioDictCreate(pdf)) == NULL)
|
||||||
{
|
{
|
||||||
|
ttfDelete(font);
|
||||||
close(fd);
|
close(fd);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
pdfioDictSetName(dict, "Type", "Font");
|
pdfioDictSetName(dict, "Type", "Font");
|
||||||
pdfioDictSetName(dict, "Subtype", "TrueType");
|
pdfioDictSetName(dict, "Subtype", "TrueType");
|
||||||
pdfioDictSetName(dict, "BaseFont", "Bogus"); // TODO: Fix BaseFont value
|
pdfioDictSetName(dict, "BaseFont", pdfioStringCreate(pdf, ttfGetPostScriptName(font)));
|
||||||
(void)unicode;
|
pdfioDictSetName(dict, "Encoding", "WinAnsiEncoding"); // TODO: Fix encoding for unicode
|
||||||
pdfioDictSetName(dict, "Encoding", "WinAnsiEncoding"); // TODO: Fix encoding
|
|
||||||
pdfioDictSetName(dict, "Filter", "FlateDecode");
|
pdfioDictSetName(dict, "Filter", "FlateDecode");
|
||||||
|
|
||||||
#if 0
|
pdfioDictSetObj(dict, "FontDescriptor", desc_obj);
|
||||||
pdfioDictSetObject(dict, "FontDescriptor", descriptor);
|
pdfioDictSetNumber(dict, "FirstChar", firstch);
|
||||||
pdfioDictSetNumber(dict, "FirstChar", firstchar);
|
pdfioDictSetNumber(dict, "LastChar", lastch);
|
||||||
pdfioDictSetNumber(dict, "LastChar", lastchar);
|
pdfioDictSetObj(dict, "Widths", widths_obj);
|
||||||
pdfioDictSetArray(dict, "Widths", widths);
|
|
||||||
#endif // 0
|
ttfDelete(font);
|
||||||
|
|
||||||
if ((obj = pdfioFileCreateObj(pdf, dict)) == NULL)
|
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.
|
// 'update_png_crc()' - Update the CRC-32 value for a PNG chunk.
|
||||||
//
|
//
|
||||||
|
26
pdfio-file.c
26
pdfio-file.c
@ -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.
|
// 'pdfioFileCreateObj()' - Create a new object in a PDF file.
|
||||||
//
|
//
|
||||||
|
1
pdfio.h
1
pdfio.h
@ -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 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_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;
|
extern pdfio_obj_t *pdfioFileCreateObj(pdfio_file_t *pdf, pdfio_dict_t *dict) PDFIO_PUBLIC;
|
||||||
// TODO: Add number, array, string, etc. versions of pdfioFileCreateObject?
|
// TODO: Add number, array, string, etc. versions of pdfioFileCreateObject?
|
||||||
extern pdfio_stream_t *pdfioFileCreatePage(pdfio_file_t *pdf, pdfio_dict_t *dict) PDFIO_PUBLIC;
|
extern pdfio_stream_t *pdfioFileCreatePage(pdfio_file_t *pdf, pdfio_dict_t *dict) PDFIO_PUBLIC;
|
||||||
|
113
ttf.h
Normal file
113
ttf.h
Normal 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
|
Loading…
Reference in New Issue
Block a user