static fz_matrix pdfViewctm(PDFContext* ctx) { fz_matrix ctm; ctm = fz_identity(); ctm = fz_concat(ctm, fz_translate(0, -ctx->page->mediabox.y1)); ctm = fz_concat(ctm, fz_scale(ctx->zoom, -ctx->zoom)); ctm = fz_concat(ctm, fz_rotate(ctx->rotate + ctx->page->rotate)); return ctm; }
fz_matrix pdfapp_viewctm(pdfapp_t *app) { fz_matrix ctm; ctm = fz_identity(); ctm = fz_concat(ctm, fz_translate(0, -app->page->mediabox.y1)); ctm = fz_concat(ctm, fz_scale(app->zoom, -app->zoom)); ctm = fz_concat(ctm, fz_rotate(app->rotate + app->page->rotate)); return ctm; }
static int fitsinside(fz_node *node, fz_rect clip) { fz_rect bbox; bbox = fz_boundnode(node, fz_identity()); if (fz_isinfiniterect(bbox)) return 0; if (fz_isemptyrect(bbox)) return 1; if (bbox.x0 < clip.x0) return 0; if (bbox.x1 > clip.x1) return 0; if (bbox.y0 < clip.y0) return 0; if (bbox.y1 > clip.y1) return 0; return 1; }
static fz_matrix getmatrix(fz_node *node) { if (node->parent) { fz_matrix ptm = getmatrix(node->parent); if (fz_istransformnode(node)) return fz_concat(((fz_transformnode*)node)->m, ptm); return ptm; } if (fz_istransformnode(node)) return ((fz_transformnode*)node)->m; return fz_identity(); }
fz_matrix pdfmoz_pagectm(pdfmoz_t *moz, int pagenum) { page_t *page = moz->pages + pagenum; fz_matrix ctm; float zoom; RECT rc; GetClientRect(moz->hwnd, &rc); zoom = (rc.right - rc.left) / (float) page->w; ctm = fz_identity(); ctm = fz_concat(ctm, fz_translate(0, -page->page->mediabox.y1)); ctm = fz_concat(ctm, fz_scale(zoom, -zoom)); ctm = fz_concat(ctm, fz_rotate(page->page->rotate)); return ctm; }
fz_error fz_newtextnode(fz_textnode **textp, fz_font *font) { fz_textnode *text; text = fz_malloc(sizeof(fz_textnode)); if (!text) return fz_rethrow(-1, "out of memory"); fz_initnode((fz_node*)text, FZ_NTEXT); text->font = fz_keepfont(font); text->trm = fz_identity(); text->len = 0; text->cap = 0; text->els = nil; *textp = text; return fz_okay; }
static fz_font * fz_newfont(void) { fz_font *font; font = fz_malloc(sizeof(fz_font)); font->refs = 1; strcpy(font->name, "<unknown>"); font->ftface = nil; font->ftsubstitute = 0; font->fthint = 0; font->t3matrix = fz_identity(); font->t3procs = nil; font->t3widths = nil; font->bbox.x0 = 0; font->bbox.y0 = 0; font->bbox.x1 = 1000; font->bbox.y1 = 1000; return font; }
static void drawpnm(int pagenum, struct benchmark *loadtimes, struct benchmark *drawtimes) { fz_error error; fz_matrix ctm; fz_irect bbox; fz_pixmap *pix; char name[256]; char pnmhdr[256]; int i, x, y, w, h, b, bh; int fd = -1; long start; long end; long elapsed; fz_md5 digest; if (!drawpattern) fz_md5init(&digest); drawloadpage(pagenum, loadtimes); if (benchmark) gettime(&start); ctm = fz_identity(); ctm = fz_concat(ctm, fz_translate(0, -drawpage->mediabox.y1)); ctm = fz_concat(ctm, fz_scale(drawzoom, -drawzoom)); ctm = fz_concat(ctm, fz_rotate(drawrotate + drawpage->rotate)); bbox = fz_roundrect(fz_transformaabb(ctm, drawpage->mediabox)); w = bbox.x1 - bbox.x0; h = bbox.y1 - bbox.y0; bh = h / drawbands; if (drawpattern) { sprintf(name, drawpattern, drawcount++); fd = open(name, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666); if (fd < 0) die(fz_throw("ioerror: could not open file '%s'", name)); sprintf(pnmhdr, "P6\n%d %d\n255\n", w, h); write(fd, pnmhdr, strlen(pnmhdr)); } error = fz_newpixmap(&pix, bbox.x0, bbox.y0, w, bh, 4); if (error) die(error); memset(pix->samples, 0xff, pix->h * pix->w * pix->n); for (b = 0; b < drawbands; b++) { if (drawbands > 1) fprintf(stderr, "drawing band %d / %d\n", b + 1, drawbands); error = fz_rendertreeover(drawgc, pix, drawpage->tree, ctm); if (error) die(error); if (drawpattern) { for (y = 0; y < pix->h; y++) { unsigned char *src = pix->samples + y * pix->w * 4; unsigned char *dst = src; for (x = 0; x < pix->w; x++) { dst[x * 3 + 0] = src[x * 4 + 1]; dst[x * 3 + 1] = src[x * 4 + 2]; dst[x * 3 + 2] = src[x * 4 + 3]; } write(fd, dst, pix->w * 3); memset(src, 0xff, pix->w * 4); } } if (!drawpattern) fz_md5update(&digest, pix->samples, pix->h * pix->w * 4); pix->y += bh; if (pix->y + pix->h > bbox.y1) pix->h = bbox.y1 - pix->y; } fz_droppixmap(pix); if (!drawpattern) { unsigned char buf[16]; fz_md5final(&digest, buf); for (i = 0; i < 16; i++) fprintf(stderr, "%02x", buf[i]); } if (drawpattern) close(fd); drawfreepage(); if (benchmark) { gettime(&end); elapsed = end - start; if (elapsed < drawtimes->min) { drawtimes->min = elapsed; drawtimes->minpage = pagenum; } if (elapsed > drawtimes->max) { drawtimes->max = elapsed; drawtimes->maxpage = pagenum; } drawtimes->avg += elapsed; drawtimes->pages++; fprintf(stderr, " time %.3fs", elapsed / 1000000.0); } fprintf(stderr, "\n"); }
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; }
fz_error* processPage( soPdfFile* inFile, int pageNo, fz_rect *bbRect, int rectCount ) { fz_error *error; fz_obj *pageRef; pdf_page *pdfPage; fz_rect contentBox; fz_rect mediaBox; // Initialize for (int ctr = 0; ctr < rectCount; ctr++) bbRect[ctr] = fz_emptyrect; // Get the page reference and load the page contents pageRef = pdf_getpageobject(inFile->pageTree, pageNo); error = pdf_loadpage(&pdfPage, inFile->xref, pageRef); if (error != NULL) { // Ideally pdf_loadpage should render all the pages // and this should never happen return processErrorPage(inFile, pageRef, pageNo, bbRect, error); } // Get the bounding box for the page mediaBox = pdfPage->mediabox; float mbHeight = mediaBox.y1 - mediaBox.y0; // calculate the bounding box for all the elements in the page contentBox = fz_boundnode(pdfPage->tree->root, fz_identity()); float cbHeight = contentBox.y1 - contentBox.y0; // If there is nothing on the page we return nothing. // should we return an empty page instead ??? if (fz_isemptyrect(contentBox)) goto Cleanup; // if contentBox is bigger than mediaBox then there are some // elements that should not be display and hence we reset the // content box to media box if ((cbHeight > mbHeight) || ((contentBox.x1 - contentBox.x0) > (mediaBox.x1 - mediaBox.x0))) { // Calculate the new content box based on the content that is // inside the the media box and recalculate cbHeight contentBox = getContainingRect(pdfPage->tree->root, mediaBox); cbHeight = contentBox.y1 - contentBox.y0; } #ifdef _blahblah printf("-->Page %d\n", pageNo); bbdump(pdfPage->tree->root, 1); #endif // The rotation takes place when we insert the page into destination // If only the mupdf renderer could give accurate values of the // bounding box of all the elements in a page, the splitting would // be so much more easier without overlapping, cutting text, etc switch(p_mode) { case FitHeight: case FitWidth: bbRect[0] = contentBox; goto Cleanup; case Fit2xHeight: case Fit2xWidth: // Let the processing happen. break; case SmartFitHeight: case SmartFitWidth: default: return fz_throw("Mode(%d) not yet implemented.", p_mode); break; } // If the contentBox is 60% of mediaBox then do not split if (((cbHeight / mbHeight) * 100) <= 55) { bbRect[0] = contentBox; goto Cleanup; } // Get the first split contents from top. The box we specify is // top 55% (bottom + 45) of the contents bbRect[0] = contentBox; bbRect[0].y0 = bbRect[0].y0 + (float)(0.45 * cbHeight); bbRect[0] = getContainingRect(pdfPage->tree->root, bbRect[0]); // Check if the contents we got in first split is more than 40% // of the total contents float bbRect0Height = bbRect[0].y1 - bbRect[0].y0; if (((bbRect0Height / cbHeight) * 100) >= 40) { // The content is more than 40%. Put the rest of the // content in the second split and exit bbRect[1] = contentBox; bbRect[1].y1 = bbRect[1].y1 - bbRect0Height; // Adjust the split box height by X points to make sure // we get everything and dont have annoying tail cuts bbRect[0].y0 -= 2; goto Cleanup; } // Since the contents we got in first split is less than 40% // of the total contents, split the content in half with overlap float overlap = (cbHeight * (float)(p_overlap / 100)) / 2; bbRect[0] = contentBox; bbRect[0].y0 = bbRect[0].y0 + (float)(0.5 * cbHeight) - overlap; bbRect[1] = contentBox; bbRect[1].y1 = bbRect[1].y1 - (float)(0.5 * cbHeight) + overlap; Cleanup: // This function can overflow the stack when the pdf page // to be rendered is very complex. I had to increase the // stack size reserved for exe using compiler option pdf_droppage(pdfPage); return error; }
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; }
void drawpnm(int pagenum) { fz_error *error; fz_matrix ctm; fz_irect bbox; fz_pixmap *pix; char namebuf[256]; char buf[256]; int x, y, w, h, b, bh; int fd; drawloadpage(pagenum); ctm = fz_identity(); ctm = fz_concat(ctm, fz_translate(0, -drawpage->mediabox.y1)); ctm = fz_concat(ctm, fz_scale(drawzoom, -drawzoom)); ctm = fz_concat(ctm, fz_rotate(drawrotate + drawpage->rotate)); bbox = fz_roundrect(fz_transformaabb(ctm, drawpage->mediabox)); w = bbox.x1 - bbox.x0; h = bbox.y1 - bbox.y0; bh = h / drawbands; if (drawpattern) { sprintf(namebuf, drawpattern, drawcount++); fd = open(namebuf, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666); if (fd < 0) die(fz_throw("ioerror: could not open file '%s'", namebuf)); } else fd = 1; sprintf(buf, "P6\n%d %d\n255\n", w, h); write(fd, buf, strlen(buf)); error = fz_newpixmap(&pix, bbox.x0, bbox.y0, w, bh, 4); if (error) die(error); memset(pix->samples, 0xff, pix->h * pix->w * pix->n); for (b = 0; b < drawbands; b++) { if (drawbands > 1) fprintf(stderr, "drawing band %d / %d\n", b + 1, drawbands); error = fz_rendertreeover(drawgc, pix, drawpage->tree, ctm); if (error) die(error); for (y = 0; y < pix->h; y++) { unsigned char *src = pix->samples + y * pix->w * 4; unsigned char *dst = src; for (x = 0; x < pix->w; x++) { dst[x * 3 + 0] = src[x * 4 + 1]; dst[x * 3 + 1] = src[x * 4 + 2]; dst[x * 3 + 2] = src[x * 4 + 3]; } write(fd, dst, pix->w * 3); memset(src, 0xff, pix->w * 4); } pix->y += bh; if (pix->y + pix->h > bbox.y1) pix->h = bbox.y1 - pix->y; } fz_droppixmap(pix); if (drawpattern) close(fd); drawfreepage(); }
fz_error pdf_loadxobject(pdf_xobject **formp, pdf_xref *xref, fz_obj *dict) { fz_error error; pdf_xobject *form; fz_obj *obj; if ((*formp = pdf_finditem(xref->store, PDF_KXOBJECT, dict))) { pdf_keepxobject(*formp); return fz_okay; } form = fz_malloc(sizeof(pdf_xobject)); form->refs = 1; form->resources = nil; form->contents = nil; /* Store item immediately, to avoid possible recursion if objects refer back to this one */ pdf_storeitem(xref->store, PDF_KXOBJECT, dict, form); pdf_logrsrc("load xobject (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), 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); form->isolated = 0; form->knockout = 0; form->transparency = 0; obj = fz_dictgets(dict, "Group"); if (obj) { fz_obj *attrs = obj; form->isolated = fz_tobool(fz_dictgets(attrs, "I")); form->knockout = fz_tobool(fz_dictgets(attrs, "K")); obj = fz_dictgets(attrs, "S"); if (fz_isname(obj) && !strcmp(fz_toname(obj), "Transparency")) form->transparency = 1; } pdf_logrsrc("isolated %d\n", form->isolated); pdf_logrsrc("knockout %d\n", form->knockout); pdf_logrsrc("transparency %d\n", form->transparency); form->resources = fz_dictgets(dict, "Resources"); if (form->resources) fz_keepobj(form->resources); error = pdf_loadstream(&form->contents, xref, fz_tonum(dict), fz_togen(dict)); if (error) { pdf_removeitem(xref->store, PDF_KXOBJECT, dict); pdf_dropxobject(form); return fz_rethrow(error, "cannot load xobject content stream (%d %d R)", fz_tonum(dict), fz_togen(dict)); } pdf_logrsrc("stream %d bytes\n", form->contents->wp - form->contents->rp); pdf_logrsrc("}\n"); *formp = form; return fz_okay; }
static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage) { char buf[256]; fz_error error; fz_device *idev, *tdev, *mdev; fz_displaylist *list; fz_matrix ctm; fz_bbox bbox; fz_obj *obj; if (loadpage) { wincursor(app, WAIT); if (app->page) pdf_droppage(app->page); app->page = nil; //code change by kakai kno_clearselect(app); //code change by kakai pdf_flushxref(app->xref, 0); obj = pdf_getpageobject(app->xref, app->pageno); error = pdf_loadpage(&app->page, app->xref, obj); if (error) pdfapp_error(app, error); sprintf(buf, "%s - %d/%d", app->doctitle, app->pageno, app->pagecount); wintitle(app, buf); } if (drawpage) { wincursor(app, WAIT); ctm = pdfapp_viewctm(app); bbox = fz_roundrect(fz_transformrect(ctm, app->page->mediabox)); list = fz_newdisplaylist(); mdev = fz_newlistdevice(list); error = pdf_runcontentstream(mdev, fz_identity(), app->xref, app->page->resources, app->page->contents); if (error) pdfapp_error(app, error); fz_freedevice(mdev); if (app->image) fz_droppixmap(app->image); app->image = fz_newpixmapwithrect(pdf_devicergb, bbox); fz_clearpixmap(app->image, 0xFF); idev = fz_newdrawdevice(app->cache, app->image); fz_executedisplaylist(list, idev, ctm); fz_freedevice(idev); if (app->text) fz_freetextspan(app->text); app->text = fz_newtextspan(); tdev = fz_newtextdevice(app->text); fz_executedisplaylist(list, tdev, ctm); fz_freedevice(tdev); fz_freedisplaylist(list); //code change by kakai kno_allocselection(app); kno_applyselect(app); //code change by kakai winconvert(app, app->image); } pdfapp_panview(app, app->panx, app->pany); if (app->shrinkwrap) { int w = app->image->w; int h = app->image->h; if (app->winw == w) app->panx = 0; if (app->winh == h) app->pany = 0; if (w > app->scrw * 90 / 100) w = app->scrw * 90 / 100; if (h > app->scrh * 90 / 100) h = app->scrh * 90 / 100; if (w != app->winw || h != app->winh) winresize(app, w, h); } winrepaint(app); wincursor(app, ARROW); }