static fz_error pdf_loadpagecontents(fz_buffer **bufp, pdf_xref *xref, fz_obj *obj) { fz_error error; if (fz_isarray(obj)) { error = pdf_loadpagecontentsarray(bufp, xref, obj); if (error) return fz_rethrow(error, "cannot load content stream array (%d 0 R)", fz_tonum(obj)); } else if (pdf_isstream(xref, fz_tonum(obj), fz_togen(obj))) { error = pdf_loadstream(bufp, xref, fz_tonum(obj), fz_togen(obj)); if (error) return fz_rethrow(error, "cannot load content stream (%d 0 R)", fz_tonum(obj)); } else { fz_warn("page contents missing, leaving page blank"); *bufp = fz_newbuffer(0); } return fz_okay; }
static void sweepref(fz_obj *obj) { int num = fz_tonum(obj); int gen = fz_togen(obj); if (num < 0 || num >= xref->len) return; if (uselist[num]) return; uselist[num] = 1; /* Bake in /Length in stream objects */ if (pdf_isstream(xref, num, gen)) { fz_obj *len = fz_dictgets(obj, "Length"); if (fz_isindirect(len)) { uselist[fz_tonum(len)] = 0; len = fz_resolveindirect(len); fz_dictputs(obj, "Length", len); } } sweepobj(fz_resolveindirect(obj)); }
static fz_error loadcharproc(fz_tree **treep, pdf_xref *xref, fz_obj *rdb, fz_obj *stmref) { fz_error error; pdf_csi *csi; fz_stream *stm; error = pdf_newcsi(&csi, 1); if (error) return fz_rethrow(error, "cannot create interpreter"); error = pdf_openstream(&stm, xref, fz_tonum(stmref), fz_togen(stmref)); if (error) { pdf_dropcsi(csi); return fz_rethrow(error, "cannot open glyph content stream"); } error = pdf_runcsi(csi, xref, rdb, stm); if (error) { fz_dropstream(stm); pdf_dropcsi(csi); return fz_rethrow(error, "cannot interpret glyph content stream (%d %d R)", fz_tonum(stmref), fz_togen(stmref)); } *treep = csi->tree; csi->tree = nil; fz_dropstream(stm); pdf_dropcsi(csi); return fz_okay; }
void pdf_storeitem(pdf_store *store, pdf_itemkind kind, fz_obj *key, void *val) { pdf_item *item; item = fz_malloc(sizeof(pdf_item)); item->kind = kind; item->key = fz_keepobj(key); item->val = val; item->age = 0; item->next = nil; if (fz_isindirect(key)) { struct refkey refkey; pdf_logrsrc("store item %s (%d %d R) ptr=%p\n", kindstr(kind), fz_tonum(key), fz_togen(key), val); refkey.kind = kind; refkey.oid = fz_tonum(key); refkey.gen = fz_togen(key); fz_hashinsert(store->hash, &refkey, item); } else { pdf_logrsrc("store item %s: ... = %p\n", kindstr(kind), val); item->next = store->root; store->root = item; } keepitem(kind, val); }
fz_error pdf_loadembeddedfont(pdf_fontdesc *fontdesc, pdf_xref *xref, fz_obj *stmref) { fz_error error; fz_buffer *buf; pdf_logfont("load embedded font\n"); error = pdf_loadstream(&buf, xref, fz_tonum(stmref), fz_togen(stmref)); if (error) return fz_rethrow(error, "cannot load font stream (%d %d R)", fz_tonum(stmref), fz_togen(stmref)); error = fz_newfontfrombuffer(&fontdesc->font, buf->data, buf->len, 0); if (error) { fz_dropbuffer(buf); return fz_rethrow(error, "cannot load embedded font (%d %d R)", fz_tonum(stmref), fz_togen(stmref)); } fontdesc->buffer = buf->data; /* save the buffer so we can free it later */ fz_free(buf); /* only free the fz_buffer struct, not the contained data */ fontdesc->isembedded = 1; 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_findpageobject(pdf_xref *xref, fz_obj *page) { int num = fz_tonum(page); int gen = fz_togen(page); int i; for (i = 0; i < xref->pagelen; i++) if (num == fz_tonum(xref->pagerefs[i]) && gen == fz_togen(xref->pagerefs[i])) return i + 1; return 0; }
int epdf_index_item_page_get(const Epdf_Document *doc, const Epdf_Index_Item *item) { fz_obj *dest; int p; int n; int g; if (!item || !item->link) return -1; if (PDF_LGOTO != item->link->kind) return -1; dest = item->link->dest; p = 0; if (fz_isint(dest)) { p = fz_toint(dest); return p; } if (fz_isdict(dest)) { /* The destination is linked from a Go-To action's D array */ fz_obj *D; D = fz_dictgets(dest, "D"); if (D && fz_isarray(D)) dest = fz_arrayget(D, 0); } n = fz_tonum(dest); g = fz_togen(dest); for (p = 1; p <= epdf_document_page_count_get(doc); p++) { fz_obj *page; int np; int gp; page = pdf_getpageobject(doc->xref, p); if (!page) continue; np = fz_tonum(page); gp = fz_togen(page); if (n == np && g == gp) return p-1; } return 0; }
fz_error * pdf_storeitem(pdf_store *store, pdf_itemkind kind, fz_obj *key, void *val) { fz_error *error; switch (kind) { case PDF_KCOLORSPACE: fz_keepcolorspace(val); break; case PDF_KFUNCTION: pdf_keepfunction(val); break; case PDF_KXOBJECT: pdf_keepxobject(val); break; case PDF_KIMAGE: fz_keepimage(val); break; case PDF_KPATTERN: pdf_keeppattern(val); break; case PDF_KSHADE: fz_keepshade(val); break; case PDF_KCMAP: pdf_keepcmap(val); break; case PDF_KFONT: fz_keepfont(val); break; } if (fz_isindirect(key)) { struct refkey item; pdf_logrsrc("store item %d: %d %d R = %p\n", kind, fz_tonum(key), fz_togen(key), val); item.kind = kind; item.oid = fz_tonum(key); item.gen = fz_togen(key); error = fz_hashinsert(store->hash, &item, val); if (error) return error; } else { pdf_item *item; item = fz_malloc(sizeof(pdf_item)); if (!item) return fz_outofmem; pdf_logrsrc("store item %d: ... = %p\n", kind, val); item->kind = kind; item->key = fz_keepobj(key); item->val = val; item->next = store->root; store->root = item; } return nil; }
static fz_error gathershadings(int page, fz_obj *pageobj, fz_obj *dict) { int i; for (i = 0; i < fz_dictlen(dict); i++) { fz_obj *ref; fz_obj *shade; fz_obj *type; int k; shade = ref = fz_dictgetval(dict, i); if (!fz_isdict(shade)) return fz_throw("not a shading dict (%d %d R)", fz_tonum(ref), fz_togen(ref)); type = fz_dictgets(shade, "ShadingType"); if (!fz_isint(type) || fz_toint(type) < 1 || fz_toint(type) > 7) { fz_warn("not a shading type (%d %d R)", fz_tonum(ref), fz_togen(ref)); type = nil; } for (k = 0; k < shadings; k++) if (fz_tonum(shading[k]->ref) == fz_tonum(ref) && fz_togen(shading[k]->ref) == fz_togen(ref)) break; if (k < shadings) continue; shadings++; shading = fz_realloc(shading, shadings * sizeof (struct info *)); if (!shading) return fz_throw("out of memory"); shading[shadings - 1] = fz_malloc(sizeof (struct info)); if (!shading[shadings - 1]) return fz_throw("out of memory"); shading[shadings - 1]->page = page; shading[shadings - 1]->pageobj = pageobj; shading[shadings - 1]->ref = ref; shading[shadings - 1]->u.shading.type = type; } return fz_okay; }
fz_error * pdf_loadembeddedfont(pdf_font *font, pdf_xref *xref, fz_obj *stmref) { fz_error *error; int fterr; FT_Face face; fz_buffer *buf; error = initfontlibs(); if (error) return fz_rethrow(error, "cannot init font libraries"); pdf_logfont("load embedded font\n"); error = pdf_loadstream(&buf, xref, fz_tonum(stmref), fz_togen(stmref)); if (error) return fz_rethrow(error, "cannot load font stream"); fterr = FT_New_Memory_Face(ftlib, buf->rp, buf->wp - buf->rp, 0, &face); if (fterr) { fz_dropbuffer(buf); return fz_throw("freetype: cannot load embedded font: %s", ft_errstr(fterr)); } font->ftface = face; font->fontdata = buf; return fz_okay; }
static void evictitem(pdf_item *item) { pdf_logrsrc("evicting item %s (%d %d R) at age %d\n", kindstr(item->kind), fz_tonum(item->key), fz_togen(item->key), item->age); fz_dropobj(item->key); dropitem(item->kind, item->val); fz_free(item); }
void * pdf_finditem(pdf_store *store, pdf_itemkind kind, fz_obj *key) { pdf_item *item; struct refkey refkey; if (key == nil) return nil; if (fz_isindirect(key)) { refkey.kind = kind; refkey.oid = fz_tonum(key); refkey.gen = fz_togen(key); item = fz_hashfind(store->hash, &refkey); if (item) { item->age = 0; return item->val; } } else { for (item = store->root; item; item = item->next) if (item->kind == kind && !fz_objcmp(item->key, key)) { item->age = 0; return item->val; } } return nil; }
fz_error * pdf_loadembeddedfont(pdf_font *font, pdf_xref *xref, fz_obj *stmref) { fz_error *error; int fterr; FT_Face face; fz_buffer *buf; error = initfontlibs(); if (error) return error; pdf_logfont("load embedded font\n"); error = pdf_loadstream(&buf, xref, fz_tonum(stmref), fz_togen(stmref)); if (error) return error; fterr = FT_New_Memory_Face(ftlib, buf->rp, buf->wp - buf->rp, 0, &face); if (fterr) { fz_free(buf); return fz_throw("freetype could not load embedded font: %s", pdf_fterrorstring(fterr)); } font->ftface = face; font->fontdata = buf; return nil; }
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; }
void pdf_removeitem(pdf_store *store, pdf_itemkind kind, fz_obj *key) { pdf_item *item, *prev; struct refkey refkey; if (key == nil) return; if (fz_isindirect(key)) { refkey.kind = kind; refkey.oid = fz_tonum(key); refkey.gen = fz_togen(key); item = fz_hashfind(store->hash, &refkey); if (!item) return; fz_hashremove(store->hash, &refkey); pdf_logrsrc("remove item %s (%d %d R) ptr=%p\n", kindstr(kind), fz_tonum(key), fz_togen(key), item->val); dropitem(kind, item->val); fz_dropobj(item->key); fz_free(item); } else { prev = nil; for (item = store->root; item; item = item->next) { if (item->kind == kind && !fz_objcmp(item->key, key)) { if (!prev) store->root = item->next; else prev->next = item->next; dropitem(kind, item->val); fz_dropobj(item->key); fz_free(item); break; } prev = item; } } }
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; }
static void printglobalinfo(void) { printf("\nPDF-%d.%d\n", xref->version / 10, xref->version % 10); if (info->u.info.obj) { printf("Info object (%d %d R):\n", fz_tonum(info->ref), fz_togen(info->ref)); fz_debugobj(fz_resolveindirect(info->u.info.obj)); } if (cryptinfo->u.crypt.obj) { printf("\nEncryption object (%d %d R):\n", fz_tonum(cryptinfo->ref), fz_togen(cryptinfo->ref)); fz_debugobj(cryptinfo->u.crypt.obj); } printf("\nPages: %d\n\n", pagecount); }
static void renumberobjs(void) { pdf_xrefentry *oldxref; int newlen; int num; /* Apply renumber map to indirect references in all objects in xref */ renumberobj(xref->trailer); for (num = 0; num < xref->len; num++) { fz_obj *obj = xref->table[num].obj; if (fz_isindirect(obj)) { obj = fz_newindirect(renumbermap[fz_tonum(obj)], 0, xref); pdf_updateobject(xref, num, 0, obj); fz_dropobj(obj); } else { renumberobj(obj); } } /* Create new table for the reordered, compacted xref */ oldxref = xref->table; xref->table = fz_calloc(xref->len, sizeof(pdf_xrefentry)); xref->table[0] = oldxref[0]; /* Move used objects into the new compacted xref */ newlen = 0; for (num = 1; num < xref->len; num++) { if (uselist[num]) { if (newlen < renumbermap[num]) newlen = renumbermap[num]; xref->table[renumbermap[num]] = oldxref[num]; } else { if (oldxref[num].obj) fz_dropobj(oldxref[num].obj); } } fz_free(oldxref); /* Update the used objects count in compacted xref */ xref->len = newlen + 1; /* Update list of used objects to fit with compacted xref */ for (num = 1; num < xref->len; num++) uselist[num] = 1; }
static void renumberobj(fz_obj *obj) { int i; if (fz_isdict(obj)) { for (i = 0; i < fz_dictlen(obj); i++) { fz_obj *key = fz_dictgetkey(obj, i); fz_obj *val = fz_dictgetval(obj, i); if (fz_isindirect(val)) { val = fz_newindirect(renumbermap[fz_tonum(val)], 0, xref); fz_dictput(obj, key, val); fz_dropobj(val); } else { renumberobj(val); } } } else if (fz_isarray(obj)) { for (i = 0; i < fz_arraylen(obj); i++) { fz_obj *val = fz_arrayget(obj, i); if (fz_isindirect(val)) { val = fz_newindirect(renumbermap[fz_tonum(val)], 0, xref); fz_arrayput(obj, i, val); fz_dropobj(val); } else { renumberobj(val); } } } }
void pdfapp_gotopage(pdfapp_t *app, fz_obj *obj) { int oid = fz_tonum(obj); int i; for (i = 0; i < pdf_getpagecount(app->pages); i++) { if (fz_tonum(app->pages->pref[i]) == oid) { if (app->histlen + 1 == 256) { memmove(app->hist, app->hist + 1, sizeof(int) * 255); app->histlen --; } app->hist[app->histlen++] = app->pageno; app->pageno = i + 1; pdfapp_showpage(app, 1, 1); return; } } }
fz_error pdf_loadimage(fz_pixmap **pixp, pdf_xref *xref, fz_obj *dict) { fz_error error; if ((*pixp = pdf_finditem(xref->store, fz_droppixmap, dict))) { fz_keeppixmap(*pixp); return fz_okay; } pdf_logimage("load image (%d 0 R) {\n", fz_tonum(dict)); error = pdf_loadimageimp(pixp, xref, nil, dict, nil, 0); if (error) return fz_rethrow(error, "cannot load image (%d 0 R)", fz_tonum(dict)); pdf_storeitem(xref->store, fz_keeppixmap, fz_droppixmap, dict, *pixp); pdf_logimage("}\n"); return fz_okay; }
static fz_error gatherdimensions(int page, fz_obj *pageobj) { fz_obj *ref; fz_rect bbox; fz_obj *obj; int j; obj = ref = fz_dictgets(pageobj, "MediaBox"); if (!fz_isarray(obj)) return fz_throw("cannot find page bounds (%d %d R)", fz_tonum(ref), fz_togen(ref)); bbox = pdf_torect(obj); for (j = 0; j < dims; j++) if (!memcmp(dim[j]->u.dim.bbox, &bbox, sizeof (fz_rect))) break; if (j < dims) return fz_okay; dims++; dim = fz_realloc(dim, dims * sizeof (struct info *)); if (!dim) return fz_throw("out of memory"); dim[dims - 1] = fz_malloc(sizeof (struct info)); if (!dim[dims - 1]) return fz_throw("out of memory"); dim[dims - 1]->u.dim.bbox = fz_malloc(sizeof (fz_rect)); if (!dim[dims - 1]->u.dim.bbox) return fz_throw("out of memory"); dim[dims - 1]->page = page; dim[dims - 1]->pageobj = pageobj; dim[dims - 1]->ref = nil; memcpy(dim[dims - 1]->u.dim.bbox, &bbox, sizeof (fz_rect)); return fz_okay; }
void editcopy(int pagenum) { fz_error *error; fz_obj *obj; fz_obj *ref; fz_obj *num; printf("copy %s page %d\n", srcname, pagenum); ref = srcpages->pref[pagenum - 1]; obj = pdf_getpageobject(srcpages, pagenum - 1); fz_dictdels(obj, "Parent"); /* fz_dictdels(obj, "B"); fz_dictdels(obj, "PieceInfo"); fz_dictdels(obj, "Metadata"); fz_dictdels(obj, "Annots"); fz_dictdels(obj, "Tabs"); */ pdf_updateobject(src, fz_tonum(ref), fz_togen(ref), obj); error = fz_arraypush(editobjects, ref); if (error) die(error); error = fz_newint(&num, editmode); if (error) die(error); error = fz_arraypush(editmodelist, num); if (error) die(error); fz_dropobj(num); }
static fz_error pdf_loadpagecontentsarray(fz_buffer **bigbufp, pdf_xref *xref, fz_obj *list) { fz_error error; fz_buffer *big; fz_buffer *one; int i; pdf_logpage("multiple content streams: %d\n", fz_arraylen(list)); /* TODO: openstream, read, close into big buffer at once */ big = fz_newbuffer(32 * 1024); for (i = 0; i < fz_arraylen(list); i++) { fz_obj *stm = fz_arrayget(list, i); error = pdf_loadstream(&one, xref, fz_tonum(stm), fz_togen(stm)); if (error) { fz_dropbuffer(big); return fz_rethrow(error, "cannot load content stream part %d/%d (%d %d R)", i + 1, fz_arraylen(list), fz_tonum(stm), fz_togen(stm)); } if (big->len + one->len + 1 > big->cap) fz_resizebuffer(big, big->len + one->len + 1); memcpy(big->data + big->len, one->data, one->len); big->data[big->len + one->len] = ' '; big->len += one->len + 1; fz_dropbuffer(one); } *bigbufp = big; return fz_okay; }
fz_error pdf_loadpattern(pdf_pattern **patp, pdf_xref *xref, fz_obj *dict) { fz_error error; pdf_pattern *pat; fz_obj *obj; if ((*patp = pdf_finditem(xref->store, pdf_droppattern, dict))) { pdf_keeppattern(*patp); return fz_okay; } pdf_logrsrc("load pattern (%d %d R) {\n", fz_tonum(dict), fz_togen(dict)); pat = fz_malloc(sizeof(pdf_pattern)); pat->refs = 1; pat->resources = nil; pat->contents = nil; /* Store pattern now, to avoid possible recursion if objects refer back to this one */ pdf_storeitem(xref->store, pdf_keeppattern, pdf_droppattern, dict, pat); pat->ismask = fz_toint(fz_dictgets(dict, "PaintType")) == 2; pat->xstep = fz_toreal(fz_dictgets(dict, "XStep")); pat->ystep = fz_toreal(fz_dictgets(dict, "YStep")); pdf_logrsrc("mask %d\n", pat->ismask); pdf_logrsrc("xstep %g\n", pat->xstep); pdf_logrsrc("ystep %g\n", pat->ystep); obj = fz_dictgets(dict, "BBox"); pat->bbox = pdf_torect(obj); pdf_logrsrc("bbox [%g %g %g %g]\n", pat->bbox.x0, pat->bbox.y0, pat->bbox.x1, pat->bbox.y1); obj = fz_dictgets(dict, "Matrix"); if (obj) pat->matrix = pdf_tomatrix(obj); else pat->matrix = fz_identity; pdf_logrsrc("matrix [%g %g %g %g %g %g]\n", pat->matrix.a, pat->matrix.b, pat->matrix.c, pat->matrix.d, pat->matrix.e, pat->matrix.f); pat->resources = fz_dictgets(dict, "Resources"); if (pat->resources) fz_keepobj(pat->resources); error = pdf_loadstream(&pat->contents, xref, fz_tonum(dict), fz_togen(dict)); if (error) { pdf_removeitem(xref->store, pdf_droppattern, dict); pdf_droppattern(pat); return fz_rethrow(error, "cannot load pattern stream (%d %d R)", fz_tonum(dict), fz_togen(dict)); } pdf_logrsrc("}\n"); *patp = pat; return fz_okay; }
static void retainpages(int argc, char **argv) { fz_error error; fz_obj *oldroot, *root, *pages, *kids, *countobj, *parent; /* Load the old page tree */ error = pdf_loadpagetree(xref); if (error) die(fz_rethrow(error, "cannot load page tree")); /* Keep only pages/type entry to avoid references to unretained pages */ oldroot = fz_dictgets(xref->trailer, "Root"); pages = fz_dictgets(oldroot, "Pages"); root = fz_newdict(2); fz_dictputs(root, "Type", fz_dictgets(oldroot, "Type")); fz_dictputs(root, "Pages", fz_dictgets(oldroot, "Pages")); pdf_updateobject(xref, fz_tonum(oldroot), fz_togen(oldroot), root); fz_dropobj(root); /* Create a new kids array with only the pages we want to keep */ parent = fz_newindirect(fz_tonum(pages), fz_togen(pages), xref); kids = fz_newarray(1); /* Retain pages specified */ while (argc - fz_optind) { int page, spage, epage; char *spec, *dash; char *pagelist = argv[fz_optind]; spec = fz_strsep(&pagelist, ","); while (spec) { dash = strchr(spec, '-'); if (dash == spec) spage = epage = pdf_getpagecount(xref); else spage = epage = atoi(spec); if (dash) { if (strlen(dash) > 1) epage = atoi(dash + 1); else epage = pdf_getpagecount(xref); } if (spage > epage) page = spage, spage = epage, epage = page; if (spage < 1) spage = 1; if (epage > pdf_getpagecount(xref)) epage = pdf_getpagecount(xref); for (page = spage; page <= epage; page++) { fz_obj *pageobj = pdf_getpageobject(xref, page); fz_obj *pageref = pdf_getpageref(xref, page); fz_dictputs(pageobj, "Parent", parent); /* Store page object in new kids array */ fz_arraypush(kids, pageref); } spec = fz_strsep(&pagelist, ","); } fz_optind++; } fz_dropobj(parent); /* Update page count and kids array */ countobj = fz_newint(fz_arraylen(kids)); fz_dictputs(pages, "Count", countobj); fz_dropobj(countobj); fz_dictputs(pages, "Kids", kids); fz_dropobj(kids); }
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; }
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; }
int copyPdfFile( soPdfFile* inFile, soPdfFile* outFile ) { fz_error *error; int pageTreeNum, pageTreeGen; assert(inFile != NULL); assert(outFile != NULL); // // Process every page in the source file // { printf("\nProcessing input page : "); for (int pageNo = 0; pageNo < pdf_getpagecount(inFile->pageTree); pageNo++) { displayPageNumber(pageNo + 1, !pageNo); // Get the page object from the source fz_obj *pageRef = inFile->pageTree->pref[pageNo]; fz_obj *pageObj = pdf_getpageobject(inFile->pageTree, pageNo); // // Process the page. Each page can be split into up-to 3 pages // fz_rect bbRect[3]; error = processPage(inFile, pageNo, bbRect, 3); if (error) return soPdfError(error); for (int ctr = 0; ctr < 3; ctr++) { // Check if this was a blank page if (fz_isemptyrect(bbRect[ctr])) break; // // copy the source page dictionary entry. The way this is done is basically // by making a copy of the page dict object in the source file, and adding // the copy in the source file. Then the copied page dict object is // referenced and added to the destination file. // // This convoluted procedure is done because the copy is done by pdf_transplant // function that accepts a source and destination. Whatever is referenced by // destination object is deep copied // // allocate an object id and generation id in source file // // There is a bug in mupdf where the object allocation returns // 0 oid and 0 gid when the input pdf file has iref stream // so to work around the issue, we wrap the pdf_allocojbect // in a for loop 10 times to get the number // int sNum, sGen, tries; for (tries = 0; tries < 10; tries++) { error = pdf_allocobject(inFile->xref, &sNum, &sGen); if (error) return soPdfError(error); // If sNum is non zero then the allocation was successful if (sNum != 0) break; pdf_updateobject(inFile->xref, sNum, sGen, pageObj); } // If we didn't succeed even after 10 tries then this file // is not going to work. if (tries >= 10) return soPdfError(fz_throw("cannot allocate object because of mupdf bug")); // make a deep copy of the original page dict fz_obj *pageObj2; error = fz_deepcopydict(&pageObj2, pageObj); if (error) return soPdfError(error); // update the source file with the duplicate page object pdf_updateobject(inFile->xref, sNum, sGen, pageObj2); fz_dropobj(pageObj2); // create an indirect reference to the page object fz_obj *pageRef2; error = fz_newindirect(&pageRef2, sNum, sGen); if (error) return soPdfError(error); // delete the parent dictionary entry // Do we need to delete any other dictionary entry // like annot, tabs, metadata, etc fz_dictdels(pageObj2, "Parent"); // Set the media box setPageMediaBox(inFile->xref, pageObj2, bbRect[ctr]); // Set the rotation based on input switch(p_mode) { // no rotation if fit height case FitHeight: case Fit2xHeight: break; // rotate -90 deg if fit width case Fit2xWidth: case FitWidth: setPageRotate(pageObj2, p_reverseLandscape ? 90 : -90); break; case SmartFitHeight: case SmartFitWidth: default: return soPdfError(fz_throw("Mode(%d) not yet implemented.", p_mode)); break; } // push the indirect reference to the destination list for copy by pdf_transplant error = fz_arraypush(outFile->editobjs, pageRef2); if (error) return soPdfError(error); } } } // flush the objects into destination from source { fz_obj *results; int outPages; printf("\nCopying output page : "); error = pdf_transplant(outFile->xref, inFile->xref, &results, outFile->editobjs); if (error) return soPdfError(error); outPages = fz_arraylen(results); for (int ctr = 0; ctr < outPages; ctr++) { displayPageNumber(ctr + 1, !ctr); error = fz_arraypush(outFile->pagelist, fz_arrayget(results, p_reverseLandscape ? outPages - 1 - ctr : ctr)); if (error) return soPdfError(error); } fz_dropobj(results); } // flush page tree // Create page tree and add back-links { fz_obj *pageTreeObj; fz_obj *pageTreeRef; // allocate a new object in out file for pageTree object error = pdf_allocobject(outFile->xref, &pageTreeNum, &pageTreeGen); if (error) return soPdfError(error); // Create a page tree object error = fz_packobj(&pageTreeObj, "<</Type/Pages/Count %i/Kids %o>>", fz_arraylen(outFile->pagelist), outFile->pagelist); if (error) return soPdfError(error); // Update the xref entry with the pageTree object pdf_updateobject(outFile->xref, pageTreeNum, pageTreeGen, pageTreeObj); fz_dropobj(pageTreeObj); // Create a reference to the pageTree object error = fz_newindirect(&pageTreeRef, pageTreeNum, pageTreeGen); if (error) return soPdfError(error); // // For every page in the output file, update the parent entry // for (int ctr = 0; ctr < fz_arraylen(outFile->pagelist); ctr++) { fz_obj *pageObj; int num = fz_tonum(fz_arrayget(outFile->pagelist, ctr)); int gen = fz_togen(fz_arrayget(outFile->pagelist, ctr)); // Get the page object from xreft error = pdf_loadobject(&pageObj, outFile->xref, num, gen); if (error) return soPdfError(error); // Update the parent entry in the page dictionary error = fz_dictputs(pageObj, "Parent", pageTreeRef); if (error) return soPdfError(error); // Update the entry with the updated page object pdf_updateobject(outFile->xref, num, gen, pageObj); fz_dropobj(pageObj); } } // Create catalog and root entries { fz_obj *catObj, *infoObj; int rootNum, rootGen; int infoNum, infoGen; // // Copy the info catalog to the destination // alloc an object id and gen id in destination file error = pdf_allocobject(outFile->xref, &infoNum, &infoGen); if (error) return soPdfError(error); // make a deep copy of the original page dict error = fz_deepcopydict(&infoObj, inFile->xref->info); if (error) return soPdfError(error); // update the dest file with object pdf_updateobject(outFile->xref, infoNum, infoGen, infoObj); outFile->xref->info = infoObj; fz_dropobj(infoObj); // // root/catalog object creation error = pdf_allocobject(outFile->xref, &rootNum, &rootGen); if (error) return soPdfError(error); error = fz_packobj(&catObj, "<</Type/Catalog /Pages %r>>", pageTreeNum, pageTreeGen); if (error) return soPdfError(error); pdf_updateobject(outFile->xref, rootNum, rootGen, catObj); fz_dropobj(catObj); // Create trailer error = fz_packobj(&outFile->xref->trailer, "<</Root %r /Info %r>>", rootNum, rootGen, infoNum, infoGen); if (error) return soPdfError(error); } // Update the info in the target file and save the xref printf("\nSaving.\n"); error = setPageInfo(inFile, outFile); if (error) return soPdfError(error); error = pdf_savexref(outFile->xref, outFile->fileName, NULL); if (error) return soPdfError(error); if (g_errorCount != 0) { printf("\nFollowing issues encounted were ignored.\n\n"); for (int ctr = g_errorCount - 1; ctr >= 0; ctr--) soPdfError(g_errorList[ctr]); } printf("\nSaved.\n"); return 0; }