fz_rect fz_boundtext(fz_text *text, fz_matrix ctm) { fz_matrix trm; fz_rect bbox; fz_rect fbox; int i; if (text->len == 0) return fz_emptyrect; /* find bbox of glyph origins in ctm space */ bbox.x0 = bbox.x1 = text->els[0].x; bbox.y0 = bbox.y1 = text->els[0].y; for (i = 1; i < text->len; i++) { bbox.x0 = MIN(bbox.x0, text->els[i].x); bbox.y0 = MIN(bbox.y0, text->els[i].y); bbox.x1 = MAX(bbox.x1, text->els[i].x); bbox.y1 = MAX(bbox.y1, text->els[i].y); } bbox = fz_transformrect(ctm, bbox); /* find bbox of font in trm * ctm space */ trm = fz_concat(text->trm, ctm); trm.e = 0; trm.f = 0; fbox.x0 = text->font->bbox.x0 * 0.001f; fbox.y0 = text->font->bbox.y0 * 0.001f; fbox.x1 = text->font->bbox.x1 * 0.001f; fbox.y1 = text->font->bbox.y1 * 0.001f; fbox = fz_transformrect(trm, fbox); /* expand glyph origin bbox by font bbox */ bbox.x0 += fbox.x0; bbox.y0 += fbox.y0; bbox.x1 += fbox.x1; bbox.y1 += fbox.y1; return bbox; }
static void pdf_begingroup(pdf_csi *csi, fz_rect bbox) { pdf_gstate *gstate = csi->gstate + csi->gtop; fz_error error; if (gstate->softmask) { pdf_xobject *softmask = gstate->softmask; fz_rect bbox = fz_transformrect(gstate->ctm, softmask->bbox); gstate->softmask = nil; csi->dev->beginmask(csi->dev->user, bbox, gstate->luminosity, softmask->colorspace, gstate->softmaskbc); error = pdf_runxobject(csi, nil, softmask, fz_identity); if (error) fz_catch(error, "cannot run softmask"); csi->dev->endmask(csi->dev->user); gstate->softmask = softmask; } if (gstate->blendmode != FZ_BNORMAL) csi->dev->begingroup(csi->dev->user, bbox, 0, 0, gstate->blendmode, 1); }
void pdf_showimage(pdf_csi *csi, fz_pixmap *image) { pdf_gstate *gstate = csi->gstate + csi->gtop; fz_rect bbox; bbox = fz_transformrect(gstate->ctm, fz_unitrect); if (gstate->blendmode != FZ_BNORMAL) csi->dev->begingroup(csi->dev->user, bbox, 0, 0, gstate->blendmode, 1); if (image->mask) csi->dev->clipimagemask(csi->dev->user, image->mask, gstate->ctm); if (!image->colorspace) { switch (gstate->fill.kind) { case PDF_MNONE: break; case PDF_MCOLOR: csi->dev->fillimagemask(csi->dev->user, image, gstate->ctm, gstate->fill.cs, gstate->fill.v, gstate->fill.alpha); break; case PDF_MPATTERN: if (gstate->fill.pattern) { csi->dev->clipimagemask(csi->dev->user, image, gstate->ctm); pdf_showpattern(csi, gstate->fill.pattern, bbox, PDF_MFILL); csi->dev->popclip(csi->dev->user); } break; case PDF_MSHADE: if (gstate->fill.shade) { csi->dev->clipimagemask(csi->dev->user, image, gstate->ctm); csi->dev->fillshade(csi->dev->user, gstate->fill.shade, gstate->ctm, gstate->fill.alpha); csi->dev->popclip(csi->dev->user); } break; } } else { csi->dev->fillimage(csi->dev->user, image, gstate->ctm, gstate->fill.alpha); } if (image->mask) csi->dev->popclip(csi->dev->user); if (gstate->blendmode != FZ_BNORMAL) csi->dev->endgroup(csi->dev->user); }
JNIEXPORT void JNICALL Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal( JNIEnv *env, jobject thiz, int page) { float zoom; fz_matrix ctm; fz_obj *pageobj; fz_bbox bbox; fz_error error; fz_device *dev; pdf_page *currentPage; /* In the event of an error, ensure we give a non-empty page */ pageWidth = 100; pageHeight = 100; LOGE("Goto page %d...", page); if (currentPageList != NULL) { fz_freedisplaylist(currentPageList); currentPageList = NULL; } pagenum = page; pageobj = pdf_getpageobject(xref, pagenum); if (pageobj == NULL) return; error = pdf_loadpage(¤tPage, xref, pageobj); if (error) return; zoom = resolution / 72; currentMediabox = currentPage->mediabox; currentRotate = currentPage->rotate; ctm = fz_translate(0, -currentMediabox.y1); ctm = fz_concat(ctm, fz_scale(zoom, -zoom)); ctm = fz_concat(ctm, fz_rotate(currentRotate)); bbox = fz_roundrect(fz_transformrect(ctm, currentMediabox)); pageWidth = bbox.x1-bbox.x0; pageHeight = bbox.y1-bbox.y0; /* Render to list */ currentPageList = fz_newdisplaylist(); dev = fz_newlistdevice(currentPageList); error = pdf_runpage(xref, currentPage, dev, fz_identity); pdf_freepage(currentPage); if (error) LOGE("cannot make displaylist from page %d", pagenum); fz_freedevice(dev); }
static void fz_drawclipimagemask(void *user, fz_pixmap *image, fz_matrix ctm) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *mask, *dest; fz_pixmap *scaled = nil; int dx, dy; if (dev->top == STACKSIZE) { fz_warn("assert: too many buffers on stack"); return; } if (image->w == 0 || image->h == 0) { dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = nil; dev->stack[dev->top].dest = nil; dev->scissor = fz_emptybbox; dev->top++; return; } bbox = fz_roundrect(fz_transformrect(ctm, fz_unitrect)); bbox = fz_intersectbbox(bbox, dev->scissor); mask = fz_newpixmapwithrect(nil, bbox); dest = fz_newpixmapwithrect(model, bbox); fz_clearpixmap(mask, 0); fz_clearpixmap(dest, 0); #ifdef SMOOTHSCALE dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); if (dx < image->w && dy < image->h) { scaled = fz_smoothtransformpixmap(image, &ctm, dev->dest->x, dev->dest->y, dx, dy); if (scaled == NULL) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; scaled = fz_smoothscalepixmap(image, image->x, image->y, dx, dy); } if (scaled != NULL) image = scaled; } #else if (fz_calcimagescale(image, ctm, &dx, &dy)) { scaled = fz_scalepixmap(image, dx, dy); image = scaled; } #endif fz_paintimage(mask, bbox, image, ctm, 255); if (scaled) fz_droppixmap(scaled); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->scissor = bbox; dev->dest = dest; dev->top++; }
static void fz_drawfillshade(void *user, fz_shade *shade, fz_matrix ctm, float alpha) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_pixmap *dest = dev->dest; fz_rect bounds; fz_bbox bbox; float colorfv[FZ_MAXCOLORS]; unsigned char colorbv[FZ_MAXCOLORS + 1]; bounds = fz_boundshade(shade, ctm); bbox = fz_intersectbbox(fz_roundrect(bounds), dev->scissor); // TODO: proper clip by shade->bbox if (!fz_isemptyrect(shade->bbox)) { bounds = fz_transformrect(fz_concat(shade->matrix, ctm), shade->bbox); bbox = fz_intersectbbox(fz_roundrect(bounds), bbox); } if (fz_isemptyrect(bbox)) return; if (!model) { fz_warn("cannot render shading directly to an alpha mask"); return; } if (alpha < 1) { dest = fz_newpixmapwithrect(dev->dest->colorspace, bbox); fz_clearpixmap(dest, 0); } if (shade->usebackground) { unsigned char *s; int x, y, n, i; fz_convertcolor(shade->cs, shade->background, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = 255; n = dest->n; for (y = bbox.y0; y < bbox.y1; y++) { s = dest->samples + ((bbox.x0 - dest->x) + (y - dest->y) * dest->w) * dest->n; for (x = bbox.x0; x < bbox.x1; x++) { for (i = 0; i < n; i++) *s++ = colorbv[i]; } } } fz_rendershade(shade, ctm, dest, bbox); if (alpha < 1) { fz_paintpixmap(dev->dest, dest, alpha * 255); fz_droppixmap(dest); } }
fz_rect fz_boundshade(fz_shade *shade, fz_matrix ctm) { ctm = fz_concat(shade->matrix, ctm); return fz_transformrect(ctm, shade->bbox); }
static void pdf_showpattern(pdf_csi *csi, pdf_pattern *pat, fz_rect bbox, int what) { pdf_gstate *gstate; fz_matrix ptm, invptm; fz_matrix oldtopctm; fz_error error; int x, y, x0, y0, x1, y1; int oldtop; pdf_gsave(csi); gstate = csi->gstate + csi->gtop; if (pat->ismask) { pdf_unsetpattern(csi, PDF_MFILL); pdf_unsetpattern(csi, PDF_MSTROKE); if (what == PDF_MFILL) { pdf_dropmaterial(&gstate->stroke); pdf_keepmaterial(&gstate->fill); gstate->stroke = gstate->fill; } if (what == PDF_MSTROKE) { pdf_dropmaterial(&gstate->fill); pdf_keepmaterial(&gstate->stroke); gstate->fill = gstate->stroke; } } else { // TODO: unset only the current fill/stroke or both? pdf_unsetpattern(csi, what); } /* don't apply softmasks to objects in the pattern as well */ if (gstate->softmask) { pdf_dropxobject(gstate->softmask); gstate->softmask = nil; } ptm = fz_concat(pat->matrix, csi->topctm); invptm = fz_invertmatrix(ptm); /* patterns are painted using the ctm in effect at the beginning of the content stream */ /* get bbox of shape in pattern space for stamping */ bbox = fz_transformrect(invptm, bbox); x0 = floorf(bbox.x0 / pat->xstep); y0 = floorf(bbox.y0 / pat->ystep); x1 = ceilf(bbox.x1 / pat->xstep); y1 = ceilf(bbox.y1 / pat->ystep); oldtopctm = csi->topctm; oldtop = csi->gtop; for (y = y0; y < y1; y++) { for (x = x0; x < x1; x++) { gstate->ctm = fz_concat(fz_translate(x * pat->xstep, y * pat->ystep), ptm); csi->topctm = gstate->ctm; error = pdf_runcsibuffer(csi, pat->resources, pat->contents); while (oldtop < csi->gtop) pdf_grestore(csi); if (error) { fz_catch(error, "cannot render pattern tile"); goto cleanup; } } } cleanup: csi->topctm = oldtopctm; pdf_grestore(csi); }
JNIEXPORT jboolean JNICALL Java_com_artifex_mupdf_MuPDFCore_drawPage( JNIEnv *env, jobject thiz, jobject bitmap, int pageW, int pageH, int patchX, int patchY, int patchW, int patchH) { AndroidBitmapInfo info; void *pixels; int ret; fz_error error; fz_device *dev; float zoom; fz_matrix ctm; fz_bbox bbox; fz_pixmap *pix; float xscale, yscale; LOGI("In native method\n"); if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) { LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); return 0; } LOGI("Checking format\n"); if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { LOGE("Bitmap format is not RGBA_8888 !"); return 0; } LOGI("locking pixels\n"); if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); return 0; } /* Call mupdf to render display list to screen */ LOGE("Rendering page=%dx%d patch=[%d,%d,%d,%d]", pageW, pageH, patchX, patchY, patchW, patchH); pix = fz_newpixmapwithdata(colorspace, patchX, patchY, patchW, patchH, pixels); if (currentPageList == NULL) { fz_clearpixmapwithcolor(pix, 0xd0); return 0; } fz_clearpixmapwithcolor(pix, 0xff); zoom = resolution / 72; ctm = fz_translate(0, -currentMediabox.y1); ctm = fz_concat(ctm, fz_scale(zoom, -zoom)); ctm = fz_concat(ctm, fz_rotate(currentRotate)); bbox = fz_roundrect(fz_transformrect(ctm,currentMediabox)); /* Now, adjust ctm so that it would give the correct page width * heights. */ xscale = (float)pageW/(float)(bbox.x1-bbox.x0); yscale = (float)pageH/(float)(bbox.y1-bbox.y0); ctm = fz_concat(ctm, fz_scale(xscale, yscale)); dev = fz_newdrawdevice(glyphcache, pix); fz_executedisplaylist(currentPageList, dev, ctm); fz_freedevice(dev); fz_droppixmap(pix); LOGE("Rendered"); AndroidBitmap_unlockPixels(env, bitmap); return 1; }
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); }