From dde3b9897b613b7321a506ae7b41a900080af747 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 8 Feb 2007 21:50:00 +0000 Subject: [PATCH] Support for embedding TrueType fonts in PDF output. The code isn't the most beautiful I've ever written, and xpdf turns out not to support the encoding mechanism I've chosen, but it works in GhostScript so I'm not too unhappy for now. git-svn-id: svn://svn.tartarus.org/sgt/halibut@7259 cda61777-01e9-0310-a592-d414129be87e --- bk_pdf.c | 156 ++++++++++++++++++++++++++++++++++++++------------------------ in_sfnt.c | 46 ++++++++++++++++++ paper.h | 10 +++- 3 files changed, 150 insertions(+), 62 deletions(-) diff --git a/bk_pdf.c b/bk_pdf.c index 74944f0..d75244d 100644 --- a/bk_pdf.c +++ b/bk_pdf.c @@ -14,9 +14,6 @@ paragraph *pdf_config_filename(char *filename) return cmdline_cfg_simple("pdf-filename", filename, NULL); } -typedef struct object_Tag object; -typedef struct objlist_Tag objlist; - struct object_Tag { objlist *list; object *next; @@ -31,10 +28,6 @@ struct objlist_Tag { object *head, *tail; }; -static object *new_object(objlist *list); -static void objtext(object *o, char const *text); -static void objstream(object *o, char const *text); -static void objstream_len(object *o, char const *text, size_t len); static void pdf_string(void (*add)(object *, char const *), object *, char const *); static void pdf_string_len(void (*add)(object *, char const *), @@ -137,8 +130,11 @@ void pdf_backend(paragraph *sourceform, keywordlist *keywords, objtext(resources, "<<\n/ProcSet [/PDF/Text]\n/Font <<\n"); for (fe = doc->fonts->head; fe; fe = fe->next) { char fname[40]; + char buf[80]; int i, prev; - object *font; + object *font, *fontdesc; + int flags; + font_info const *fi = fe->font->info; sprintf(fname, "f%d", font_index++); fe->name = dupstr(fname); @@ -151,26 +147,13 @@ void pdf_backend(paragraph *sourceform, keywordlist *keywords, objref(resources, font); objtext(resources, "\n"); - objtext(font, "<<\n/Type /Font\n/Subtype /Type1\n/Name /"); - objtext(font, fe->name); - objtext(font, "\n/BaseFont /"); - objtext(font, fe->font->info->name); - objtext(font, "\n/Encoding <<\n/Type /Encoding\n/Differences ["); - - for (i = 0; i < 256; i++) { - char buf[20]; - if (fe->vector[i] == NOGLYPH) - continue; - if (i != prev + 1) { - sprintf(buf, "\n%d", i); - objtext(font, buf); - } - objtext(font, i % 8 ? "/" : "\n/"); - objtext(font, glyph_extern(fe->vector[i])); - prev = i; - } - objtext(font, "\n]\n>>\n"); + /* + * Construct those parts of the font descriptor that don't dependd + * on the file format. + */ + if (!is_std_font(fe->font->info->name)) { + fontdesc = new_object(&olist); #define FF_FIXEDPITCH 0x00000001 #define FF_SERIF 0x00000002 @@ -182,36 +165,6 @@ void pdf_backend(paragraph *sourceform, keywordlist *keywords, #define FF_SMALLCAP 0x00020000 #define FF_FORCEBOLD 0x00040000 - if (!is_std_font(fe->font->info->name)){ - object *widths = new_object(&olist); - object *fontdesc = new_object(&olist); - int firstchar = -1, lastchar = -1; - char buf[80]; - font_info const *fi = fe->font->info; - int flags; - for (i = 0; i < 256; i++) - if (fe->vector[i] != NOGLYPH) { - if (firstchar < 0) firstchar = i; - lastchar = i; - } - sprintf(buf, "/FirstChar %d\n/LastChar %d\n/Widths ", - firstchar, lastchar); - objtext(font, buf); - objref(font, widths); - objtext(font, "\n"); - objtext(widths, "[\n"); - for (i = firstchar; i <= lastchar; i++) { - double width; - if (fe->vector[i] == NOGLYPH) - width = 0.0; - else - width = find_width(fe->font, fe->vector[i]); - sprintf(buf, "%g\n", 1000.0 * width / FUNITS_PER_PT); - objtext(widths, buf); - } - objtext(widths, "]\n"); - objtext(font, "/FontDescriptor "); - objref(font, fontdesc); objtext(fontdesc, "<<\n/Type /FontDescriptor\n/Name /"); objtext(fontdesc, fi->name); flags = 0; @@ -236,6 +189,76 @@ void pdf_backend(paragraph *sourceform, keywordlist *keywords, objtext(fontdesc, buf); sprintf(buf, "/StemV %g\n", fi->stemv); objtext(fontdesc, buf); + } + + objtext(font, "<<\n/Type /Font\n/BaseFont /"); + objtext(font, fe->font->info->name); + if (fe->font->info->filetype == TRUETYPE) { + object *cidfont = new_object(&olist); + object *cmap = new_object(&olist); + objtext(font, "/Subtype/Type0\n/Encoding "); + sfnt_cmap(fe, cmap); + objref(font, cmap); + objtext(font, "\n/DescendantFonts["); + objref(font, cidfont); + objtext(font, "]\n"); + objtext(cidfont, "<<\n/Type/Font\n/Subtype/CIDFontType2\n" + "/BaseFont/"); + objtext(cidfont, fe->font->info->name); + objtext(cidfont, "\n/CIDSystemInfo<>\n"); + objtext(cidfont, "/FontDescriptor "); + objref(cidfont, fontdesc); + objtext(cidfont, ">>\n"); + } else { + objtext(font, "/Subtype /Type1\n"); + objtext(font, "\n/Encoding <<\n/Type /Encoding\n/Differences ["); + + for (i = 0; i < 256; i++) { + char buf[20]; + if (fe->vector[i] == NOGLYPH) + continue; + if (i != prev + 1) { + sprintf(buf, "\n%d", i); + objtext(font, buf); + } + objtext(font, i % 8 ? "/" : "\n/"); + objtext(font, glyph_extern(fe->vector[i])); + prev = i; + } + + objtext(font, "\n]\n>>\n"); + if (!is_std_font(fe->font->info->name)){ + object *widths = new_object(&olist); + int firstchar = -1, lastchar = -1; + for (i = 0; i < 256; i++) + if (fe->vector[i] != NOGLYPH) { + if (firstchar < 0) firstchar = i; + lastchar = i; + } + sprintf(buf, "/FirstChar %d\n/LastChar %d\n/Widths ", + firstchar, lastchar); + objtext(font, buf); + objref(font, widths); + objtext(font, "\n"); + objtext(widths, "[\n"); + for (i = firstchar; i <= lastchar; i++) { + double width; + if (fe->vector[i] == NOGLYPH) + width = 0.0; + else + width = find_width(fe->font, fe->vector[i]); + sprintf(buf, "%g\n", 1000.0 * width / FUNITS_PER_PT); + objtext(widths, buf); + } + objtext(widths, "]\n"); + objtext(font, "/FontDescriptor "); + objref(font, fontdesc); + } + + } + + if (!is_std_font(fe->font->info->name)) { if (fi->fontfile && fi->filetype == TYPE1) { object *fontfile = new_object(&olist); size_t len; @@ -254,6 +277,17 @@ void pdf_backend(paragraph *sourceform, keywordlist *keywords, objtext(fontfile, "/Length3 0\n"); objtext(fontdesc, "/FontFile "); objref(fontdesc, fontfile); + } else if (fi->fontfile && fi->filetype == TRUETYPE) { + object *fontfile = new_object(&olist); + size_t len; + char *ffbuf; + + sfnt_data((font_info *)fi, &ffbuf, &len); + objstream_len(fontfile, ffbuf, len); + sprintf(buf, "<<\n/Length1 %lu\n", (unsigned long)len); + objtext(fontfile, buf); + objtext(fontdesc, "/FontFile2 "); + objref(fontdesc, fontfile); } objtext(fontdesc, "\n>>\n"); } @@ -581,7 +615,7 @@ void pdf_backend(paragraph *sourceform, keywordlist *keywords, sfree(filename); } -static object *new_object(objlist *list) +object *new_object(objlist *list) { object *obj = snew(object); @@ -607,17 +641,17 @@ static object *new_object(objlist *list) return obj; } -static void objtext(object *o, char const *text) +void objtext(object *o, char const *text) { rdaddsc(&o->main, text); } -static void objstream_len(object *o, char const *text, size_t len) +void objstream_len(object *o, char const *text, size_t len) { rdaddsn(&o->stream, text, len); } -static void objstream(object *o, char const *text) +void objstream(object *o, char const *text) { rdaddsc(&o->stream, text); } diff --git a/in_sfnt.c b/in_sfnt.c index fe16941..9e21bf2 100644 --- a/in_sfnt.c +++ b/in_sfnt.c @@ -802,3 +802,49 @@ void sfnt_writeps(font_info const *fi, FILE *ofp) { sfree(breaks); fprintf(ofp, "end /%s exch definefont\n", fi->name); } + +void sfnt_cmap(font_encoding *fe, object *cmap) { + unsigned i; + + objtext(cmap, "<name); + objtext(cmap, "\n/CIDSystemInfo<>\n"); + objstream(cmap, "%!PS-Adobe-3.0 Resource-CMap\n" + "%%DocumentNeededResources: procset CIDInit\n" + "%%IncludeResource: procset CIDInit\n" + "%%BeginResource: CMap "); + objstream(cmap, fe->name); + objstream(cmap, "\n%%Title ("); + objstream(cmap, fe->name); + objstream(cmap, " Adobe Identity 0)\n%%Version: 1\n%%EndComments\n"); + objstream(cmap, "/CIDInit/ProcSet findresource begin\n"); + objstream(cmap, "12 dict begin begincmap\n"); + objstream(cmap, "/CIDSystemInfo 3 dict dup begin\n" + "/Registry(Adobe)def/Ordering(Identity)def/Supplement 0 def " + "end def\n"); + objstream(cmap, "/CMapName/"); + objstream(cmap, fe->name); + objstream(cmap, " def/CMapType 0 def/WMode 0 def\n"); + objstream(cmap, "1 begincodespacerange<00>endcodespacerange\n"); + for (i = 0; i < 256; i++) { + char buf[20]; + if (fe->vector[i] == NOGLYPH) + continue; + objstream(cmap, "1 begincidchar"); + sprintf(buf, "<%02X>", i); + objstream(cmap, buf); + sprintf(buf, "%hu", sfnt_glyphtoindex(fe->font->info->fontfile, + fe->vector[i])); + objstream(cmap, buf); + objstream(cmap, " endcidchar\n"); + } + objstream(cmap, "endcmap CMapName currentdict /CMap defineresource pop " + "end end\n%%EndResource\n%%EOF\n"); +} + +void sfnt_data(font_info *fi, char **bufp, size_t *lenp) { + sfnt *sf = fi->fontfile; + *bufp = sf->data; + *lenp = sf->len; +} diff --git a/paper.h b/paper.h index b68fd5f..3f20fc2 100644 --- a/paper.h +++ b/paper.h @@ -393,8 +393,14 @@ const int *ps_std_font_widths(char const *fontname); const kern_pair *ps_std_font_kerns(char const *fontname); /* - * Function from bk_pdf.c borrowed by bk_ps.c + * Functions exported from bk_pdf.c */ +typedef struct object_Tag object; +typedef struct objlist_Tag objlist; +object *new_object(objlist *list); +void objtext(object *o, char const *text); +void objstream(object *o, char const *text); +void objstream_len(object *o, char const *text, size_t len); char *pdf_outline_convert(wchar_t *s, int *len); /* @@ -413,5 +419,7 @@ void pf_writeps(font_info const *fi, FILE *ofp); * Backend functions exported by in_sfnt.c */ void sfnt_writeps(font_info const *fi, FILE *ofp); +void sfnt_cmap(font_encoding *fe, object *); +void sfnt_data(font_info *fi, char **bufp, size_t *lenp); #endif -- 2.11.0