static fz_obj * resolvedest(pdf_xref *xref, fz_obj *dest) { if (fz_isname(dest)) { dest = fz_dictget(xref->dests, dest); if (dest) pdf_resolve(&dest, xref); /* XXX */ return resolvedest(xref, dest); } else if (fz_isstring(dest)) { dest = fz_dictget(xref->dests, dest); if (dest) pdf_resolve(&dest, xref); /* XXX */ return resolvedest(xref, dest); } else if (fz_isarray(dest)) { return fz_arrayget(dest, 0); } else if (fz_isdict(dest)) { dest = fz_dictgets(dest, "D"); return resolvedest(xref, dest); } else if (fz_isindirect(dest)) return dest; return nil; }
static fz_error * loadoutline(pdf_outline **nodep, pdf_xref *xref, fz_obj *dict) { fz_error *error; pdf_outline *node; fz_obj *obj; node = fz_malloc(sizeof(pdf_outline)); node->title = "<unknown>"; node->link = nil; node->child = nil; node->next = nil; pdf_logpage("load outline {\n"); obj = fz_dictgets(dict, "Title"); if (obj) { error = pdf_toutf8(&node->title, obj); if (error) return error; pdf_logpage("title %s\n", node->title); } if (fz_dictgets(dict, "Dest") || fz_dictgets(dict, "A")) { error = pdf_loadlink(&node->link, xref, dict); if (error) return error; } obj = fz_dictgets(dict, "First"); if (obj) { error = pdf_resolve(&obj, xref); if (error) return error; error = loadoutline(&node->child, xref, obj); fz_dropobj(obj); if (error) return error; } pdf_logpage("}\n"); obj = fz_dictgets(dict, "Next"); if (obj) { error = pdf_resolve(&obj, xref); if (error) return error; error = loadoutline(&node->next, xref, obj); fz_dropobj(obj); if (error) return error; } *nodep = node; return nil; }
fz_error* setPageMediaBox( pdf_xref* pdfXRef, fz_obj* pageObj, fz_rect mediaBox ) { fz_error *error; fz_obj *objMedia; fz_irect mRect; fz_obj *objInt; // Delete the CropBox. This is done because we are reducing // the size of the media box and CropBox is of no use to us fz_dictdels(pageObj, "CropBox"); //objMedia = fz_dictgets(pageObj, "CropBox"); //if (objMedia == NULL) return fz_throw("no CropBox entry"); //error = pdf_resolve(&objMedia, pdfXRef); //if (error) return fz_rethrow(error, "cannot resolve page bounds"); //if (! fz_isarray(objMedia)) return fz_throw("cannot find page bounds"); //fz_rect cRect = pdf_torect(objMedia); // Get the media box objMedia = fz_dictgets(pageObj, "MediaBox"); if (objMedia == NULL) return fz_throw("no MediaBox entry"); error = pdf_resolve(&objMedia, pdfXRef); if (error) return fz_rethrow(error, "cannot resolve page bounds"); if (! fz_isarray(objMedia)) return fz_throw("cannot find page bounds"); // We have the MediaBox array here mRect = fz_roundrect(mediaBox); error = fz_newint(&objInt, mRect.x0); if (error) return fz_rethrow(error, "cannot allocate int"); fz_arrayput(objMedia, 0, objInt); fz_dropobj(objInt); error = fz_newint(&objInt, mRect.y0); if (error) return fz_rethrow(error, "cannot allocate int"); fz_arrayput(objMedia, 1, objInt); fz_dropobj(objInt); error = fz_newint(&objInt, mRect.x1); if (error) return fz_rethrow(error, "cannot allocate int"); fz_arrayput(objMedia, 2, objInt); fz_dropobj(objInt); error = fz_newint(&objInt, mRect.y1); if (error) return fz_rethrow(error, "cannot allocate int"); fz_arrayput(objMedia, 3, objInt); fz_dropobj(objInt); return NULL; }
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 fz_error * loadseparation(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) { fz_error *error; struct separation *cs; fz_obj *nameobj = fz_arrayget(array, 1); fz_obj *baseobj = fz_arrayget(array, 2); fz_obj *tintobj = fz_arrayget(array, 3); fz_colorspace *base; pdf_function *tint; int n; pdf_logrsrc("load Separation {\n"); if (fz_isarray(nameobj)) n = fz_arraylen(nameobj); else n = 1; pdf_logrsrc("n = %d\n", n); error = pdf_resolve(&baseobj, xref); if (error) return error; error = pdf_loadcolorspace(&base, xref, baseobj); fz_dropobj(baseobj); if (error) return error; error = pdf_loadfunction(&tint, xref, tintobj); if (error) { fz_dropcolorspace(base); return error; } cs = fz_malloc(sizeof(struct separation)); if (!cs) { pdf_dropfunction(tint); fz_dropcolorspace(base); return fz_outofmem; } initcs((fz_colorspace*)cs, n == 1 ? "Separation" : "DeviceN", n, separationtoxyz, nil, dropseparation); cs->base = base; cs->tint = tint; pdf_logrsrc("}\n"); *csp = (fz_colorspace*)cs; return nil; }
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 fz_error * loadcalgray(fz_colorspace **csp, pdf_xref *xref, fz_obj *dict) { fz_error *error; struct calgray *cs; fz_obj *tmp; error = pdf_resolve(&dict, xref); if (error) return error; cs = fz_malloc(sizeof(struct calgray)); if (!cs) return fz_outofmem; pdf_logrsrc("load CalGray\n"); initcs((fz_colorspace*)cs, "CalGray", 1, graytoxyz, xyztogray, nil); cs->white[0] = 1.0; cs->white[1] = 1.0; cs->white[2] = 1.0; cs->black[0] = 0.0; cs->black[1] = 0.0; cs->black[2] = 0.0; cs->gamma = 1.0; tmp = fz_dictgets(dict, "WhitePoint"); if (fz_isarray(tmp)) { cs->white[0] = fz_toreal(fz_arrayget(tmp, 0)); cs->white[1] = fz_toreal(fz_arrayget(tmp, 1)); cs->white[2] = fz_toreal(fz_arrayget(tmp, 2)); } tmp = fz_dictgets(dict, "BlackPoint"); if (fz_isarray(tmp)) { cs->black[0] = fz_toreal(fz_arrayget(tmp, 0)); cs->black[1] = fz_toreal(fz_arrayget(tmp, 1)); cs->black[2] = fz_toreal(fz_arrayget(tmp, 2)); } tmp = fz_dictgets(dict, "Gamma"); if (fz_isreal(tmp)) cs->gamma = fz_toreal(tmp); fz_dropobj(dict); *csp = (fz_colorspace*) cs; return nil; }
fz_error * pdf_loadoutline(pdf_outline **nodep, pdf_xref *xref) { fz_error *error; pdf_outline *node; fz_obj *obj; fz_obj *first; pdf_logpage("load outlines {\n"); node = nil; obj = fz_dictgets(xref->root, "Outlines"); if (obj) { error = pdf_resolve(&obj, xref); if (error) return error; first = fz_dictgets(obj, "First"); if (first) { error = pdf_resolve(&first, xref); fz_dropobj(obj); if (error) return error; error = loadoutline(&node, xref, first); fz_dropobj(first); if (error) return error; } else fz_dropobj(obj); } pdf_logpage("}\n"); *nodep = node; return nil; }
fz_error * pdf_loadnametrees(pdf_xref *xref) { fz_error *error; fz_obj *names; fz_obj *dests; /* PDF 1.1 */ dests = fz_dictgets(xref->root, "Dests"); if (dests) { error = pdf_resolve(&dests, xref); if (error) return error; xref->dests = dests; return nil; } /* PDF 1.2 */ names = fz_dictgets(xref->root, "Names"); if (names) { error = pdf_resolve(&names, xref); if (error) return error; dests = fz_dictgets(names, "Dests"); if (dests) { error = pdf_loadnametree(&xref->dests, xref, dests); if (error) { fz_dropobj(names); return error; } } fz_dropobj(names); } return nil; }
/* * Build a filter for reading raw stream data. * This is a null filter to constrain reading to the * stream length, followed by a decryption filter. */ static fz_error * buildrawfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int oid, int gen) { fz_error *error; fz_filter *base; fz_obj *stmlen; int len; stmlen = fz_dictgets(stmobj, "Length"); error = pdf_resolve(&stmlen, xref); if (error) return fz_rethrow(error, "cannot resolve stream /Length"); len = fz_toint(stmlen); fz_dropobj(stmlen); error = fz_newnullfilter(&base, len); if (error) return fz_rethrow(error, "cannot create null filter"); if (xref->crypt) { fz_filter *crypt; fz_filter *pipe; error = pdf_cryptstream(&crypt, xref->crypt, oid, gen); if (error) { fz_dropfilter(base); return fz_rethrow(error, "cannot create decryption filter"); } error = fz_newpipeline(&pipe, base, crypt); fz_dropfilter(base); fz_dropfilter(crypt); if (error) return fz_rethrow(error, "cannot create pipeline filter"); *filterp = pipe; } else { *filterp = base; } return fz_okay; }
fz_error * pdf_loadcolorspace(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 nil; } 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")) return loadcalgray(csp, xref, fz_arrayget(obj, 1)); else if (!strcmp(fz_toname(name), "CalRGB")) return loadcalrgb(csp, xref, fz_arrayget(obj, 1)); else if (!strcmp(fz_toname(name), "Lab")) return loadlab(csp, 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 nil; } error = pdf_resolve(&obj, xref); if (error) return error; error = pdf_loadcolorspace(csp, xref, obj); fz_dropobj(obj); return error; } else return fz_throw("syntaxerror: unknown colorspace %s", fz_toname(name)); return nil; } } return fz_throw("syntaxerror: could not parse color space"); }
static fz_error * loadindexed(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) { fz_error *error; pdf_indexed *cs; fz_obj *baseobj = fz_arrayget(array, 1); fz_obj *highobj = fz_arrayget(array, 2); fz_obj *lookup = fz_arrayget(array, 3); fz_colorspace *base; int n; pdf_logrsrc("load Indexed {\n"); error = pdf_resolve(&baseobj, xref); if (error) return error; error = pdf_loadcolorspace(&base, xref, baseobj); fz_dropobj(baseobj); if (error) return error; pdf_logrsrc("base %s\n", base->name); cs = fz_malloc(sizeof(pdf_indexed)); if (!cs) { fz_dropcolorspace(base); return fz_outofmem; } initcs((fz_colorspace*)cs, "Indexed", 1, nil, nil, dropindexed); cs->base = base; cs->high = fz_toint(highobj); n = base->n * (cs->high + 1); cs->lookup = fz_malloc(n); if (!cs->lookup) { fz_dropcolorspace((fz_colorspace*)cs); return fz_outofmem; } if (fz_isstring(lookup) && fz_tostrlen(lookup) == n) { unsigned char *buf; int i; pdf_logrsrc("string lookup\n"); buf = fz_tostrbuf(lookup); for (i = 0; i < n; i++) cs->lookup[i] = buf[i]; } if (fz_isindirect(lookup)) { fz_buffer *buf; int i; pdf_logrsrc("stream lookup\n"); error = pdf_loadstream(&buf, xref, fz_tonum(lookup), fz_togen(lookup)); if (error) { fz_dropcolorspace((fz_colorspace*)cs); return error; } for (i = 0; i < n && i < (buf->wp - buf->rp); i++) cs->lookup[i] = buf->rp[i]; fz_dropbuffer(buf); } pdf_logrsrc("}\n"); *csp = (fz_colorspace*)cs; return nil; }
/* TODO error cleanup */ fz_error * pdf_loadimage(pdf_image **imgp, pdf_xref *xref, fz_obj *dict, fz_obj *ref) { fz_error *error; pdf_image *img; pdf_image *mask; int ismask; fz_obj *obj; fz_obj *sub; int i; int w, h, bpc; int n = 0; int a = 0; int usecolorkey = 0; fz_colorspace *cs = nil; pdf_indexed *indexed = nil; int stride; #ifndef PSP printf("LI\n"); #endif if ((*imgp = pdf_finditem(xref->store, PDF_KIMAGE, ref))) { fz_keepimage((fz_image*)*imgp); return nil; } img = fz_malloc(sizeof(pdf_image)); if (!img) return fz_outofmem; img->super.refs = 0; pdf_logimage("load image %d %d (%p) {\n", fz_tonum(ref), fz_togen(ref), img); /* * Dimensions, BPC and ColorSpace */ w = fz_toint(fz_dictgets(dict, "Width")); h = fz_toint(fz_dictgets(dict, "Height")); bpc = fz_toint(fz_dictgets(dict, "BitsPerComponent")); pdf_logimage("size %dx%d %d\n", w, h, bpc); cs = nil; obj = fz_dictgets(dict, "ColorSpace"); if (obj) { cs = pdf_finditem(xref->store, PDF_KCOLORSPACE, obj); if (cs) fz_keepcolorspace(cs); else { error = pdf_resolve(&obj, xref); if (error) return error; error = pdf_loadcolorspace(&cs, xref, obj); if (error) return error; fz_dropobj(obj); } if (!strcmp(cs->name, "Indexed")) { pdf_logimage("indexed\n"); indexed = (pdf_indexed*)cs; cs = indexed->base; } n = cs->n; a = 0; pdf_logimage("colorspace %s\n", cs->name); } /* * ImageMask, Mask and SoftMask */ mask = nil; ismask = fz_tobool(fz_dictgets(dict, "ImageMask")); if (ismask) { pdf_logimage("is mask\n"); bpc = 1; n = 0; a = 1; } obj = fz_dictgets(dict, "SMask"); if (fz_isindirect(obj)) { pdf_logimage("has soft mask\n"); error = pdf_loadindirect(&sub, xref, obj); if (error) return error; error = pdf_loadimage(&mask, xref, sub, obj); if (error) return error; if (mask->super.cs != pdf_devicegray) return fz_throw("syntaxerror: SMask must be DeviceGray"); mask->super.cs = 0; mask->super.n = 0; mask->super.a = 1; fz_dropobj(sub); } obj = fz_dictgets(dict, "Mask"); if (fz_isindirect(obj)) { error = pdf_loadindirect(&sub, xref, obj); if (error) return error; if (fz_isarray(sub)) { usecolorkey = 1; loadcolorkey(img->colorkey, bpc, indexed != nil, sub); } else { pdf_logimage("has mask\n"); error = pdf_loadimage(&mask, xref, sub, obj); if (error) return error; } fz_dropobj(sub); } else if (fz_isarray(obj)) { usecolorkey = 1; loadcolorkey(img->colorkey, bpc, indexed != nil, obj); } /* * Decode */ obj = fz_dictgets(dict, "Decode"); if (fz_isarray(obj)) { pdf_logimage("decode array\n"); if (indexed) for (i = 0; i < 2; i++) img->decode[i] = fz_toreal(fz_arrayget(obj, i)); else for (i = 0; i < (n + a) * 2; i++) img->decode[i] = fz_toreal(fz_arrayget(obj, i)); } else { if (indexed) for (i = 0; i < 2; i++) img->decode[i] = i & 1 ? (1 << bpc) - 1 : 0; else for (i = 0; i < (n + a) * 2; i++) img->decode[i] = i & 1; } /* * Load samples */ if (indexed) stride = (w * bpc + 7) / 8; else stride = (w * (n + a) * bpc + 7) / 8; // ccm // do not load images larger than 2MB uncompressed int early_reject = 0; if (h * stride <= 2*1024*1024) { error = pdf_loadstream(&img->samples, xref, fz_tonum(ref), fz_togen(ref)); if (error) { /* TODO: colorspace? */ fz_free(img); return error; } if (img->samples->wp - img->samples->bp < stride * h) { /* TODO: colorspace? */ fz_dropbuffer(img->samples); fz_free(img); return fz_throw("syntaxerror: truncated image data"); } /* 0 means opaque and 1 means transparent, so we invert to get alpha */ if (ismask) { unsigned char *p; for (p = img->samples->bp; p < img->samples->ep; p++) *p = ~*p; } } else { #ifndef PSP printf("LI - %p - early reject\n", img); #endif img->samples = nil; early_reject = 1; } /* * Create image object */ img->super.loadtile = pdf_loadtile; img->super.drop = pdf_dropimage; img->super.cs = cs; img->super.w = w; img->super.h = h; img->super.n = n; img->super.a = a; img->indexed = indexed; img->stride = stride; img->bpc = bpc; img->mask = (fz_image*)mask; img->usecolorkey = usecolorkey; if (img->mask) fz_keepimage(img->mask); // ccm #if 1 int bs = 0; if (img->samples) bs = (int)(img->samples->wp) - (int)(img->samples->rp); if (early_reject || (image_buffers_size + bs >= image_buffers_size_max)) { #ifndef PSP printf("LI - %p - optimized out\n", img); #endif if (img->samples) fz_dropbuffer(img->samples); if (img->mask) fz_dropimage(img->mask); fz_newbuffer(&img->samples, 8); img->super.w = 1; img->super.h = 1; img->super.n = 3; img->super.a = 0; img->super.refs = 0; unsigned char *p; for (p = img->samples->bp; p < img->samples->ep; p++) *p = 0x7f; img->indexed = 0; img->stride = (1 * (3 + 0) * 8 + 7) / 8; //(w * (n + a) * bpc + 7) / 8; img->super.cs = cs; img->super.loadtile = fakeImageTile; img->bpc = 8; img->mask = NULL; img->usecolorkey = 0; } else { image_buffers_size += bs; } #endif pdf_logimage("}\n"); error = pdf_storeitem(xref->store, PDF_KIMAGE, ref, img); if (error) { fz_dropimage((fz_image*)img); return error; } *imgp = img; return nil; }
static fz_error * loadlab(fz_colorspace **csp, pdf_xref *xref, fz_obj *dict) { fz_error *error; struct cielab *cs; fz_obj *tmp; error = pdf_resolve(&dict, xref); if (error) return error; cs = fz_malloc(sizeof(struct cielab)); if (!cs) return fz_outofmem; pdf_logrsrc("load Lab\n"); initcs((fz_colorspace*)cs, "Lab", 3, labtoxyz, xyztolab, nil); cs->white[0] = 1.0; cs->white[1] = 1.0; cs->white[2] = 1.0; cs->black[0] = 0.0; cs->black[1] = 0.0; cs->black[2] = 0.0; cs->range[0] = -100; cs->range[1] = 100; cs->range[2] = -100; cs->range[3] = 100; tmp = fz_dictgets(dict, "WhitePoint"); if (fz_isarray(tmp)) { cs->white[0] = fz_toreal(fz_arrayget(tmp, 0)); cs->white[1] = fz_toreal(fz_arrayget(tmp, 1)); cs->white[2] = fz_toreal(fz_arrayget(tmp, 2)); } tmp = fz_dictgets(dict, "BlackPoint"); if (fz_isarray(tmp)) { cs->black[0] = fz_toreal(fz_arrayget(tmp, 0)); cs->black[1] = fz_toreal(fz_arrayget(tmp, 1)); cs->black[2] = fz_toreal(fz_arrayget(tmp, 2)); } tmp = fz_dictgets(dict, "Range"); if (fz_isarray(tmp)) { cs->range[0] = fz_toreal(fz_arrayget(tmp, 0)); cs->range[1] = fz_toreal(fz_arrayget(tmp, 1)); cs->range[2] = fz_toreal(fz_arrayget(tmp, 2)); cs->range[3] = fz_toreal(fz_arrayget(tmp, 3)); } fz_dropobj(dict); *csp = (fz_colorspace*) cs; return nil; }
fz_error * pdf_loadxobject(pdf_xobject **formp, pdf_xref *xref, fz_obj *dict, fz_obj *ref) { fz_error *error; pdf_xobject *form; fz_obj *obj; if ((*formp = pdf_finditem(xref->store, PDF_KXOBJECT, ref))) { pdf_keepxobject(*formp); return fz_okay; } form = fz_malloc(sizeof(pdf_xobject)); if (!form) return fz_throw("outofmem: xobject struct"); form->refs = 1; form->resources = nil; form->contents = nil; /* Store item immediately, to avoid infinite recursion if contained objects refer again to this xobject */ error = pdf_storeitem(xref->store, PDF_KXOBJECT, ref, form); if (error) { pdf_dropxobject(form); return fz_rethrow(error, "cannot store xobject resource"); } pdf_logrsrc("load xobject %d %d (%p) {\n", fz_tonum(ref), fz_togen(ref), form); obj = fz_dictgets(dict, "BBox"); form->bbox = pdf_torect(obj); pdf_logrsrc("bbox [%g %g %g %g]\n", form->bbox.x0, form->bbox.y0, form->bbox.x1, form->bbox.y1); obj = fz_dictgets(dict, "Matrix"); if (obj) form->matrix = pdf_tomatrix(obj); else form->matrix = fz_identity(); pdf_logrsrc("matrix [%g %g %g %g %g %g]\n", form->matrix.a, form->matrix.b, form->matrix.c, form->matrix.d, form->matrix.e, form->matrix.f); obj = fz_dictgets(dict, "I"); form->isolated = fz_tobool(obj); obj = fz_dictgets(dict, "K"); form->knockout = fz_tobool(obj); pdf_logrsrc("isolated %d\n", form->isolated); pdf_logrsrc("knockout %d\n", form->knockout); obj = fz_dictgets(dict, "Resources"); if (obj) { error = pdf_resolve(&obj, xref); if (error) { fz_dropobj(obj); error = fz_rethrow(error, "cannot resolve xobject resources"); goto cleanup; } error = pdf_loadresources(&form->resources, xref, obj); fz_dropobj(obj); if (error) { error = fz_rethrow(error, "cannot load xobject resources"); goto cleanup; } } error = pdf_loadstream(&form->contents, xref, fz_tonum(ref), fz_togen(ref)); if (error) { error = fz_rethrow(error, "cannot load xobject content stream"); goto cleanup; } pdf_logrsrc("stream %d bytes\n", form->contents->wp - form->contents->rp); pdf_logrsrc("}\n"); *formp = form; return fz_okay; cleanup: pdf_removeitem(xref->store, PDF_KXOBJECT, ref); pdf_dropxobject(form); return error; }
fz_error * pdf_loadshade(fz_shade **shadep, pdf_xref *xref, fz_obj *dict, fz_obj *ref) { fz_error *error; fz_matrix mat; fz_obj *obj; fz_obj *shd; if ((*shadep = pdf_finditem(xref->store, PDF_KSHADE, ref))) return nil; /* * Type 2 pattern dictionary */ if (fz_dictgets(dict, "PatternType")) { pdf_logshade("load shade pattern %d %d {\n", fz_tonum(ref), fz_togen(ref)); obj = fz_dictgets(dict, "Matrix"); if (obj) { mat = pdf_tomatrix(obj); pdf_logshade("matrix [%g %g %g %g %g %g]\n", mat.a, mat.b, mat.c, mat.d, mat.e, mat.f); } else { mat = fz_identity(); } obj = fz_dictgets(dict, "ExtGState"); if (obj) { pdf_logshade("extgstate ...\n"); } obj = fz_dictgets(dict, "Shading"); if (!obj) return fz_throw("syntaxerror: missing shading dictionary"); shd = obj; error = pdf_resolve(&shd, xref); if (error) return error; error = loadshadedict(shadep, xref, shd, obj, mat); fz_dropobj(shd); if (error) return error; pdf_logshade("}\n"); } /* * Naked shading dictionary */ else { error = loadshadedict(shadep, xref, dict, ref, fz_identity()); if (error) return error; } error = pdf_storeitem(xref->store, PDF_KSHADE, ref, *shadep); if (error) { fz_dropshade(*shadep); return error; } return nil; }
static fz_error * loadcidfont(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref, fz_obj *encoding, fz_obj *tounicode) { fz_error *error; fz_obj *widths = nil; fz_obj *descriptor; pdf_font *font; FT_Face face; fz_irect bbox; int kind; char collection[256]; char *basefont; int i, k; /* * Get font name and CID collection */ basefont = fz_toname(fz_dictgets(dict, "BaseFont")); { fz_obj *cidinfo; fz_obj *obj; char tmpstr[64]; int tmplen; cidinfo = fz_dictgets(dict, "CIDSystemInfo"); error = pdf_resolve(&cidinfo, xref); if (error) return fz_rethrow(error, "cannot find CIDSystemInfo"); obj = fz_dictgets(cidinfo, "Registry"); tmplen = MIN(sizeof tmpstr - 1, fz_tostrlen(obj)); memcpy(tmpstr, fz_tostrbuf(obj), tmplen); tmpstr[tmplen] = '\0'; strlcpy(collection, tmpstr, sizeof collection); 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'; strlcat(collection, tmpstr, sizeof collection); fz_dropobj(cidinfo); } /* * Load font file */ font = pdf_newfont(basefont); if (!font) return fz_outofmem; pdf_logfont("load cid font %d %d (%p) {\n", fz_tonum(ref), fz_togen(ref), font); pdf_logfont("basefont %s\n", basefont); pdf_logfont("collection %s\n", collection); descriptor = fz_dictgets(dict, "FontDescriptor"); if (descriptor) error = pdf_loadfontdescriptor(font, xref, descriptor, collection); else error = fz_throw("syntaxerror: missing font descriptor"); if (error) goto cleanup; face = 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((fz_font*)font, -1000, -1000, 2000, 2000); else fz_setfontbbox((fz_font*)font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* * Encoding */ if (fz_isname(encoding)) { pdf_logfont("encoding /%s\n", fz_toname(encoding)); if (!strcmp(fz_toname(encoding), "Identity-H")) error = pdf_newidentitycmap(&font->encoding, 0, 2); else if (!strcmp(fz_toname(encoding), "Identity-V")) error = pdf_newidentitycmap(&font->encoding, 1, 2); else error = pdf_loadsystemcmap(&font->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(&font->encoding, xref, encoding); } else { error = fz_throw("syntaxerror: font missing encoding"); } if (error) goto cleanup; fz_setfontwmode((fz_font*)font, pdf_getwmode(font->encoding)); pdf_logfont("wmode %d\n", pdf_getwmode(font->encoding)); if (kind == TRUETYPE) { fz_obj *cidtogidmap; cidtogidmap = fz_dictgets(dict, "CIDToGIDMap"); if (fz_isindirect(cidtogidmap)) { unsigned short *map; fz_buffer *buf; int len; pdf_logfont("cidtogidmap stream\n"); error = pdf_loadstream(&buf, xref, fz_tonum(cidtogidmap), fz_togen(cidtogidmap)); if (error) goto cleanup; len = (buf->wp - buf->rp) / 2; map = fz_malloc(len * sizeof(unsigned short)); if (!map) { fz_dropbuffer(buf); error = fz_outofmem; goto cleanup; } for (i = 0; i < len; i++) map[i] = (buf->rp[i * 2] << 8) + buf->rp[i * 2 + 1]; font->ncidtogid = len; font->cidtogid = map; 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 (font->substitute) { int e; pdf_logfont("emulate ttf cidfont\n"); e = FT_Select_Charmap(face, ft_encoding_unicode); if (e) return fz_throw("fonterror: no unicode cmap when emulating CID font"); if (!strcmp(collection, "Adobe-CNS1")) error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-CNS1-UCS2"); else if (!strcmp(collection, "Adobe-GB1")) error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-GB1-UCS2"); else if (!strcmp(collection, "Adobe-Japan1")) error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-Japan1-UCS2"); else if (!strcmp(collection, "Adobe-Japan2")) error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-Japan2-UCS2"); else if (!strcmp(collection, "Adobe-Korea1")) error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-Korea1-UCS2"); else error = fz_okay; if (error) return fz_rethrow(error, "cannot load system cmap %s", collection); } } error = pdf_loadtounicode(font, xref, nil, collection, tounicode); if (error) goto cleanup; /* * Horizontal */ fz_setdefaulthmtx((fz_font*)font, fz_toint(fz_dictgets(dict, "DW"))); widths = fz_dictgets(dict, "W"); if (widths) { int c0, c1, w; fz_obj *obj; error = pdf_resolve(&widths, xref); if (error) goto cleanup; 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)); error = fz_addhmtx((fz_font*)font, c0 + k, c0 + k, w); if (error) goto cleanup; } i += 2; } else { c1 = fz_toint(obj); w = fz_toint(fz_arrayget(widths, i + 2)); error = fz_addhmtx((fz_font*)font, c0, c1, w); if (error) goto cleanup; i += 3; } } fz_dropobj(widths); } error = fz_endhmtx((fz_font*)font); if (error) goto cleanup; /* * Vertical */ if (pdf_getwmode(font->encoding) == 1) { fz_obj *obj; 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)); } fz_setdefaultvmtx((fz_font*)font, dw2y, dw2w); widths = fz_dictgets(dict, "W2"); if (widths) { int c0, c1, w, x, y, k; error = pdf_resolve(&widths, xref); if (error) goto cleanup; 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)); error = fz_addvmtx((fz_font*)font, c0 + k, c0 + k, x, y, w); if (error) goto cleanup; } 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)); error = fz_addvmtx((fz_font*)font, c0, c1, x, y, w); if (error) goto cleanup; i += 5; } } fz_dropobj(widths); } error = fz_endvmtx((fz_font*)font); if (error) goto cleanup; } pdf_logfont("}\n"); *fontp = font; return fz_okay; cleanup: if (widths) fz_dropobj(widths); fz_dropfont((fz_font*)font); return fz_rethrow(error, "cannot load cid font"); }
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 (%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] = FT_Get_Char_Index(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) { int j; /* TODO: this is horribly slow */ for (j = 0; j < 256; j++) { if (ebuffer[j][0] && !strcmp(s, ebuffer[j])) { etable[i] = j; break; } } } /* TODO: should this really be here? */ if (ebuffer[i][0]) estrings[i] = ebuffer[i]; } } } fz_dropobj(encoding); } else { pdf_logfont("encode builtin\n"); for (i = 0; i < 256; i++) { etable[i] = ftcharindex(face, i); FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32); if (ebuffer[i][0]) estrings[i] = ebuffer[i]; } } error = pdf_newidentitycmap(&font->encoding, 0, 1); if (error) goto cleanup; font->ncidtogid = 256; font->cidtogid = etable; error = pdf_loadtounicode(font, xref, estrings, nil, fz_dictgets(dict, "ToUnicode")); if (error) goto cleanup; /* * Widths */ fz_setdefaulthmtx((fz_font*)font, font->missingwidth); widths = fz_dictgets(dict, "Widths"); if (widths) { int first, last; error = pdf_resolve(&widths, xref); if (error) goto cleanup; 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 = fz_addhmtx((fz_font*)font, i + first, i + first, wid); if (error) goto cleanup; } fz_dropobj(widths); } else { FT_Set_Char_Size(face, 1000, 1000, 72, 72); for (i = 0; i < 256; i++) { error = fz_addhmtx((fz_font*)font, i, i, ftwidth(font, i)); if (error) goto cleanup; } } error = fz_endhmtx((fz_font*)font); if (error) goto cleanup; pdf_logfont("}\n"); *fontp = font; return fz_okay; cleanup: fz_free(etable); if (widths) fz_dropobj(widths); fz_dropfont((fz_font*)font); return fz_rethrow(error, "cannot load simple font"); }
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 * loadnametreenode(fz_obj *tree, pdf_xref *xref, fz_obj *node) { fz_error *error; fz_obj *names; fz_obj *kids; fz_obj *key; fz_obj *val; int i, len; error = pdf_resolve(&node, xref); if (error) return error; names = fz_dictgets(node, "Names"); if (names) { error = pdf_resolve(&names, xref); if (error) goto cleanup; len = fz_arraylen(names) / 2; for (i = 0; i < len; ++i) { key = fz_arrayget(names, i * 2 + 0); val = fz_arrayget(names, i * 2 + 1); error = fz_dictput(tree, key, val); if (error) { fz_dropobj(names); goto cleanup; } } fz_dropobj(names); } kids = fz_dictgets(node, "Kids"); if (kids) { error = pdf_resolve(&kids, xref); if (error) goto cleanup; len = fz_arraylen(kids); for (i = 0; i < len; ++i) { error = loadnametreenode(tree, xref, fz_arrayget(kids, i)); if (error) { fz_dropobj(kids); goto cleanup; } } fz_dropobj(kids); } fz_dropobj(node); return nil; cleanup: fz_dropobj(node); return error; }
fz_error * pdf_loadlink(pdf_link **linkp, pdf_xref *xref, fz_obj *dict) { fz_error *error; pdf_link *link; fz_obj *dest; fz_obj *action; fz_obj *obj; fz_rect bbox; pdf_linkkind kind; pdf_logpage("load link {\n"); link = nil; 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) { error = pdf_resolve(&obj, xref); if (error) return error; dest = resolvedest(xref, obj); pdf_logpage("dest %d %d R\n", fz_tonum(dest), fz_togen(dest)); fz_dropobj(obj); } kind = PDF_LUNKNOWN; action = fz_dictgets(dict, "A"); if (action) { error = pdf_resolve(&action, xref); if (error) return error; obj = fz_dictgets(action, "S"); if (!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 (!strcmp(fz_toname(obj), "URI")) { kind = PDF_LURI; dest = fz_dictgets(action, "URI"); pdf_logpage("action uri %s\n", fz_tostrbuf(dest)); } else pdf_logpage("action ... ?\n"); fz_dropobj(action); } pdf_logpage("}\n"); if (dest) { error = pdf_newlink(&link, bbox, dest, kind); if (error) return error; *linkp = link; } return nil; }
fz_error* processErrorPage( soPdfFile* inFile, fz_obj *pageObj, int pageNo, fz_rect *bbRect, fz_error *error ) { // Wrap the error error = fz_rethrow(error, "Cannot process page %d", pageNo + 1); // If we are not supposed to proceed with error then it ends if (p_proceedWithErrors == false) return error; // Save the error in the list if (g_errorCount >= MAX_ERRORS_BEFORE_STOP) return soPdfErrorList(error); g_errorList[g_errorCount++] = error; // Get the box for the page fz_obj *obj = fz_dictgets(pageObj, "CropBox"); if (!obj) obj = fz_dictgets(pageObj, "MediaBox"); error = pdf_resolve(&obj, inFile->xref); if (error) return fz_rethrow(error, "Cannot proceed with error %d", pageNo + 1); if (!fz_isarray(obj)) return fz_throw("Cannot find page bounds : %d", pageNo + 1); fz_rect bbox = pdf_torect(obj); fz_rect mediaBox; mediaBox.x0 = MIN(bbox.x0, bbox.x1); mediaBox.y0 = MIN(bbox.y0, bbox.y1); mediaBox.x1 = MAX(bbox.x0, bbox.x1); mediaBox.y1 = MAX(bbox.y0, bbox.y1); float mbHeight = mediaBox.y1 - mediaBox.y0; switch(p_mode) { case FitHeight: case FitWidth: bbRect[0] = mediaBox; break; case Fit2xHeight: case Fit2xWidth: { float overlap = (mbHeight * (float)(p_overlap / 100)) / 2; bbRect[0] = mediaBox; bbRect[0].y0 = bbRect[0].y0 + (float)(0.5 * mbHeight) - overlap; bbRect[1] = mediaBox; bbRect[1].y1 = bbRect[1].y1 - (float)(0.5 * mbHeight) + overlap; } break; case SmartFitHeight: case SmartFitWidth: default: return fz_throw("Mode(%d) not yet implemented.", p_mode); break; } return NULL; }
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; }
static fz_error * loadshadedict(fz_shade **shadep, pdf_xref *xref, fz_obj *dict, fz_obj *ref, fz_matrix matrix) { fz_error *error; fz_shade *shade; fz_obj *obj; int type; int i; pdf_logshade("load shade dict %d %d {\n", fz_tonum(ref), fz_togen(ref)); shade = fz_malloc(sizeof(fz_shade)); if (!shade) return fz_outofmem; shade->refs = 1; shade->usebackground = 0; shade->usefunction = 0; shade->matrix = matrix; shade->bbox = fz_infiniterect; shade->meshlen = 0; shade->meshcap = 0; shade->mesh = nil; obj = fz_dictgets(dict, "ShadingType"); type = fz_toint(obj); pdf_logshade("type %d\n", type); /* TODO: flatten indexed... */ obj = fz_dictgets(dict, "ColorSpace"); if (obj) { shade->cs = pdf_finditem(xref->store, PDF_KCOLORSPACE, obj); if (shade->cs) fz_keepcolorspace(shade->cs); else { error = pdf_resolve(&obj, xref); if (error) return error; error = pdf_loadcolorspace(&shade->cs, xref, obj); if (error) return error; fz_dropobj(obj); } } pdf_logshade("colorspace %s\n", shade->cs->name); obj = fz_dictgets(dict, "Background"); if (obj) { pdf_logshade("background\n"); shade->usebackground = 1; for (i = 0; i < shade->cs->n; i++) shade->background[i] = fz_toreal(fz_arrayget(obj, i)); } obj = fz_dictgets(dict, "BBox"); if (fz_isarray(obj)) { shade->bbox = pdf_torect(obj); pdf_logshade("bbox [%g %g %g %g]\n", shade->bbox.x0, shade->bbox.y0, shade->bbox.x1, shade->bbox.y1); } switch(type) { case 1: error = pdf_loadtype1shade(shade, xref, dict, ref); if (error) goto cleanup; break; case 2: error = pdf_loadtype2shade(shade, xref, dict, ref); if (error) goto cleanup; break; case 3: error = pdf_loadtype3shade(shade, xref, dict, ref); if (error) goto cleanup; break; case 4: error = pdf_loadtype4shade(shade, xref, dict, ref); if (error) goto cleanup; break; case 5: error = pdf_loadtype5shade(shade, xref, dict, ref); if (error) goto cleanup; break; case 6: error = pdf_loadtype6shade(shade, xref, dict, ref); if (error) goto cleanup; break; case 7: error = pdf_loadtype7shade(shade, xref, dict, ref); if (error) goto cleanup; break; default: fz_warn("syntaxerror: unknown shading type: %d", type); break; }; pdf_logshade("}\n"); *shadep = shade; return nil; cleanup: fz_dropshade(shade); return error; }
static fz_error * loadcalrgb(fz_colorspace **csp, pdf_xref *xref, fz_obj *dict) { fz_error *error; struct calrgb *cs; fz_obj *tmp; int i; error = pdf_resolve(&dict, xref); if (error) return error; cs = fz_malloc(sizeof(struct calrgb)); if (!cs) return fz_outofmem; pdf_logrsrc("load CalRGB\n"); initcs((fz_colorspace*)cs, "CalRGB", 3, rgbtoxyz, xyztorgb, nil); cs->white[0] = 1.0; cs->white[1] = 1.0; cs->white[2] = 1.0; cs->black[0] = 0.0; cs->black[1] = 0.0; cs->black[2] = 0.0; cs->gamma[0] = 1.0; cs->gamma[1] = 1.0; cs->gamma[2] = 1.0; cs->matrix[0] = 1.0; cs->matrix[1] = 0.0; cs->matrix[2] = 0.0; cs->matrix[3] = 0.0; cs->matrix[4] = 1.0; cs->matrix[5] = 0.0; cs->matrix[6] = 0.0; cs->matrix[7] = 0.0; cs->matrix[8] = 1.0; tmp = fz_dictgets(dict, "WhitePoint"); if (fz_isarray(tmp)) { cs->white[0] = fz_toreal(fz_arrayget(tmp, 0)); cs->white[1] = fz_toreal(fz_arrayget(tmp, 1)); cs->white[2] = fz_toreal(fz_arrayget(tmp, 2)); } tmp = fz_dictgets(dict, "BlackPoint"); if (fz_isarray(tmp)) { cs->black[0] = fz_toreal(fz_arrayget(tmp, 0)); cs->black[1] = fz_toreal(fz_arrayget(tmp, 1)); cs->black[2] = fz_toreal(fz_arrayget(tmp, 2)); } tmp = fz_dictgets(dict, "Gamma"); if (fz_isarray(tmp)) { cs->gamma[0] = fz_toreal(fz_arrayget(tmp, 0)); cs->gamma[1] = fz_toreal(fz_arrayget(tmp, 1)); cs->gamma[2] = fz_toreal(fz_arrayget(tmp, 2)); } tmp = fz_dictgets(dict, "Matrix"); if (fz_isarray(tmp)) { for (i = 0; i < 9; i++) cs->matrix[i] = fz_toreal(fz_arrayget(tmp, i)); } fz_invert3x3(cs->invmat, cs->matrix); fz_dropobj(dict); *csp = (fz_colorspace*) cs; return nil; }
/* * Construct a filter to decode a stream, constraining * to stream length and decrypting. */ static fz_error * pdf_buildfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int oid, int gen) { fz_error *error; fz_filter *base, *pipe, *tmp; fz_obj *filters; fz_obj *params; error = buildrawfilter(&base, xref, stmobj, oid, gen); if (error) return fz_rethrow(error, "cannot create raw filter chain"); filters = fz_dictgetsa(stmobj, "Filter", "F"); params = fz_dictgetsa(stmobj, "DecodeParms", "DP"); if (filters) { error = pdf_resolve(&filters, xref); if (error) { error = fz_rethrow(error, "cannot resolve stream /Filter"); goto cleanup0; } if (params) { error = pdf_resolve(¶ms, xref); if (error) { error = fz_rethrow(error, "cannot resolve stream /DecodeParms"); goto cleanup1; } } if (fz_isname(filters)) { error = buildonefilter(&tmp, filters, params); if (error) { error = fz_rethrow(error, "cannot create filter"); goto cleanup2; } error = fz_newpipeline(&pipe, base, tmp); fz_dropfilter(base); fz_dropfilter(tmp); if (error) { error = fz_rethrow(error, "cannot create filter pipeline"); goto cleanup2; } } else { error = buildfilterchain(&pipe, base, filters, params); if (error) { error = fz_rethrow(error, "cannot create filter chain"); goto cleanup2; } } if (params) fz_dropobj(params); fz_dropobj(filters); *filterp = pipe; } else { *filterp = base; } return fz_okay; cleanup2: if (params) fz_dropobj(params); cleanup1: fz_dropobj(filters); cleanup0: fz_dropfilter(base); return error; /* already rethrown */ }
fz_error * pdf_loadtype3font(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref) { fz_error *error; char buf[256]; char *estrings[256]; pdf_font *font; fz_obj *encoding; fz_obj *widths; fz_obj *resources; fz_obj *charprocs; fz_obj *obj; int first, last; int i, k, n; fz_rect bbox; obj = fz_dictgets(dict, "Name"); if (obj) strlcpy(buf, fz_toname(obj), sizeof buf); else sprintf(buf, "Unnamed-T3"); font = pdf_newfont(buf); if (!font) return fz_throw("outofmem: font struct"); pdf_logfont("load type3 font %d %d (%p) {\n", fz_tonum(ref), fz_togen(ref), font); pdf_logfont("name %s\n", buf); font->super.render = t3render; font->super.drop = (void(*)(fz_font*)) t3dropfont; obj = fz_dictgets(dict, "FontMatrix"); font->matrix = pdf_tomatrix(obj); pdf_logfont("matrix [%g %g %g %g %g %g]\n", font->matrix.a, font->matrix.b, font->matrix.c, font->matrix.d, font->matrix.e, font->matrix.f); obj = fz_dictgets(dict, "FontBBox"); bbox = pdf_torect(obj); pdf_logfont("bbox [%g %g %g %g]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1); bbox = fz_transformaabb(font->matrix, bbox); bbox.x0 = fz_floor(bbox.x0 * 1000); bbox.y0 = fz_floor(bbox.y0 * 1000); bbox.x1 = fz_ceil(bbox.x1 * 1000); bbox.y1 = fz_ceil(bbox.y1 * 1000); fz_setfontbbox((fz_font*)font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* * Encoding */ for (i = 0; i < 256; i++) estrings[i] = nil; encoding = fz_dictgets(dict, "Encoding"); if (!encoding) { error = fz_throw("syntaxerror: Type3 font missing Encoding"); goto cleanup; } error = pdf_resolve(&encoding, xref); if (error) goto cleanup; if (fz_isname(obj)) 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; } } } fz_dropobj(encoding); error = pdf_newidentitycmap(&font->encoding, 0, 1); if (error) goto cleanup; error = pdf_loadtounicode(font, xref, estrings, nil, fz_dictgets(dict, "ToUnicode")); if (error) goto cleanup; /* * Widths */ fz_setdefaulthmtx((fz_font*)font, 0); first = fz_toint(fz_dictgets(dict, "FirstChar")); last = fz_toint(fz_dictgets(dict, "LastChar")); widths = fz_dictgets(dict, "Widths"); if (!widths) { error = fz_throw("syntaxerror: Type3 font missing Widths"); goto cleanup; } error = pdf_resolve(&widths, xref); if (error) goto cleanup; for (i = first; i <= last; i++) { float w = fz_toreal(fz_arrayget(widths, i - first)); w = font->matrix.a * w * 1000.0; error = fz_addhmtx((fz_font*)font, i, i, w); if (error) { fz_dropobj(widths); goto cleanup; } } fz_dropobj(widths); error = fz_endhmtx((fz_font*)font); if (error) goto cleanup; /* * Resources */ resources = nil; obj = fz_dictgets(dict, "Resources"); if (obj) { error = pdf_resolve(&obj, xref); if (error) goto cleanup; error = pdf_loadresources(&resources, xref, obj); fz_dropobj(obj); if (error) goto cleanup; } else pdf_logfont("no resource dict!\n"); /* * CharProcs */ charprocs = fz_dictgets(dict, "CharProcs"); if (!charprocs) { error = fz_throw("syntaxerror: Type3 font missing CharProcs"); goto cleanup2; } error = pdf_resolve(&charprocs, xref); if (error) goto cleanup2; for (i = 0; i < 256; i++) { if (estrings[i]) { obj = fz_dictgets(charprocs, estrings[i]); if (obj) { pdf_logfont("load charproc %s {\n", estrings[i]); error = loadcharproc(&font->charprocs[i], xref, resources, obj); if (error) goto cleanup2; error = fz_optimizetree(font->charprocs[i]); if (error) goto cleanup2; pdf_logfont("}\n"); } } } fz_dropobj(charprocs); if (resources) fz_dropobj(resources); pdf_logfont("}\n"); *fontp = font; return fz_okay; cleanup2: if (resources) fz_dropobj(resources); cleanup: fz_dropfont((fz_font*)font); return fz_rethrow(error, "cannot load type3 font"); }