static fz_error loadtype0(pdf_fontdesc **fontdescp, pdf_xref *xref, fz_obj *dict) { fz_error error; fz_obj *dfonts; fz_obj *dfont; fz_obj *subtype; fz_obj *encoding; fz_obj *tounicode; dfonts = fz_dictgets(dict, "DescendantFonts"); if (!dfonts) return fz_throw("cid font is missing descendant fonts"); dfont = fz_arrayget(dfonts, 0); subtype = fz_dictgets(dfont, "Subtype"); encoding = fz_dictgets(dict, "Encoding"); tounicode = fz_dictgets(dict, "ToUnicode"); if (fz_isname(subtype) && !strcmp(fz_toname(subtype), "CIDFontType0")) error = loadcidfont(fontdescp, xref, dfont, encoding, tounicode); else if (fz_isname(subtype) && !strcmp(fz_toname(subtype), "CIDFontType2")) error = loadcidfont(fontdescp, xref, dfont, encoding, tounicode); else error = fz_throw("syntaxerror: unknown cid font type"); if (error) return fz_rethrow(error, "cannot load descendant font (%d %d R)", fz_tonum(dfont), fz_togen(dfont)); return fz_okay; }
static fz_error gatherpsobjs(int page, fz_obj *pageobj, fz_obj *dict) { int i; for (i = 0; i < fz_dictlen(dict); i++) { fz_obj *ref; fz_obj *xobjdict; fz_obj *type; fz_obj *subtype; int k; xobjdict = ref = fz_dictgetval(dict, i); if (!fz_isdict(xobjdict)) return fz_throw("not a xobject dict (%d %d R)", fz_tonum(ref), fz_togen(ref)); type = fz_dictgets(xobjdict, "Subtype"); if (!fz_isname(type)) return fz_throw("not a xobject type (%d %d R)", fz_tonum(ref), fz_togen(ref)); if (strcmp(fz_toname(type), "Form")) continue; subtype = fz_dictgets(xobjdict, "Subtype2"); if (subtype && !fz_isname(subtype)) return fz_throw("not a xobject subtype (%d %d R)", fz_tonum(ref), fz_togen(ref)); if (strcmp(fz_toname(type), "PS") && (strcmp(fz_toname(type), "Form") || strcmp(fz_toname(subtype), "PS"))) continue; for (k = 0; k < psobjs; k++) if (fz_tonum(psobj[k]->ref) == fz_tonum(ref) && fz_togen(psobj[k]->ref) == fz_togen(ref)) break; if (k < psobjs) continue; psobjs++; psobj = fz_realloc(psobj, psobjs * sizeof (struct info *)); if (!psobj) return fz_throw("out of memory"); psobj[psobjs - 1] = fz_malloc(sizeof (struct info)); if (!psobj[psobjs - 1]) return fz_throw("out of memory"); psobj[psobjs - 1]->page = page; psobj[psobjs - 1]->pageobj = pageobj; psobj[psobjs - 1]->ref = ref; } return fz_okay; }
int pdf_isjpximage(fz_obj *dict) { fz_obj *filter; int i; filter = fz_dictgets(dict, "Filter"); if (!strcmp(fz_toname(filter), "JPXDecode")) return 1; for (i = 0; i < fz_arraylen(filter); i++) if (!strcmp(fz_toname(fz_arrayget(filter, i)), "JPXDecode")) return 1; return 0; }
void pdf_loadannots(pdf_comment **cp, pdf_link **lp, pdf_xref *xref, fz_obj *annots) { pdf_comment *comment; pdf_link *link; fz_obj *subtype; fz_obj *obj; int i; comment = nil; link = nil; pdf_logpage("load annotations {\n"); for (i = 0; i < fz_arraylen(annots); i++) { obj = fz_arrayget(annots, i); subtype = fz_dictgets(obj, "Subtype"); if (fz_isname(subtype) && !strcmp(fz_toname(subtype), "Link")) { pdf_link *temp = pdf_loadlink(xref, obj); if (temp) { temp->next = link; link = temp; } } } pdf_logpage("}\n"); *cp = comment; *lp = link; }
fz_error * pdf_loadfont(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref) { fz_error *error; char *subtype; if ((*fontp = pdf_finditem(xref->store, PDF_KFONT, ref))) { fz_keepfont((fz_font*)*fontp); return fz_okay; } subtype = fz_toname(fz_dictgets(dict, "Subtype")); if (!strcmp(subtype, "Type0")) error = loadtype0(fontp, xref, dict, ref); else if (!strcmp(subtype, "Type1") || !strcmp(subtype, "MMType1")) error = loadsimplefont(fontp, xref, dict, ref); else if (!strcmp(subtype, "TrueType")) error = loadsimplefont(fontp, xref, dict, ref); else if (!strcmp(subtype, "Type3")) error = pdf_loadtype3font(fontp, xref, dict, ref); else return fz_throw("cannot recognize font format %s", subtype); if (error) return fz_rethrow(error, "cannot load font"); error = pdf_storeitem(xref->store, PDF_KFONT, ref, *fontp); if (error) return fz_rethrow(error, "cannot store font resource"); return fz_okay; }
fz_error pdf_loadfontdescriptor(pdf_fontdesc *fontdesc, pdf_xref *xref, fz_obj *dict, char *collection) { fz_error error; fz_obj *obj1, *obj2, *obj3, *obj; fz_rect bbox; char *fontname; pdf_logfont("load fontdescriptor {\n"); fontname = fz_toname(fz_dictgets(dict, "FontName")); pdf_logfont("fontname '%s'\n", fontname); fontdesc->flags = fz_toint(fz_dictgets(dict, "Flags")); fontdesc->italicangle = fz_toreal(fz_dictgets(dict, "ItalicAngle")); fontdesc->ascent = fz_toreal(fz_dictgets(dict, "Ascent")); fontdesc->descent = fz_toreal(fz_dictgets(dict, "Descent")); fontdesc->capheight = fz_toreal(fz_dictgets(dict, "CapHeight")); fontdesc->xheight = fz_toreal(fz_dictgets(dict, "XHeight")); fontdesc->missingwidth = fz_toreal(fz_dictgets(dict, "MissingWidth")); bbox = pdf_torect(fz_dictgets(dict, "FontBBox")); pdf_logfont("bbox [%g %g %g %g]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1); pdf_logfont("flags %d\n", fontdesc->flags); obj1 = fz_dictgets(dict, "FontFile"); obj2 = fz_dictgets(dict, "FontFile2"); obj3 = fz_dictgets(dict, "FontFile3"); obj = obj1 ? obj1 : obj2 ? obj2 : obj3; if (getenv("NOFONT")) obj = nil; if (fz_isindirect(obj)) { error = pdf_loadembeddedfont(fontdesc, xref, obj); if (error) { fz_catch(error, "ignored error when loading embedded font, attempting to load system font"); error = pdf_loadsystemfont(fontdesc, fontname, collection); if (error) return fz_rethrow(error, "cannot load font descriptor"); } } else { error = pdf_loadsystemfont(fontdesc, fontname, collection); if (error) return fz_rethrow(error, "cannot load font descriptor"); } pdf_logfont("}\n"); return fz_okay; }
fz_error pdf_loadfont(pdf_fontdesc **fontdescp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict) { fz_error error; char *subtype; fz_obj *dfonts; fz_obj *charprocs; if ((*fontdescp = pdf_finditem(xref->store, pdf_dropfont, dict))) { pdf_keepfont(*fontdescp); return fz_okay; } subtype = fz_toname(fz_dictgets(dict, "Subtype")); dfonts = fz_dictgets(dict, "DescendantFonts"); charprocs = fz_dictgets(dict, "CharProcs"); if (subtype && !strcmp(subtype, "Type0")) error = loadtype0(fontdescp, xref, dict); else if (subtype && !strcmp(subtype, "Type1")) error = loadsimplefont(fontdescp, xref, dict); else if (subtype && !strcmp(subtype, "MMType1")) error = loadsimplefont(fontdescp, xref, dict); else if (subtype && !strcmp(subtype, "TrueType")) error = loadsimplefont(fontdescp, xref, dict); else if (subtype && !strcmp(subtype, "Type3")) error = pdf_loadtype3font(fontdescp, xref, rdb, dict); else if (charprocs) { fz_warn("unknown font format, guessing type3."); error = pdf_loadtype3font(fontdescp, xref, rdb, dict); } else if (dfonts) { fz_warn("unknown font format, guessing type0."); error = loadtype0(fontdescp, xref, dict); } else { fz_warn("unknown font format, guessing type1 or truetype."); error = loadsimplefont(fontdescp, xref, dict); } if (error) return fz_rethrow(error, "cannot load font (%d %d R)", fz_tonum(dict), fz_togen(dict)); /* Save the widths to stretch non-CJK substitute fonts */ if ((*fontdescp)->font->ftsubstitute && !(*fontdescp)->tottfcmap) pdf_makewidthtable(*fontdescp); /* SumatraPDF: this font renders wrong without hinting */ if (strstr((*fontdescp)->font->name, "MingLiU")) (*fontdescp)->font->fthint = 1; pdf_storeitem(xref->store, pdf_keepfont, pdf_dropfont, dict, *fontdescp); return fz_okay; }
fz_error * pdf_loadannots(pdf_comment **cp, pdf_link **lp, pdf_xref *xref, fz_obj *annots) { fz_error *error; pdf_comment *comment; pdf_link *link; fz_obj *subtype; fz_obj *obj; int i; comment = nil; link = nil; pdf_logpage("load annotations {\n"); for (i = 0; i < fz_arraylen(annots); i++) { obj = fz_arrayget(annots, i); error = pdf_resolve(&obj, xref); if (error) goto cleanup; subtype = fz_dictgets(obj, "Subtype"); if (!strcmp(fz_toname(subtype), "Link")) { pdf_link *temp = nil; error = pdf_loadlink(&temp, xref, obj); fz_dropobj(obj); if (error) goto cleanup; if (temp) { temp->next = link; link = temp; } } else { error = loadcomment(&comment, xref, obj); fz_dropobj(obj); if (error) goto cleanup; } } pdf_logpage("}\n"); *cp = comment; *lp = link; return nil; cleanup: pdf_droplink(link); return error; }
static void writeobject(int num, int gen) { fz_error error; fz_obj *obj; fz_obj *type; error = pdf_loadobject(&obj, xref, num, gen); if (error) die(error); /* skip ObjStm and XRef objects */ if (fz_isdict(obj)) { type = fz_dictgets(obj, "Type"); if (fz_isname(type) && !strcmp(fz_toname(type), "ObjStm")) { uselist[num] = 0; fz_dropobj(obj); return; } if (fz_isname(type) && !strcmp(fz_toname(type), "XRef")) { uselist[num] = 0; fz_dropobj(obj); return; } } if (!pdf_isstream(xref, num, gen)) { fprintf(out, "%d %d obj\n", num, gen); fz_fprintobj(out, obj, !doexpand); fprintf(out, "endobj\n\n"); } else { if (doexpand && !pdf_isjpximage(obj)) expandstream(obj, num, gen); else copystream(obj, num, gen); } fz_dropobj(obj); }
fz_error pdf_loadannots(pdf_comment **cp, pdf_link **lp, pdf_xref *xref, fz_obj *annots) { fz_error error; pdf_comment *comment; pdf_link *link; fz_obj *subtype; fz_obj *obj; int i; comment = nil; link = nil; pdf_logpage("load annotations {\n"); for (i = 0; i < fz_arraylen(annots); i++) { obj = fz_arrayget(annots, i); subtype = fz_dictgets(obj, "Subtype"); if (fz_isname(subtype) && !strcmp(fz_toname(subtype), "Link")) { pdf_link *temp = nil; error = pdf_loadlink(&temp, xref, obj); if (error) { if (link) pdf_droplink(link); return fz_rethrow(error, "cannot load annotation link"); } if (temp) { temp->next = link; link = temp; } } else { error = loadcomment(&comment, xref, obj); if (error) { if (link) pdf_droplink(link); return fz_rethrow(error, "cannot load annotation comment"); } } } pdf_logpage("}\n"); *cp = comment; *lp = link; return fz_okay; }
static fz_error * loadtype0(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref) { fz_error *error; fz_obj *dfonts; fz_obj *dfont; fz_obj *subtype; fz_obj *encoding; fz_obj *tounicode; dfonts = fz_dictgets(dict, "DescendantFonts"); error = pdf_resolve(&dfonts, xref); if (error) return fz_rethrow(error, "cannot find DescendantFonts"); dfont = fz_arrayget(dfonts, 0); error = pdf_resolve(&dfont, xref); if (error) { fz_dropobj(dfonts); return fz_rethrow(error, "cannot find descendant font"); } subtype = fz_dictgets(dfont, "Subtype"); encoding = fz_dictgets(dict, "Encoding"); tounicode = fz_dictgets(dict, "ToUnicode"); if (!strcmp(fz_toname(subtype), "CIDFontType0")) error = loadcidfont(fontp, xref, dfont, ref, encoding, tounicode); else if (!strcmp(fz_toname(subtype), "CIDFontType2")) error = loadcidfont(fontp, xref, dfont, ref, encoding, tounicode); else error = fz_throw("syntaxerror: unknown cid font type"); fz_dropobj(dfont); fz_dropobj(dfonts); if (error) return fz_rethrow(error, "cannot load descendant font"); return fz_okay; }
static int pdf_extgstateusesblending(fz_obj *dict) { fz_obj *obj; obj = fz_dictgets(dict, "BM"); if (fz_isname(obj) && strcmp(fz_toname(obj), "Normal")) return 1; return 0; }
fz_error pdf_loadfont(pdf_fontdesc **fontdescp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict) { fz_error error; char *subtype; fz_obj *dfonts; fz_obj *charprocs; if ((*fontdescp = pdf_finditem(xref->store, PDF_KFONT, dict))) { pdf_keepfont(*fontdescp); return fz_okay; } subtype = fz_toname(fz_dictgets(dict, "Subtype")); dfonts = fz_dictgets(dict, "DescendantFonts"); charprocs = fz_dictgets(dict, "CharProcs"); if (subtype && !strcmp(subtype, "Type0")) error = loadtype0(fontdescp, xref, dict); else if (subtype && !strcmp(subtype, "Type1")) error = loadsimplefont(fontdescp, xref, dict); else if (subtype && !strcmp(subtype, "MMType1")) error = loadsimplefont(fontdescp, xref, dict); else if (subtype && !strcmp(subtype, "TrueType")) error = loadsimplefont(fontdescp, xref, dict); else if (subtype && !strcmp(subtype, "Type3")) error = pdf_loadtype3font(fontdescp, xref, rdb, dict); else if (charprocs) { fz_warn("unknown font format, guessing type3."); error = pdf_loadtype3font(fontdescp, xref, rdb, dict); } else if (dfonts) { fz_warn("unknown font format, guessing type0."); error = loadtype0(fontdescp, xref, dict); } else { fz_warn("unknown font format, guessing type1 or truetype."); error = loadsimplefont(fontdescp, xref, dict); } if (error) return fz_rethrow(error, "cannot load font"); error = pdf_storeitem(xref->store, PDF_KFONT, dict, *fontdescp); if (error) return fz_rethrow(error, "cannot store font resource"); return fz_okay; }
fz_error pdf_repairobjstms(pdf_xref *xref) { fz_obj *dict; int i; for (i = 0; i < xref->len; i++) { if (xref->table[i].stmofs) { pdf_loadobject(&dict, xref, i, 0); if (!strcmp(fz_toname(fz_dictgets(dict, "Type")), "ObjStm")) pdf_repairobjstm(xref, i, 0); fz_dropobj(dict); } } return fz_okay; }
fz_error pdf_loadfontdescriptor(pdf_fontdesc *fontdesc, pdf_xref *xref, fz_obj *dict, char *collection, char *basefont) { fz_error error; fz_obj *obj1, *obj2, *obj3, *obj; fz_rect bbox; char *fontname; char *origname; pdf_logfont("load fontdescriptor {\n"); /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1014 */ if (!strchr(basefont, ',') || strchr(basefont, '+')) origname = fz_toname(fz_dictgets(dict, "FontName")); else origname = basefont; fontname = cleanfontname(origname); pdf_logfont("fontname %s -> %s\n", origname, fontname); fontdesc->flags = fz_toint(fz_dictgets(dict, "Flags")); fontdesc->italicangle = fz_toreal(fz_dictgets(dict, "ItalicAngle")); fontdesc->ascent = fz_toreal(fz_dictgets(dict, "Ascent")); fontdesc->descent = fz_toreal(fz_dictgets(dict, "Descent")); fontdesc->capheight = fz_toreal(fz_dictgets(dict, "CapHeight")); fontdesc->xheight = fz_toreal(fz_dictgets(dict, "XHeight")); fontdesc->missingwidth = fz_toreal(fz_dictgets(dict, "MissingWidth")); bbox = pdf_torect(fz_dictgets(dict, "FontBBox")); pdf_logfont("bbox [%g %g %g %g]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1); pdf_logfont("flags %d\n", fontdesc->flags); obj1 = fz_dictgets(dict, "FontFile"); obj2 = fz_dictgets(dict, "FontFile2"); obj3 = fz_dictgets(dict, "FontFile3"); obj = obj1 ? obj1 : obj2 ? obj2 : obj3; if (getenv("NOFONT")) obj = nil; if (fz_isindirect(obj)) { error = pdf_loadembeddedfont(fontdesc, xref, obj); if (error) { fz_catch(error, "ignored error when loading embedded font, attempting to load system font"); if (origname != fontname) error = pdf_loadbuiltinfont(fontdesc, fontname); else error = pdf_loadsystemfont(fontdesc, fontname, collection); if (error) return fz_rethrow(error, "cannot load font descriptor (%d %d R)", fz_tonum(dict), fz_togen(dict)); } } else { if (origname != fontname && 0 /* SumatraPDF: prefer system fonts to the built-in ones */) error = pdf_loadbuiltinfont(fontdesc, fontname); else error = pdf_loadsystemfont(fontdesc, fontname, collection); if (error) return fz_rethrow(error, "cannot load font descriptor (%d %d R)", fz_tonum(dict), fz_togen(dict)); } fz_strlcpy(fontdesc->font->name, fontname, sizeof fontdesc->font->name); pdf_logfont("}\n"); return fz_okay; }
static fz_error loadsimplefont(pdf_fontdesc **fontdescp, pdf_xref *xref, fz_obj *dict) { fz_error error; fz_obj *descriptor; fz_obj *encoding; fz_obj *widths; unsigned short *etable = nil; pdf_fontdesc *fontdesc; fz_bbox 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; basefont = fz_toname(fz_dictgets(dict, "BaseFont")); fontname = cleanfontname(basefont); /* Load font file */ fontdesc = pdf_newfontdesc(); pdf_logfont("load simple font (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), fontdesc); pdf_logfont("basefont %s -> %s\n", basefont, fontname); descriptor = fz_dictgets(dict, "FontDescriptor"); if (descriptor) error = pdf_loadfontdescriptor(fontdesc, xref, descriptor, nil, basefont); else error = pdf_loadbuiltinfont(fontdesc, fontname); if (error) goto cleanup; face = fontdesc->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(fontdesc->font, -1000, -1000, 2000, 2000); else fz_setfontbbox(fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* Encoding */ symbolic = fontdesc->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) fz_warn("freetype could not set cmap: %s", ft_errorstring(fterr)); } else fz_warn("freetype could not find any cmaps"); etable = fz_malloc(sizeof(unsigned short) * 256); for (i = 0; i < 256; i++) { estrings[i] = nil; etable[i] = 0; } encoding = fz_dictgets(dict, "Encoding"); if (encoding) { 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)); else if (!fontdesc->isembedded && !symbolic) pdf_loadencoding(estrings, "StandardEncoding"); /* cf. http://bugs.ghostscript.com/show_bug.cgi?id=690615 and http://code.google.com/p/sumatrapdf/issues/detail?id=687 */ /* try to extract an encoding from the font or synthesize a likely one */ /* note: FT_Get_Name_Index fails for symbolic CFF fonts, so let them be encoded by index */ else if (!fontdesc->encoding && !ftloadt1encoding(face, estrings) && !(symbolic && !strcmp(FT_Get_X11_Font_Format(face), "CFF"))) pdf_loadencoding(estrings, "StandardEncoding"); 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; } } } } /* start with the builtin encoding */ for (i = 0; i < 256; i++) etable[i] = ftcharindex(face, i); /* encode by glyph name where we can */ 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]); if (etable[i] == 0) { int aglcode = pdf_lookupagl(estrings[i]); char **aglnames = pdf_lookupaglnames(aglcode); while (*aglnames) { etable[i] = FT_Get_Name_Index(face, *aglnames); if (etable[i]) break; aglnames++; } } } } } /* encode by glyph name where we can */ if (kind == TRUETYPE) { /* Unicode cmap */ if (!symbolic && face->charmap && face->charmap->platform_id == 3) { pdf_logfont("encode truetype via unicode\n"); for (i = 0; i < 256; i++) { if (estrings[i]) { int aglcode = pdf_lookupagl(estrings[i]); if (!aglcode) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ftcharindex(face, aglcode); } } } /* MacRoman cmap */ else if (!symbolic && 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); } } } /* Symbolic cmap */ else { pdf_logfont("encode truetype symbolic\n"); for (i = 0; i < 256; i++) { if (estrings[i]) { etable[i] = FT_Get_Name_Index(face, estrings[i]); if (etable[i] == 0) etable[i] = ftcharindex(face, i); } } } } /* try to reverse the glyph names from the builtin encoding */ for (i = 0; i < 256; i++) { if (etable[i] && !estrings[i]) { if (FT_HAS_GLYPH_NAMES(face)) { fterr = FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32); if (fterr) fz_warn("freetype get glyph name (gid %d): %s", etable[i], ft_errorstring(fterr)); if (ebuffer[i][0]) estrings[i] = ebuffer[i]; } else { estrings[i] = (char*) pdf_winansi[i]; /* discard const */ } } } /* Prevent encoding Differences from being overwritten by reloading them */ /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=115 */ if (fz_isdict(encoding)) { fz_obj *diff, *item; 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; } } } fontdesc->encoding = pdf_newidentitycmap(0, 1); fontdesc->ncidtogid = 256; fontdesc->cidtogid = etable; error = pdf_loadtounicode(fontdesc, xref, estrings, nil, fz_dictgets(dict, "ToUnicode")); if (error) goto cleanup; /* Widths */ pdf_setdefaulthmtx(fontdesc, fontdesc->missingwidth); widths = fz_dictgets(dict, "Widths"); if (widths) { int first, last; first = fz_toint(fz_dictgets(dict, "FirstChar")); last = fz_toint(fz_dictgets(dict, "LastChar")); if (first < 0 || last > 255 || first > last) first = last = 0; for (i = 0; i < last - first + 1; i++) { int wid = fz_toint(fz_arrayget(widths, i)); pdf_addhmtx(fontdesc, i + first, i + first, wid); } } else { fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72); if (fterr) fz_warn("freetype set character size: %s", ft_errorstring(fterr)); for (i = 0; i < 256; i++) { pdf_addhmtx(fontdesc, i, i, ftwidth(fontdesc, i)); } } pdf_endhmtx(fontdesc); pdf_logfont("}\n"); *fontdescp = fontdesc; return fz_okay; cleanup: if (etable != fontdesc->cidtogid) fz_free(etable); pdf_dropfont(fontdesc); return fz_rethrow(error, "cannot load simple font (%d %d R)", fz_tonum(dict), fz_togen(dict)); }
static fz_error loadcidfont(pdf_fontdesc **fontdescp, pdf_xref *xref, fz_obj *dict, fz_obj *encoding, fz_obj *tounicode) { fz_error error; fz_obj *widths; fz_obj *descriptor; pdf_fontdesc *fontdesc; FT_Face face; fz_bbox bbox; int kind; char collection[256]; char *basefont; int i, k, fterr; fz_obj *obj; int dw; /* Get font name and CID collection */ basefont = fz_toname(fz_dictgets(dict, "BaseFont")); { fz_obj *cidinfo; char tmpstr[64]; int tmplen; cidinfo = fz_dictgets(dict, "CIDSystemInfo"); if (!cidinfo) return fz_throw("cid font is missing info"); obj = fz_dictgets(cidinfo, "Registry"); tmplen = MIN(sizeof tmpstr - 1, fz_tostrlen(obj)); memcpy(tmpstr, fz_tostrbuf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcpy(collection, tmpstr, sizeof collection); fz_strlcat(collection, "-", sizeof collection); obj = fz_dictgets(cidinfo, "Ordering"); tmplen = MIN(sizeof tmpstr - 1, fz_tostrlen(obj)); memcpy(tmpstr, fz_tostrbuf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcat(collection, tmpstr, sizeof collection); } /* Load font file */ fontdesc = pdf_newfontdesc(); pdf_logfont("load cid font (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), fontdesc); pdf_logfont("basefont %s\n", basefont); pdf_logfont("collection %s\n", collection); descriptor = fz_dictgets(dict, "FontDescriptor"); if (descriptor) error = pdf_loadfontdescriptor(fontdesc, xref, descriptor, collection, basefont); else error = fz_throw("syntaxerror: missing font descriptor"); if (error) goto cleanup; face = fontdesc->font->ftface; kind = ftkind(face); 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(fontdesc->font, -1000, -1000, 2000, 2000); else fz_setfontbbox(fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* Encoding */ error = fz_okay; if (fz_isname(encoding)) { pdf_logfont("encoding /%s\n", fz_toname(encoding)); if (!strcmp(fz_toname(encoding), "Identity-H")) fontdesc->encoding = pdf_newidentitycmap(0, 2); else if (!strcmp(fz_toname(encoding), "Identity-V")) fontdesc->encoding = pdf_newidentitycmap(1, 2); else error = pdf_loadsystemcmap(&fontdesc->encoding, fz_toname(encoding)); } else if (fz_isindirect(encoding)) { pdf_logfont("encoding %d %d R\n", fz_tonum(encoding), fz_togen(encoding)); error = pdf_loadembeddedcmap(&fontdesc->encoding, xref, encoding); } else { error = fz_throw("syntaxerror: font missing encoding"); } if (error) goto cleanup; pdf_setfontwmode(fontdesc, pdf_getwmode(fontdesc->encoding)); pdf_logfont("wmode %d\n", pdf_getwmode(fontdesc->encoding)); if (kind == TRUETYPE) { fz_obj *cidtogidmap; cidtogidmap = fz_dictgets(dict, "CIDToGIDMap"); if (fz_isindirect(cidtogidmap)) { fz_buffer *buf; pdf_logfont("cidtogidmap stream\n"); error = pdf_loadstream(&buf, xref, fz_tonum(cidtogidmap), fz_togen(cidtogidmap)); if (error) goto cleanup; fontdesc->ncidtogid = (buf->len) / 2; fontdesc->cidtogid = fz_malloc(fontdesc->ncidtogid * sizeof(unsigned short)); for (i = 0; i < fontdesc->ncidtogid; i++) fontdesc->cidtogid[i] = (buf->data[i * 2] << 8) + buf->data[i * 2 + 1]; fz_dropbuffer(buf); } /* if truetype font is external, cidtogidmap should not be identity */ /* so we map from cid to unicode and then map that through the (3 1) */ /* unicode cmap to get a glyph id */ else if (fontdesc->font->ftsubstitute) { pdf_logfont("emulate ttf cidfont\n"); fterr = FT_Select_Charmap(face, ft_encoding_unicode); if (fterr) { error = fz_throw("fonterror: no unicode cmap when emulating CID font: %s", ft_errorstring(fterr)); goto cleanup; } if (!strcmp(collection, "Adobe-CNS1")) error = pdf_loadsystemcmap(&fontdesc->tottfcmap, "Adobe-CNS1-UCS2"); else if (!strcmp(collection, "Adobe-GB1")) error = pdf_loadsystemcmap(&fontdesc->tottfcmap, "Adobe-GB1-UCS2"); else if (!strcmp(collection, "Adobe-Japan1")) error = pdf_loadsystemcmap(&fontdesc->tottfcmap, "Adobe-Japan1-UCS2"); else if (!strcmp(collection, "Adobe-Japan2")) error = pdf_loadsystemcmap(&fontdesc->tottfcmap, "Adobe-Japan2-UCS2"); else if (!strcmp(collection, "Adobe-Korea1")) error = pdf_loadsystemcmap(&fontdesc->tottfcmap, "Adobe-Korea1-UCS2"); else error = fz_okay; if (error) { error = fz_rethrow(error, "cannot load system cmap %s", collection); goto cleanup; } } } error = pdf_loadtounicode(fontdesc, xref, nil, collection, tounicode); if (error) goto cleanup; /* Horizontal */ dw = 1000; obj = fz_dictgets(dict, "DW"); if (obj) dw = fz_toint(obj); pdf_setdefaulthmtx(fontdesc, dw); widths = fz_dictgets(dict, "W"); if (widths) { int c0, c1, w; for (i = 0; i < fz_arraylen(widths); ) { c0 = fz_toint(fz_arrayget(widths, i)); obj = fz_arrayget(widths, i + 1); if (fz_isarray(obj)) { for (k = 0; k < fz_arraylen(obj); k++) { w = fz_toint(fz_arrayget(obj, k)); pdf_addhmtx(fontdesc, c0 + k, c0 + k, w); } i += 2; } else { c1 = fz_toint(obj); w = fz_toint(fz_arrayget(widths, i + 2)); pdf_addhmtx(fontdesc, c0, c1, w); i += 3; } } } pdf_endhmtx(fontdesc); /* Vertical */ if (pdf_getwmode(fontdesc->encoding) == 1) { int dw2y = 880; int dw2w = -1000; obj = fz_dictgets(dict, "DW2"); if (obj) { dw2y = fz_toint(fz_arrayget(obj, 0)); dw2w = fz_toint(fz_arrayget(obj, 1)); } pdf_setdefaultvmtx(fontdesc, dw2y, dw2w); widths = fz_dictgets(dict, "W2"); if (widths) { int c0, c1, w, x, y; for (i = 0; i < fz_arraylen(widths); ) { c0 = fz_toint(fz_arrayget(widths, i)); obj = fz_arrayget(widths, i + 1); if (fz_isarray(obj)) { for (k = 0; k < fz_arraylen(obj); k += 3) { w = fz_toint(fz_arrayget(obj, k + 0)); x = fz_toint(fz_arrayget(obj, k + 1)); y = fz_toint(fz_arrayget(obj, k + 2)); pdf_addvmtx(fontdesc, c0 + k, c0 + k, x, y, w); } i += 2; } else { c1 = fz_toint(obj); w = fz_toint(fz_arrayget(widths, i + 2)); x = fz_toint(fz_arrayget(widths, i + 3)); y = fz_toint(fz_arrayget(widths, i + 4)); pdf_addvmtx(fontdesc, c0, c1, x, y, w); i += 5; } } } pdf_endvmtx(fontdesc); } pdf_logfont("}\n"); *fontdescp = fontdesc; return fz_okay; cleanup: pdf_dropfont(fontdesc); return fz_rethrow(error, "cannot load cid font (%d %d R)", fz_tonum(dict), fz_togen(dict)); }
static fz_error pdf_loadcolorspaceimp(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj) { if (fz_isname(obj)) { if (!strcmp(fz_toname(obj), "DeviceGray")) *csp = pdf_devicegray; else if (!strcmp(fz_toname(obj), "DeviceRGB")) *csp = pdf_devicergb; else if (!strcmp(fz_toname(obj), "DeviceCMYK")) *csp = pdf_devicecmyk; else if (!strcmp(fz_toname(obj), "G")) *csp = pdf_devicegray; else if (!strcmp(fz_toname(obj), "RGB")) *csp = pdf_devicergb; else if (!strcmp(fz_toname(obj), "CMYK")) *csp = pdf_devicecmyk; else if (!strcmp(fz_toname(obj), "Pattern")) *csp = pdf_devicepattern; else return fz_throw("unknown colorspace: %s", fz_toname(obj)); return fz_okay; } else if (fz_isarray(obj)) { fz_obj *name = fz_arrayget(obj, 0); if (fz_isname(name)) { if (!strcmp(fz_toname(name), "CalCMYK")) *csp = pdf_devicecmyk; #ifdef USECAL else if (!strcmp(fz_toname(name), "CalGray")) *csp = loadcalgray(xref, fz_arrayget(obj, 1)); else if (!strcmp(fz_toname(name), "CalRGB")) *csp = loadcalrgb(xref, fz_arrayget(obj, 1)); else if (!strcmp(fz_toname(name), "Lab")) *csp = loadlab(xref, fz_arrayget(obj, 1)); #else else if (!strcmp(fz_toname(name), "CalGray")) *csp = pdf_devicegray; else if (!strcmp(fz_toname(name), "CalRGB")) *csp = pdf_devicergb; else if (!strcmp(fz_toname(name), "Lab")) *csp = pdf_devicelab; #endif else if (!strcmp(fz_toname(name), "ICCBased")) return loadiccbased(csp, xref, fz_arrayget(obj, 1)); else if (!strcmp(fz_toname(name), "Indexed")) return loadindexed(csp, xref, obj); else if (!strcmp(fz_toname(name), "I")) return loadindexed(csp, xref, obj); else if (!strcmp(fz_toname(name), "Separation")) return loadseparation(csp, xref, obj); else if (!strcmp(fz_toname(name), "DeviceN")) return loadseparation(csp, xref, obj); /* load base colorspace instead */ else if (!strcmp(fz_toname(name), "Pattern")) { fz_error error; obj = fz_arrayget(obj, 1); if (!obj) { *csp = pdf_devicepattern; return fz_okay; } error = pdf_loadcolorspace(csp, xref, obj); if (error) return fz_rethrow(error, "cannot load pattern"); } else if (!strcmp(fz_toname(name), "DeviceGray")) *csp = pdf_devicegray; else if (!strcmp(fz_toname(name), "DeviceRGB")) *csp = pdf_devicergb; else if (!strcmp(fz_toname(name), "DeviceCMYK")) *csp = pdf_devicecmyk; else if (!strcmp(fz_toname(name), "G")) *csp = pdf_devicegray; else if (!strcmp(fz_toname(name), "RGB")) *csp = pdf_devicergb; else if (!strcmp(fz_toname(name), "CMYK")) *csp = pdf_devicecmyk; else return fz_throw("syntaxerror: unknown colorspace %s", fz_toname(name)); return fz_okay; } } return fz_throw("syntaxerror: could not parse color space"); }
fz_error * pdf_loadfontdescriptor(pdf_font *font, pdf_xref *xref, fz_obj *desc, char *collection) { fz_error *error; fz_obj *obj1, *obj2, *obj3, *obj; fz_rect bbox; char *fontname; error = pdf_resolve(&desc, xref); if (error) return fz_rethrow(error, "cannot find font descriptor"); pdf_logfont("load fontdescriptor {\n"); obj = fz_dictgets(desc, "FontName"); if (error) return fz_rethrow(error, "cannot resolve FontName"); fontname = fz_toname(obj); pdf_logfont("fontname %s\n", fontname); font->flags = fz_toint(fz_dictgets(desc, "Flags")); font->italicangle = fz_toreal(fz_dictgets(desc, "ItalicAngle")); font->ascent = fz_toreal(fz_dictgets(desc, "Ascent")); font->descent = fz_toreal(fz_dictgets(desc, "Descent")); font->capheight = fz_toreal(fz_dictgets(desc, "CapHeight")); font->xheight = fz_toreal(fz_dictgets(desc, "XHeight")); font->missingwidth = fz_toreal(fz_dictgets(desc, "MissingWidth")); bbox = pdf_torect(fz_dictgets(desc, "FontBBox")); pdf_logfont("bbox [%g %g %g %g]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1); pdf_logfont("flags %d\n", font->flags); obj1 = fz_dictgets(desc, "FontFile"); obj2 = fz_dictgets(desc, "FontFile2"); obj3 = fz_dictgets(desc, "FontFile3"); obj = obj1 ? obj1 : obj2 ? obj2 : obj3; if (getenv("NOFONT")) obj = nil; if (fz_isindirect(obj)) { error = pdf_loadembeddedfont(font, xref, obj); if (error) goto cleanup; } else { error = pdf_loadsystemfont(font, fontname, collection); if (error) goto cleanup; } fz_dropobj(desc); pdf_logfont("}\n"); return fz_okay; cleanup: fz_dropobj(desc); return fz_rethrow(error, "cannot load font descriptor"); }
static fz_error gatherimages(int page, fz_obj *pageobj, fz_obj *dict) { int i; for (i = 0; i < fz_dictlen(dict); i++) { fz_obj *ref; fz_obj *imagedict; fz_obj *type; fz_obj *width; fz_obj *height; fz_obj *bpc = nil; fz_obj *filter = nil; fz_obj *mask; fz_obj *cs = nil; fz_obj *altcs; int k; imagedict = ref = fz_dictgetval(dict, i); if (!fz_isdict(imagedict)) return fz_throw("not an image dict (%d %d R)", fz_tonum(ref), fz_togen(ref)); type = fz_dictgets(imagedict, "Subtype"); if (!fz_isname(type)) return fz_throw("not an image subtype (%d %d R)", fz_tonum(ref), fz_togen(ref)); if (strcmp(fz_toname(type), "Image")) continue; filter = fz_dictgets(imagedict, "Filter"); if (filter && !fz_isname(filter) && !fz_isarray(filter)) return fz_throw("not an image filter (%d %d R)", fz_tonum(ref), fz_togen(ref)); mask = fz_dictgets(imagedict, "ImageMask"); altcs = nil; cs = fz_dictgets(imagedict, "ColorSpace"); if (fz_isarray(cs)) { fz_obj *cses = cs; cs = fz_arrayget(cses, 0); if (fz_isname(cs) && (!strcmp(fz_toname(cs), "DeviceN") || !strcmp(fz_toname(cs), "Separation"))) { altcs = fz_arrayget(cses, 2); if (fz_isarray(altcs)) altcs = fz_arrayget(altcs, 0); } } if (fz_isbool(mask) && fz_tobool(mask)) { if (cs) fz_warn("image mask (%d %d R) may not have colorspace", fz_tonum(ref), fz_togen(ref)); } if (cs && !fz_isname(cs)) return fz_throw("not an image colorspace (%d %d R)", fz_tonum(ref), fz_togen(ref)); if (altcs && !fz_isname(altcs)) return fz_throw("not an image alternate colorspace (%d %d R)", fz_tonum(ref), fz_togen(ref)); width = fz_dictgets(imagedict, "Width"); if (!fz_isint(width)) return fz_throw("not an image width (%d %d R)", fz_tonum(ref), fz_togen(ref)); height = fz_dictgets(imagedict, "Height"); if (!fz_isint(height)) return fz_throw("not an image height (%d %d R)", fz_tonum(ref), fz_togen(ref)); bpc = fz_dictgets(imagedict, "BitsPerComponent"); if (!fz_tobool(mask) && !fz_isint(bpc)) return fz_throw("not an image bits per component (%d %d R)", fz_tonum(ref), fz_togen(ref)); if (fz_tobool(mask) && fz_isint(bpc) && fz_toint(bpc) != 1) return fz_throw("not an image mask bits per component (%d %d R)", fz_tonum(ref), fz_togen(ref)); for (k = 0; k < images; k++) if (fz_tonum(image[k]->ref) == fz_tonum(ref) && fz_togen(image[k]->ref) == fz_togen(ref)) break; if (k < images) continue; images++; image = fz_realloc(image, images * sizeof (struct info *)); if (!image) return fz_throw("out of memory"); image[images - 1] = fz_malloc(sizeof (struct info)); if (!image[images - 1]) return fz_throw("out of memory"); image[images - 1]->page = page; image[images - 1]->pageobj = pageobj; image[images - 1]->ref = ref; image[images - 1]->u.image.width = width; image[images - 1]->u.image.height = height; image[images - 1]->u.image.bpc = bpc; image[images - 1]->u.image.filter = filter; image[images - 1]->u.image.cs = cs; image[images - 1]->u.image.altcs = altcs; } return fz_okay; }
pdf_link * pdf_loadlink(pdf_xref *xref, fz_obj *dict) { fz_obj *dest; fz_obj *action; fz_obj *obj; fz_rect bbox; pdf_linkkind kind; pdf_logpage("load link {\n"); dest = nil; obj = fz_dictgets(dict, "Rect"); if (obj) { bbox = pdf_torect(obj); pdf_logpage("rect [%g %g %g %g]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1); } else bbox = fz_emptyrect; obj = fz_dictgets(dict, "Dest"); if (obj) { kind = PDF_LGOTO; dest = resolvedest(xref, obj); pdf_logpage("dest (%d %d R)\n", fz_tonum(dest), fz_togen(dest)); } action = fz_dictgets(dict, "A"); if (action) { obj = fz_dictgets(action, "S"); if (fz_isname(obj) && !strcmp(fz_toname(obj), "GoTo")) { kind = PDF_LGOTO; dest = resolvedest(xref, fz_dictgets(action, "D")); pdf_logpage("action goto (%d %d R)\n", fz_tonum(dest), fz_togen(dest)); } else if (fz_isname(obj) && !strcmp(fz_toname(obj), "URI")) { kind = PDF_LURI; dest = fz_dictgets(action, "URI"); pdf_logpage("action uri %s\n", fz_tostrbuf(dest)); } /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=726 */ else if (fz_isname(obj) && !strcmp(fz_toname(obj), "Launch")) { kind = PDF_LLAUNCH; dest = fz_dictgets(action, "F"); pdf_logpage("action launch (%d %d R)\n", fz_tonum(dest), fz_togen(dest)); } else { pdf_logpage("unhandled link action, ignoring link\n"); dest = nil; } } pdf_logpage("}\n"); if (dest) { return pdf_newlink(kind, bbox, dest); } return nil; }
static fz_error * loadpagetree(pdf_xref *xref, pdf_pagetree *pages, struct stuff inherit, fz_obj *obj, fz_obj *ref, int *pagenum) { fz_error *error; fz_obj *type; fz_obj *kids; fz_obj *kref, *kobj; fz_obj *inh; int i; type = fz_dictgets(obj, "Type"); if (strcmp(fz_toname(type), "Page") == 0) { pdf_logpage("page %d, %d %d\n", *pagenum, ref->u.r.oid, ref->u.r.gid); (*pagenum)++; if (inherit.resources && !fz_dictgets(obj, "Resources")) { pdf_logpage("inherit resources (%d)\n", pages->cursor); error = fz_dictputs(obj, "Resources", inherit.resources); if (error) return fz_rethrow(error, "cannot inherit page tree resources"); } if (inherit.mediabox && !fz_dictgets(obj, "MediaBox")) { pdf_logpage("inherit mediabox (%d)\n", pages->cursor); error = fz_dictputs(obj, "MediaBox", inherit.mediabox); if (error) return fz_rethrow(error, "cannot inherit page tree mediabox"); } if (inherit.cropbox && !fz_dictgets(obj, "CropBox")) { pdf_logpage("inherit cropbox (%d)\n", pages->cursor); error = fz_dictputs(obj, "CropBox", inherit.cropbox); if (error) return fz_rethrow(error, "cannot inherit page tree cropbox"); } if (inherit.rotate && !fz_dictgets(obj, "Rotate")) { pdf_logpage("inherit rotate (%d)\n", pages->cursor); error = fz_dictputs(obj, "Rotate", inherit.rotate); if (error) return fz_rethrow(error, "cannot inherit page tree rotate"); } pages->pref[pages->cursor] = fz_keepobj(ref); pages->pobj[pages->cursor] = fz_keepobj(obj); pages->cursor ++; } else if (strcmp(fz_toname(type), "Pages") == 0) { inh = fz_dictgets(obj, "Resources"); if (inh) inherit.resources = inh; inh = fz_dictgets(obj, "MediaBox"); if (inh) inherit.mediabox = inh; inh = fz_dictgets(obj, "CropBox"); if (inh) inherit.cropbox = inh; inh = fz_dictgets(obj, "Rotate"); if (inh) inherit.rotate = inh; kids = fz_dictgets(obj, "Kids"); error = pdf_resolve(&kids, xref); if (error) return fz_rethrow(error, "cannot resolve /Kids"); pdf_logpage("subtree %d pages, %d %d {\n", fz_arraylen(kids), ref->u.r.oid, ref->u.r.gid); for (i = 0; i < fz_arraylen(kids); i++) { kref = fz_arrayget(kids, i); error = pdf_loadindirect(&kobj, xref, kref); if (error) { fz_dropobj(kids); return fz_rethrow(error, "cannot load kid"); } if (kobj == obj) { /* prevent infinite recursion possible in maliciously crafted PDFs */ fz_dropobj(kids); return fz_throw("corrupted pdf file"); } error = loadpagetree(xref, pages, inherit, kobj, kref, pagenum); fz_dropobj(kobj); if (error) { fz_dropobj(kids); return fz_rethrow(error, "cannot load subtree"); } } fz_dropobj(kids); pdf_logpage("}\n"); } else return fz_throw("pagetree node has unexpected type %s", fz_toname(type)); return fz_okay; }
/* * Load CMap stream in PDF file */ fz_error pdf_loadembeddedcmap(pdf_cmap **cmapp, pdf_xref *xref, fz_obj *stmref) { fz_error error = fz_okay; fz_obj *stmobj; fz_stream *file = nil; pdf_cmap *cmap = nil; pdf_cmap *usecmap; fz_obj *wmode; fz_obj *obj; if ((*cmapp = pdf_finditem(xref->store, PDF_KCMAP, stmref))) { pdf_keepcmap(*cmapp); return fz_okay; } pdf_logfont("load embedded cmap (%d %d R) {\n", fz_tonum(stmref), fz_togen(stmref)); stmobj = fz_resolveindirect(stmref); error = pdf_openstream(&file, xref, fz_tonum(stmref), fz_togen(stmref)); if (error) { error = fz_rethrow(error, "cannot open cmap stream"); goto cleanup; } error = pdf_parsecmap(&cmap, file); if (error) { error = fz_rethrow(error, "cannot parse cmap stream"); goto cleanup; } fz_dropstream(file); wmode = fz_dictgets(stmobj, "WMode"); if (fz_isint(wmode)) { pdf_logfont("wmode %d\n", wmode); pdf_setwmode(cmap, fz_toint(wmode)); } obj = fz_dictgets(stmobj, "UseCMap"); if (fz_isname(obj)) { pdf_logfont("usecmap /%s\n", fz_toname(obj)); error = pdf_loadsystemcmap(&usecmap, fz_toname(obj)); if (error) { error = fz_rethrow(error, "cannot load system usecmap '%s'", fz_toname(obj)); goto cleanup; } pdf_setusecmap(cmap, usecmap); pdf_dropcmap(usecmap); } else if (fz_isindirect(obj)) { pdf_logfont("usecmap (%d %d R)\n", fz_tonum(obj), fz_togen(obj)); error = pdf_loadembeddedcmap(&usecmap, xref, obj); if (error) { error = fz_rethrow(error, "cannot load embedded usecmap"); goto cleanup; } pdf_setusecmap(cmap, usecmap); pdf_dropcmap(usecmap); } pdf_logfont("}\n"); error = pdf_storeitem(xref->store, PDF_KCMAP, stmref, cmap); if (error) { error = fz_rethrow(error, "cannot store cmap resource"); goto cleanup; } *cmapp = cmap; return fz_okay; cleanup: if (file) fz_dropstream(file); if (cmap) pdf_dropcmap(cmap); return error; /* already rethrown */ }
static int isfontdesc(fz_obj *obj) { fz_obj *type = fz_dictgets(obj, "Type"); return fz_isname(type) && !strcmp(fz_toname(type), "FontDescriptor"); }
static void savefont(fz_obj *dict, int num, int gen) { fz_error error; char name[1024]; char *subtype; fz_buffer *buf; fz_obj *stream = nil; fz_obj *obj; char *ext = ""; FILE *f; unsigned char *p; char *fontname = "font"; obj = fz_dictgets(dict, "FontName"); if (obj) fontname = fz_toname(obj); obj = fz_dictgets(dict, "FontFile"); if (obj) { stream = obj; ext = "pfa"; } obj = fz_dictgets(dict, "FontFile2"); if (obj) { stream = obj; ext = "ttf"; } obj = fz_dictgets(dict, "FontFile3"); if (obj) { stream = obj; obj = fz_dictgets(obj, "Subtype"); if (obj && !fz_isname(obj)) die(fz_throw("Invalid font descriptor subtype")); subtype = fz_toname(obj); if (!strcmp(subtype, "Type1C")) ext = "cff"; else if (!strcmp(subtype, "CIDFontType0C")) ext = "cid"; else die(fz_throw("Unhandled font type '%s'", subtype)); } if (!stream) { fz_warn("Unhandled font type"); return; } error = fz_newbuffer(&buf, 0); if (error) die(error); error = pdf_loadstream(&buf, xref, fz_tonum(stream), fz_togen(stream)); if (error) die(error); sprintf(name, "%s-%04d.%s", fontname, num, ext); f = fopen(name, "wb"); if (f == NULL) die(fz_throw("Error creating image file")); for (p = buf->rp; p < buf->wp; p ++) fprintf(f, "%c", *p); if (fclose(f) < 0) die(fz_throw("Error closing image file")); fz_dropbuffer(buf); }
static fz_error gatherforms(int page, fz_obj *pageobj, fz_obj *dict) { int i; for (i = 0; i < fz_dictlen(dict); i++) { fz_obj *ref; fz_obj *xobjdict; fz_obj *type; fz_obj *subtype; fz_obj *group; fz_obj *reference; int k; xobjdict = ref = fz_dictgetval(dict, i); if (!fz_isdict(xobjdict)) return fz_throw("not a xobject dict (%d %d R)", fz_tonum(ref), fz_togen(ref)); type = fz_dictgets(xobjdict, "Subtype"); if (!fz_isname(type)) return fz_throw("not a xobject type (%d %d R)", fz_tonum(ref), fz_togen(ref)); if (strcmp(fz_toname(type), "Form")) continue; subtype = fz_dictgets(xobjdict, "Subtype2"); if (subtype && !fz_isname(subtype)) return fz_throw("not a xobject subtype (%d %d R)", fz_tonum(ref), fz_togen(ref)); if (strcmp(fz_toname(subtype), "PS")) continue; group = fz_dictgets(xobjdict, "Group"); if (group && !fz_isdict(group)) return fz_throw("not a form xobject group dict (%d %d R)", fz_tonum(ref), fz_togen(ref)); reference = fz_dictgets(xobjdict, "Ref"); if (reference && !fz_isdict(reference)) return fz_throw("not a form xobject reference dict (%d %d R)", fz_tonum(ref), fz_togen(ref)); for (k = 0; k < forms; k++) if (fz_tonum(form[k]->ref) == fz_tonum(ref) && fz_togen(form[k]->ref) == fz_togen(ref)) break; if (k < forms) continue; forms++; form = fz_realloc(form, forms * sizeof (struct info *)); if (!form) return fz_throw("out of memory"); form[forms - 1] = fz_malloc(sizeof (struct info)); if (!form[forms - 1]) return fz_throw("out of memory"); form[forms - 1]->page = page; form[forms - 1]->pageobj = pageobj; form[forms - 1]->ref = ref; form[forms - 1]->u.form.group = group; form[forms - 1]->u.form.reference = reference; } return fz_okay; }
static void printinfo(char *filename, int show, int page) { int i; int j; #define PAGE_FMT "\t% 6d (% 6d %1d R): " if (show & DIMENSIONS && dims > 0) { printf("MediaBox: "); printf("\n"); for (i = 0; i < dims; i++) { printf(PAGE_FMT "[ %g %g %g %g ]\n", dim[i]->page, fz_tonum(dim[i]->pageobj), fz_togen(dim[i]->pageobj), dim[i]->u.dim.bbox->x0, dim[i]->u.dim.bbox->y0, dim[i]->u.dim.bbox->x1, dim[i]->u.dim.bbox->y1); } printf("\n"); for (i = 0; i < dims; i++) { fz_free(dim[i]->u.dim.bbox); fz_free(dim[i]); } fz_free(dim); dim = nil; dims = 0; } if (show & FONTS && fonts > 0) { printf("Fonts (%d):\n", fonts); for (i = 0; i < fonts; i++) { printf(PAGE_FMT "%s '%s' (%d %d R)\n", font[i]->page, fz_tonum(font[i]->pageobj), fz_togen(font[i]->pageobj), fz_toname(font[i]->u.font.subtype), fz_toname(font[i]->u.font.name), fz_tonum(font[i]->ref), fz_togen(font[i]->ref)); } printf("\n"); for (i = 0; i < fonts; i++) fz_free(font[i]); fz_free(font); font = nil; fonts = 0; } if (show & IMAGES && images > 0) { printf("Images (%d):\n", images); for (i = 0; i < images; i++) { printf(PAGE_FMT "[ ", image[i]->page, fz_tonum(image[i]->pageobj), fz_togen(image[i]->pageobj)); if (fz_isarray(image[i]->u.image.filter)) for (j = 0; j < fz_arraylen(image[i]->u.image.filter); j++) { printf("%s%s", fz_toname(fz_arrayget(image[i]->u.image.filter, j)), j == fz_arraylen(image[i]->u.image.filter) - 1 ? "" : " "); } else if (image[i]->u.image.filter) printf("%s", fz_toname(image[i]->u.image.filter)); else printf("Raw"); printf(" ] %dx%d %dbpc %s%s%s (%d %d R)\n", fz_toint(image[i]->u.image.width), fz_toint(image[i]->u.image.height), image[i]->u.image.bpc ? fz_toint(image[i]->u.image.bpc) : 1, image[i]->u.image.cs ? fz_toname(image[i]->u.image.cs) : "ImageMask", image[i]->u.image.altcs ? " " : "", image[i]->u.image.altcs ? fz_toname(image[i]->u.image.altcs) : "", fz_tonum(image[i]->ref), fz_togen(image[i]->ref)); } printf("\n"); for (i = 0; i < images; i++) fz_free(image[i]); fz_free(image); image = nil; images = 0; } if (show & SHADINGS && shadings > 0) { printf("Shading patterns (%d):\n", shadings); for (i = 0; i < shadings; i++) { char *shadingtype[] = { "", "Function", "Axial", "Radial", "Free-form triangle mesh", "Lattice-form triangle mesh", "Coons patch mesh", "Tensor-product patch mesh", }; printf(PAGE_FMT "%s (%d %d R)\n", shading[i]->page, fz_tonum(shading[i]->pageobj), fz_togen(shading[i]->pageobj), shadingtype[fz_toint(shading[i]->u.shading.type)], fz_tonum(shading[i]->ref), fz_togen(shading[i]->ref)); } printf("\n"); for (i = 0; i < shadings; i++) fz_free(shading[i]); fz_free(shading); shading = nil; shadings = 0; } if (show & PATTERNS && patterns > 0) { printf("Patterns (%d):\n", patterns); for (i = 0; i < patterns; i++) { char *patterntype[] = { "", "Tiling", "Shading", }; char *painttype[] = { "", "Colored", "Uncolored", }; char *tilingtype[] = { "", "Constant spacing", "No distortion", "Constant space/fast tiling", }; printf(PAGE_FMT "%s %s %s (%d %d R)\n", pattern[i]->page, fz_tonum(pattern[i]->pageobj), fz_togen(pattern[i]->pageobj), patterntype[fz_toint(pattern[i]->u.pattern.pattern)], painttype[fz_toint(pattern[i]->u.pattern.paint)], tilingtype[fz_toint(pattern[i]->u.pattern.tiling)], fz_tonum(pattern[i]->ref), fz_togen(pattern[i]->ref)); } printf("\n"); for (i = 0; i < patterns; i++) fz_free(pattern[i]); fz_free(pattern); pattern = nil; patterns = 0; } if (show & XOBJS && forms > 0) { printf("Form xobjects (%d):\n", forms); for (i = 0; i < forms; i++) { printf(PAGE_FMT "%s%s (%d %d R)\n", form[i]->page, fz_tonum(form[i]->pageobj), fz_togen(form[i]->pageobj), form[i]->u.form.group ? "Group" : "", form[i]->u.form.reference ? "Reference" : "", fz_tonum(form[i]->ref), fz_togen(form[i]->ref)); } printf("\n"); for (i = 0; i < forms; i++) fz_free(form[i]); fz_free(form); form = nil; forms = 0; } if (show & XOBJS && psobjs > 0) { printf("Postscript xobjects (%d):\n", psobjs); for (i = 0; i < psobjs; i++) { printf(PAGE_FMT "(%d %d R)\n", psobj[i]->page, fz_tonum(psobj[i]->pageobj), fz_togen(psobj[i]->pageobj), fz_tonum(psobj[i]->ref), fz_togen(psobj[i]->ref)); } printf("\n"); for (i = 0; i < psobjs; i++) fz_free(psobj[i]); fz_free(psobj); psobj = nil; psobjs = 0; } }
static fz_error loadsimplefont(pdf_fontdesc **fontdescp, pdf_xref *xref, fz_obj *dict) { fz_error error; fz_obj *descriptor = nil; fz_obj *encoding = nil; fz_obj *widths = nil; unsigned short *etable = nil; pdf_fontdesc *fontdesc; 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; basefont = fz_toname(fz_dictgets(dict, "BaseFont")); fontname = cleanfontname(basefont); /* * Load font file */ fontdesc = pdf_newfontdesc(); if (!fontdesc) return fz_rethrow(-1, "out of memory"); pdf_logfont("load simple font (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), fontdesc); pdf_logfont("basefont0 %s\n", basefont); pdf_logfont("basefont1 %s\n", fontname); descriptor = fz_dictgets(dict, "FontDescriptor"); if (descriptor && basefont == fontname) error = pdf_loadfontdescriptor(fontdesc, xref, descriptor, nil); else error = pdf_loadbuiltinfont(fontdesc, fontname); if (error) goto cleanup; face = fontdesc->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(fontdesc->font, -1000, -1000, 2000, 2000); else fz_setfontbbox(fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* * Encoding */ symbolic = fontdesc->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) fz_warn("freetype could not set cmap: %s", ft_errorstring(fterr)); } 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)) { 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)); else if (!fontdesc->isembedded) pdf_loadencoding(estrings, "StandardEncoding"); 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); fterr = FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32); if (fterr) { error = fz_throw("freetype get glyph name (gid %d): %s", etable[i], ft_errorstring(fterr)); goto cleanup; } if (ebuffer[i][0]) estrings[i] = ebuffer[i]; } } } } else { pdf_logfont("encode builtin\n"); for (i = 0; i < 256; i++) { etable[i] = ftcharindex(face, i); if (etable[i] == 0) continue; if (FT_HAS_GLYPH_NAMES(face)) { fterr = FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32); if (fterr) { error = fz_throw("freetype get glyph name (gid %d): %s", etable[i], ft_errorstring(fterr)); goto cleanup; } if (ebuffer[i][0]) estrings[i] = ebuffer[i]; } } } error = pdf_newidentitycmap(&fontdesc->encoding, 0, 1); if (error) goto cleanup; fontdesc->ncidtogid = 256; fontdesc->cidtogid = etable; error = pdf_loadtounicode(fontdesc, xref, estrings, nil, fz_dictgets(dict, "ToUnicode")); if (error) goto cleanup; /* * Widths */ pdf_setdefaulthmtx(fontdesc, fontdesc->missingwidth); widths = fz_dictgets(dict, "Widths"); if (widths) { int first, last; first = fz_toint(fz_dictgets(dict, "FirstChar")); last = fz_toint(fz_dictgets(dict, "LastChar")); if (first < 0 || last > 255 || first > last) first = last = 0; for (i = 0; i < last - first + 1; i++) { int wid = fz_toint(fz_arrayget(widths, i)); error = pdf_addhmtx(fontdesc, i + first, i + first, wid); if (error) goto cleanup; } } else { fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72); if (fterr) fz_warn("freetype set character size: %s", ft_errorstring(fterr)); for (i = 0; i < 256; i++) { error = pdf_addhmtx(fontdesc, i, i, ftwidth(fontdesc, i)); if (error) goto cleanup; } } error = pdf_endhmtx(fontdesc); if (error) goto cleanup; pdf_logfont("}\n"); *fontdescp = fontdesc; return fz_okay; cleanup: fz_free(etable); fz_dropfont(fontdesc->font); fz_free(fontdesc); return fz_rethrow(error, "cannot load simple font"); }
/* * Create a filter given a name and param dictionary. */ static fz_error * buildonefilter(fz_filter **fp, fz_obj *f, fz_obj *p) { fz_filter *decompress; fz_filter *predict; fz_error *error; char *s; s = fz_toname(f); if (!strcmp(s, "ASCIIHexDecode") || !strcmp(s, "AHx")) error = fz_newahxd(fp, p); else if (!strcmp(s, "ASCII85Decode") || !strcmp(s, "A85")) error = fz_newa85d(fp, p); else if (!strcmp(s, "CCITTFaxDecode") || !strcmp(s, "CCF")) error = fz_newfaxd(fp, p); else if (!strcmp(s, "DCTDecode") || !strcmp(s, "DCT")) error = fz_newdctd(fp, p); else if (!strcmp(s, "RunLengthDecode") || !strcmp(s, "RL")) error = fz_newrld(fp, p); else if (!strcmp(s, "FlateDecode") || !strcmp(s, "Fl")) { if (fz_isdict(p)) { fz_obj *obj = fz_dictgets(p, "Predictor"); if (obj) { error = fz_newflated(&decompress, p); if (error) return fz_rethrow(error, "cannot create deflate filter"); error = fz_newpredictd(&predict, p); if (error) { fz_dropfilter(decompress); return fz_rethrow(error, "cannot create predictor filter"); } error = fz_newpipeline(fp, decompress, predict); fz_dropfilter(decompress); fz_dropfilter(predict); if (error) return fz_rethrow(error, "cannot create pipeline filter"); return fz_okay; } } error = fz_newflated(fp, p); } else if (!strcmp(s, "LZWDecode") || !strcmp(s, "LZW")) { if (fz_isdict(p)) { fz_obj *obj = fz_dictgets(p, "Predictor"); if (obj) { error = fz_newlzwd(&decompress, p); if (error) return fz_rethrow(error, "cannot create lzwd filter"); error = fz_newpredictd(&predict, p); if (error) { fz_dropfilter(decompress); return fz_rethrow(error, "cannot create predictor filter"); } error = fz_newpipeline(fp, decompress, predict); fz_dropfilter(decompress); fz_dropfilter(predict); if (error) return fz_rethrow(error, "cannot create pipeline filter"); return fz_okay; } } error = fz_newlzwd(fp, p); } #ifdef HAVE_JBIG2DEC else if (!strcmp(s, "JBIG2Decode")) { /* TODO: extract and feed JBIG2Global */ error = fz_newjbig2d(fp, p); } #endif #ifdef HAVE_JASPER else if (!strcmp(s, "JPXDecode")) error = fz_newjpxd(fp, p); #endif else { return fz_throw("unknown filter name (%s)", s); } if (error) return fz_rethrow(error, "cannot create filter"); return fz_okay; }
static int isimage(fz_obj *obj) { fz_obj *type = fz_dictgets(obj, "Subtype"); return fz_isname(type) && !strcmp(fz_toname(type), "Image"); }