📄 pdf_font.c
字号:
#include "fitz.h"#include "mupdf.h"#define noHINT#include <ft2build.h>#include FT_FREETYPE_H#include FT_XFREE86_Hstatic char *basefontnames[14][7] ={ { "Courier", "CourierNew", "CourierNewPSMT", 0 }, { "Courier-Bold", "CourierNew,Bold", "Courier,Bold", "CourierNewPS-BoldMT", "CourierNew-Bold", 0 }, { "Courier-Oblique", "CourierNew,Italic", "Courier,Italic", "CourierNewPS-ItalicMT", "CourierNew-Italic", 0 }, { "Courier-BoldOblique", "CourierNew,BoldItalic", "Courier,BoldItalic", "CourierNewPS-BoldItalicMT", "CourierNew-BoldItalic", 0 }, { "Helvetica", "ArialMT", "Arial", 0 }, { "Helvetica-Bold", "Arial-BoldMT", "Arial,Bold", "Arial-Bold", "Helvetica,Bold", 0 }, { "Helvetica-Oblique", "Arial-ItalicMT", "Arial,Italic", "Arial-Italic", "Helvetica,Italic", "Helvetica-Italic", 0 }, { "Helvetica-BoldOblique", "Arial-BoldItalicMT", "Arial,BoldItalic", "Arial-BoldItalic", "Helvetica,BoldItalic", "Helvetica-BoldItalic", 0 }, { "Times-Roman", "TimesNewRomanPSMT", "TimesNewRoman", "TimesNewRomanPS", 0 }, { "Times-Bold", "TimesNewRomanPS-BoldMT", "TimesNewRoman,Bold", "TimesNewRomanPS-Bold", "TimesNewRoman-Bold", 0 }, { "Times-Italic", "TimesNewRomanPS-ItalicMT", "TimesNewRoman,Italic", "TimesNewRomanPS-Italic", "TimesNewRoman-Italic", 0 }, { "Times-BoldItalic", "TimesNewRomanPS-BoldItalicMT", "TimesNewRoman,BoldItalic", "TimesNewRomanPS-BoldItalic", "TimesNewRoman-BoldItalic", 0 }, { "Symbol", 0 }, { "ZapfDingbats", 0 }};/* * FreeType and Rendering glue */enum { UNKNOWN, TYPE1, TRUETYPE, CID };#undef __FTERRORS_H__#define FT_ERRORDEF(e, v, s) { (e), (s) },#define FT_ERROR_START_LIST#define FT_ERROR_END_LIST { 0, NULL }struct ft_error{ int err; char *str;};const struct ft_error ft_errors[] ={#include FT_ERRORS_H};char *ft_errstr(int err){ const struct ft_error *e; for (e = ft_errors; e->str != NULL; e++) if (e->err == err) return e->str; return "Unknown error";}static int ftkind(FT_Face face){ const char *kind = FT_Get_X11_Font_Format(face); pdf_logfont("ft font format %s\n", kind); if (!strcmp(kind, "TrueType")) return TRUETYPE; if (!strcmp(kind, "Type 1")) return TYPE1; if (!strcmp(kind, "CFF")) return TYPE1; if (!strcmp(kind, "CID Type 1")) return TYPE1; return UNKNOWN;}static int ftcharindex(FT_Face face, int cid){ int gid = FT_Get_Char_Index(face, cid); if (gid == 0) gid = FT_Get_Char_Index(face, 0xf000 + cid); return gid;}static inline int ftcidtogid(pdf_font *font, int cid){ if (font->tottfcmap) { cid = pdf_lookupcmap(font->tottfcmap, cid); return ftcharindex(font->ftface, cid); } if (font->cidtogid) return font->cidtogid[cid]; return cid;}static int ftwidth(pdf_font *font, int cid){ int e; cid = ftcidtogid(font, cid); e = FT_Load_Glyph(font->ftface, cid, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); if (e) return 0; return ((FT_Face)font->ftface)->glyph->advance.x;}static fz_error *ftrender(fz_glyph *glyph, fz_font *fzfont, int cid, fz_matrix trm){ pdf_font *font = (pdf_font*)fzfont; FT_Face face = font->ftface; FT_Matrix m; FT_Vector v; FT_Error fterr; float scale; int gid; int x, y; int hint = font->hint; gid = ftcidtogid(font, cid); if (font->substitute && fzfont->wmode == 0) { fz_hmtx subw; int realw; FT_Set_Char_Size(face, 1000, 1000, 72, 72); fterr = FT_Load_Glyph(font->ftface, gid, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); if (fterr) return fz_throw("freetype failed to load glyph: %s", ft_errstr(fterr)); realw = ((FT_Face)font->ftface)->glyph->advance.x; subw = fz_gethmtx(fzfont, cid); if (realw) scale = (float) subw.w / realw; else scale = 1.0; trm = fz_concat(fz_scale(scale, 1.0), trm); } glyph->w = 0; glyph->h = 0; glyph->x = 0; glyph->y = 0; glyph->samples = nil; /* freetype mutilates complex glyphs if they are loaded * with FT_Set_Char_Size 1.0. it rounds the coordinates * before applying transformation. to get more precision in * freetype, we shift part of the scale in the matrix * into FT_Set_Char_Size instead */#ifdef HINT hint = 1;#endif if (hint) { scale = fz_matrixexpansion(trm); m.xx = trm.a * 65536 / scale; m.yx = trm.b * 65536 / scale; m.xy = trm.c * 65536 / scale; m.yy = trm.d * 65536 / scale; v.x = 0; v.y = 0; FT_Set_Char_Size(face, 64 * scale, 64 * scale, 72, 72); FT_Set_Transform(face, &m, &v); fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP); if (fterr) fz_warn("freetype load glyph: %s", ft_errstr(fterr)); } else { m.xx = trm.a * 64; /* should be 65536 */ m.yx = trm.b * 64; m.xy = trm.c * 64; m.yy = trm.d * 64; v.x = trm.e * 64; v.y = trm.f * 64; FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ FT_Set_Transform(face, &m, &v); fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); if (fterr) fz_warn("freetype load glyph: %s", ft_errstr(fterr)); } fterr = FT_Render_Glyph(face->glyph, ft_render_mode_normal); if (fterr) fz_warn("freetype render glyph: %s", ft_errstr(fterr)); glyph->w = face->glyph->bitmap.width; glyph->h = face->glyph->bitmap.rows; glyph->x = face->glyph->bitmap_left; glyph->y = face->glyph->bitmap_top - glyph->h; glyph->samples = face->glyph->bitmap.buffer; for (y = 0; y < glyph->h / 2; y++) { for (x = 0; x < glyph->w; x++) { unsigned char a = glyph->samples[y * glyph->w + x ]; unsigned char b = glyph->samples[(glyph->h - y - 1) * glyph->w + x]; glyph->samples[y * glyph->w + x ] = b; glyph->samples[(glyph->h - y - 1) * glyph->w + x] = a; } } return fz_okay;}/* * Basic encoding tables */static char *cleanfontname(char *fontname){ int i, k; for (i = 0; i < 14; i++) for (k = 0; basefontnames[i][k]; k++) if (!strcmp(basefontnames[i][k], fontname)) return basefontnames[i][0]; return fontname;}static int mrecode(char *name){ int i; for (i = 0; i < 256; i++) if (pdf_macroman[i] && !strcmp(name, pdf_macroman[i])) return i; return -1;}/* * Create and destroy */static void ftdropfont(fz_font *font){ pdf_font *pfont = (pdf_font*)font; if (pfont->encoding) pdf_dropcmap(pfont->encoding); if (pfont->tottfcmap) pdf_dropcmap(pfont->tottfcmap); if (pfont->tounicode) pdf_dropcmap(pfont->tounicode); fz_free(pfont->cidtogid); fz_free(pfont->cidtoucs); if (pfont->ftface) FT_Done_Face((FT_Face)pfont->ftface); if (pfont->fontdata) fz_dropbuffer(pfont->fontdata);}/* List of fonts that don't render properly without hinting. This list comes freetype */static const char* const force_hinting[] ={ "DFKaiSho-SB", /* dfkaisb.ttf */ "DFKai-SB", /* kaiu.ttf */ "HuaTianSongTi?", /* htst3.ttf */ "MingLiU", /* mingliu.ttf & mingliu.ttc */ "PMingLiU", /* mingliu.ttc */ "MingLi43", /* mingli.ttf */ NULL};pdf_font *pdf_newfont(char *name){ pdf_font *font; int i; font = fz_malloc(sizeof (pdf_font)); if (!font) return nil; fz_initfont((fz_font*)font, name); font->super.render = ftrender; font->super.drop = (void(*)(fz_font*)) ftdropfont; font->ftface = nil; font->substitute = 0; font->flags = 0; font->italicangle = 0; font->ascent = 0; font->descent = 0; font->capheight = 0; font->xheight = 0; font->missingwidth = 0; font->encoding = nil; font->tottfcmap = 0; font->ncidtogid = 0; font->cidtogid = nil; font->tounicode = nil; font->ncidtoucs = 0; font->cidtoucs = nil; font->filename = nil; font->fontdata = nil; for (i = 0; i < 256; i++) font->charprocs[i] = nil; font->hint = 0; for (i = 0; force_hinting[i]; i++) { char *pos = strstr(name, force_hinting[i]); if (pos && (pos == name || pos[-1] == '+')) { font->hint = 1; break; } } return font;}/* * Simple fonts (Type1 and TrueType) */static fz_error *loadsimplefont(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref){ fz_error *error; fz_obj *descriptor = nil; fz_obj *encoding = nil; fz_obj *widths = nil; fz_obj *basefontobj = nil; unsigned short *etable = nil; pdf_font *font; fz_irect bbox; FT_Face face; FT_CharMap cmap; int kind; int symbolic; char *basefont; char *fontname; char *estrings[256]; char ebuffer[256][32]; int i, k, n; int fterr; basefontobj = fz_dictgets(dict, "BaseFont"); error = pdf_resolve(&basefontobj, xref); if (error) return fz_rethrow(error, "cannot load simple font"); basefont = fz_toname(basefontobj); fontname = cleanfontname(basefont); /* * Load font file */ font = pdf_newfont(fontname); if (!font) return fz_outofmem; pdf_logfont("load simple font (%d %d R) ptr=%p {\n", fz_tonum(ref), fz_togen(ref), font); pdf_logfont("basefont0 %s\n", basefont); pdf_logfont("basefont1 %s\n", fontname); descriptor = fz_dictgets(dict, "FontDescriptor"); if (descriptor && basefont == fontname) error = pdf_loadfontdescriptor(font, xref, descriptor, nil); else error = pdf_loadbuiltinfont(font, fontname); if (error) goto cleanup; face = font->ftface; kind = ftkind(face); pdf_logfont("ft name '%s' '%s'\n", face->family_name, face->style_name); bbox.x0 = (face->bbox.xMin * 1000) / face->units_per_EM; bbox.y0 = (face->bbox.yMin * 1000) / face->units_per_EM; bbox.x1 = (face->bbox.xMax * 1000) / face->units_per_EM; bbox.y1 = (face->bbox.yMax * 1000) / face->units_per_EM; pdf_logfont("ft bbox [%d %d %d %d]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1); if (bbox.x0 == bbox.x1) fz_setfontbbox((fz_font*)font, -1000, -1000, 2000, 2000); else fz_setfontbbox((fz_font*)font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* * Encoding */ symbolic = font->flags & 4; if (face->num_charmaps > 0) cmap = face->charmaps[0]; else cmap = nil; for (i = 0; i < face->num_charmaps; i++) { FT_CharMap test = face->charmaps[i]; if (kind == TYPE1) { if (test->platform_id == 7) cmap = test; } if (kind == TRUETYPE) { if (test->platform_id == 1 && test->encoding_id == 0) cmap = test; if (test->platform_id == 3 && test->encoding_id == 1) cmap = test; } } if (cmap) { fterr = FT_Set_Charmap(face, cmap); if (fterr) { error = fz_throw("freetype could not set cmap: %s", ft_errstr(fterr)); goto cleanup; } } else fz_warn("freetype could not find any cmaps"); etable = fz_malloc(sizeof(unsigned short) * 256); if (!etable) goto cleanup; for (i = 0; i < 256; i++) { estrings[i] = nil; etable[i] = 0; } encoding = fz_dictgets(dict, "Encoding"); if (encoding && !(kind == TRUETYPE && symbolic)) { error = pdf_resolve(&encoding, xref); if (error) goto cleanup; if (fz_isname(encoding)) pdf_loadencoding(estrings, fz_toname(encoding)); if (fz_isdict(encoding)) { fz_obj *base, *diff, *item; base = fz_dictgets(encoding, "BaseEncoding"); if (fz_isname(base)) pdf_loadencoding(estrings, fz_toname(base)); diff = fz_dictgets(encoding, "Differences"); if (fz_isarray(diff)) { n = fz_arraylen(diff); k = 0; for (i = 0; i < n; i++) { item = fz_arrayget(diff, i); if (fz_isint(item)) k = fz_toint(item); if (fz_isname(item)) estrings[k++] = fz_toname(item); if (k < 0) k = 0; if (k > 255) k = 255; } } } if (kind == TYPE1) { pdf_logfont("encode type1/cff by strings\n"); for (i = 0; i < 256; i++) if (estrings[i]) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ftcharindex(face, i); } if (kind == TRUETYPE) { /* Unicode cmap */ if (face->charmap && face->charmap->platform_id == 3) { pdf_logfont("encode truetype via unicode\n"); for (i = 0; i < 256; i++) if (estrings[i]) { int aglbuf[256]; int aglnum; aglnum = pdf_lookupagl(estrings[i], aglbuf, nelem(aglbuf)); if (aglnum != 1) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ftcharindex(face, aglbuf[0]); } else etable[i] = ftcharindex(face, i); } /* MacRoman cmap */ else if (face->charmap && face->charmap->platform_id == 1) { pdf_logfont("encode truetype via macroman\n"); for (i = 0; i < 256; i++) if (estrings[i]) { k = mrecode(estrings[i]); if (k <= 0) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ftcharindex(face, k); } else etable[i] = ftcharindex(face, i); } /* Symbolic cmap */ else { pdf_logfont("encode truetype symbolic\n"); for (i = 0; i < 256; i++) { etable[i] = ftcharindex(face, i); if (etable[i]) FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32); else FT_Get_Glyph_Name(face, i, ebuffer[i], 32); } /* map encoding to gid via glyph names */ for (i = 0; i < 256; i++) { char *s = estrings[i]; if (!etable[i] && s)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -