static void fz_drawbeginmask(void *user, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *colorfv) { fz_drawdevice *dev = user; fz_pixmap *dest; fz_bbox bbox; if (dev->top == STACKSIZE) { fz_warn("assert: too many buffers on stack"); return; } bbox = fz_roundrect(rect); bbox = fz_intersectbbox(bbox, dev->scissor); dest = fz_newpixmapwithrect(fz_devicegray, bbox); if (luminosity) { /* SumatraPDF: pass a Luminosity softmask's background color */ float gray = 1.0; fz_convertcolor(colorspace, colorfv, fz_devicegray, &gray); fz_clearpixmap(dest, gray * 255); } else fz_clearpixmap(dest, 0); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].luminosity = luminosity; dev->top++; dev->scissor = bbox; dev->dest = dest; }
static void fz_drawbegingroup(void *user, fz_rect rect, int isolated, int knockout, fz_blendmode blendmode, float alpha) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *dest; if (dev->top == STACKSIZE) { fz_warn("assert: too many buffers on stack"); return; } bbox = fz_roundrect(rect); bbox = fz_intersectbbox(bbox, dev->scissor); dest = fz_newpixmapwithrect(model, bbox); fz_clearpixmap(dest, 0); dev->stack[dev->top].alpha = alpha; dev->stack[dev->top].blendmode = blendmode; dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; dev->top++; dev->scissor = bbox; dev->dest = dest; }
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; }
static fz_error * rendertext(fz_renderer *gc, fz_textnode *text, fz_matrix ctm) { fz_error *error; fz_irect tbox; fz_irect clip; fz_matrix tm, trm; fz_glyph glyph; int i, x, y, cid; tbox = fz_roundrect(fz_boundnode((fz_node*)text, ctm)); clip = fz_intersectirects(gc->clip, tbox); DEBUG("text %s n=%d [%g %g %g %g];\n", text->font->name, text->len, text->trm.a, text->trm.b, text->trm.c, text->trm.d); if (fz_isemptyrect(clip)) return fz_okay; if (!(gc->flag & FOVER)) { error = fz_newpixmapwithrect(&gc->dest, clip, 1); if (error) return error; fz_clearpixmap(gc->dest); } tm = text->trm; for (i = 0; i < text->len; i++) { cid = text->els[i].cid; tm.e = text->els[i].x; tm.f = text->els[i].y; trm = fz_concat(tm, ctm); x = fz_floor(trm.e); y = fz_floor(trm.f); trm.e = QUANT(trm.e - fz_floor(trm.e), HSUBPIX); trm.f = QUANT(trm.f - fz_floor(trm.f), VSUBPIX); error = fz_renderglyph(gc->cache, &glyph, text->font, cid, trm); if (error) return error; if (!(gc->flag & FOVER)) drawglyph(gc, gc->dest, &glyph, x, y); else drawglyph(gc, gc->over, &glyph, x, y); } return fz_okay; }
fz_error fz_rendert3glyph(fz_glyph *glyph, fz_font *font, int gid, fz_matrix trm) { fz_error error; fz_renderer *gc; fz_tree *tree; fz_matrix ctm; fz_irect bbox; /* TODO: make it reentrant */ static fz_pixmap *pixmap = nil; if (pixmap) { fz_droppixmap(pixmap); pixmap = nil; } if (gid < 0 || gid > 255) return fz_throw("assert: glyph out of range"); tree = font->t3procs[gid]; if (!tree) { glyph->w = 0; glyph->h = 0; return fz_okay; } ctm = fz_concat(font->t3matrix, trm); bbox = fz_roundrect(fz_boundtree(tree, ctm)); error = fz_newrenderer(&gc, pdf_devicegray, 1, 4096); if (error) return fz_rethrow(error, "cannot create renderer"); error = fz_rendertree(&pixmap, gc, tree, ctm, bbox, 0); fz_droprenderer(gc); if (error) return fz_rethrow(error, "cannot render glyph"); assert(pixmap->n == 1); glyph->x = pixmap->x; glyph->y = pixmap->y; glyph->w = pixmap->w; glyph->h = pixmap->h; glyph->samples = pixmap->samples; return fz_okay; }
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); }
void pdfmoz_drawpage(pdfmoz_t *moz, int pagenum) { page_t *page = moz->pages + pagenum; fz_error error; fz_matrix ctm; fz_rect bbox; if (page->image) return; ctm = pdfmoz_pagectm(moz, pagenum); bbox = fz_transformaabb(ctm, page->page->mediabox); error = fz_rendertree(&page->image, moz->rast, page->page->tree, ctm, fz_roundrect(bbox), 1); if (error) pdfmoz_error(moz, error); }
static fz_error * t3render(fz_glyph *glyph, fz_font *fzfont, int cid, fz_matrix trm) { pdf_font *font = (pdf_font*)fzfont; fz_error *error; fz_renderer *gc; fz_tree *tree; fz_pixmap *pixmap; fz_matrix ctm; fz_irect bbox; if (cid < 0 || cid > 255) return fz_throw("assert: glyph out of range"); tree = font->charprocs[cid]; if (!tree) { glyph->w = 0; glyph->h = 0; return fz_okay; } ctm = fz_concat(font->matrix, trm); bbox = fz_roundrect(fz_boundtree(tree, ctm)); error = fz_newrenderer(&gc, pdf_devicegray, 1, GCMEM); if (error) return fz_rethrow(error, "cannot create renderer"); error = fz_rendertree(&pixmap, gc, tree, ctm, bbox, 0); fz_droprenderer(gc); if (error) return fz_rethrow(error, "cannot render glyph"); assert(pixmap->n == 1); glyph->x = pixmap->x; glyph->y = pixmap->y; glyph->w = pixmap->w; glyph->h = pixmap->h; glyph->samples = pixmap->samples; return fz_okay; }
static fz_error * rendershade(fz_renderer *gc, fz_shadenode *node, fz_matrix ctm) { fz_error *error; fz_irect bbox; assert(!gc->maskonly); DEBUG("shade;\n"); bbox = fz_roundrect(fz_boundnode((fz_node*)node, ctm)); bbox = fz_intersectirects(gc->clip, bbox); error = fz_newpixmapwithrect(&gc->dest, bbox, gc->model->n + 1); if (error) return error; return fz_rendershade(node->shade, ctm, gc->model, gc->dest); }
static fz_pixmap* pdfRenderTile(PDFContext* ctx, int x, int y, int w, int h, bool transform = false) { fz_error *error; fz_matrix ctm; fz_rect bbox; bbox.x0 = x; bbox.y0 = y; bbox.x1 = x; bbox.y1 = y; ctm = pdfViewctm(ctx); if (transform) { bbox.x1 += w; bbox.y1 += h; bbox = fz_transformaabb(ctm, bbox); } else { bbox.x0 = x; bbox.y0 = y; bbox.x1 = bbox.x0 + w; bbox.y1 = bbox.y0 + h; } fz_irect ir = fz_roundrect(bbox); /*if (!transform) { ir.x1 = ir.x0 + w; ir.y1 = ir.y0 + h; }*/ fz_pixmap* pix = NULL; error = fz_rendertree(&pix, ctx->rast, ctx->page->tree, ctm, ir, 1); if (error) { return 0; } if (BKUser::options.pdfInvertColors) { unsigned int* s = (unsigned int*)pix->samples; unsigned int n = pix->w * pix->h; for (unsigned int i = 0; i < n; ++i) { *s = ~(*s); ++s; } } return pix; }
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); } }
static void fz_drawclipstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matrix ctm) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *mask, *dest; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; if (dev->top == STACKSIZE) { fz_warn("assert: too many buffers on stack"); return; } /* make the mask the exact size needed */ bbox = fz_roundrect(fz_boundtext(text, ctm)); bbox = fz_intersectbbox(bbox, dev->scissor); mask = fz_newpixmapwithrect(nil, bbox); dest = fz_newpixmapwithrect(model, bbox); fz_clearpixmap(mask, 0); fz_clearpixmap(dest, 0); 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++; if (!fz_isemptyrect(bbox)) { tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->els[i].gid; if (gid < 0) continue; tm.e = text->els[i].x; tm.f = text->els[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); glyph = fz_renderstrokedglyph(dev->cache, text->font, gid, trm, ctm, stroke); if (glyph) { drawglyph(nil, mask, glyph, x, y, bbox); fz_droppixmap(glyph); } } } }
static void fz_drawcliptext(void *user, fz_text *text, fz_matrix ctm, int accumulate) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *mask, *dest; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; /* If accumulate == 0 then this text object is guaranteed complete */ /* If accumulate == 1 then this text object is the first (or only) in a sequence */ /* If accumulate == 2 then this text object is a continuation */ if (dev->top == STACKSIZE) { fz_warn("assert: too many buffers on stack"); return; } if (accumulate == 0) { /* make the mask the exact size needed */ bbox = fz_roundrect(fz_boundtext(text, ctm)); bbox = fz_intersectbbox(bbox, dev->scissor); } else { /* be conservative about the size of the mask needed */ bbox = dev->scissor; } if (accumulate == 0 || accumulate == 1) { mask = fz_newpixmapwithrect(nil, bbox); dest = fz_newpixmapwithrect(model, bbox); fz_clearpixmap(mask, 0); fz_clearpixmap(dest, 0); 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++; } else { mask = dev->stack[dev->top-1].mask; } if (!fz_isemptyrect(bbox)) { tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->els[i].gid; if (gid < 0) continue; tm.e = text->els[i].x; tm.f = text->els[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); glyph = fz_renderglyph(dev->cache, text->font, gid, trm); if (glyph) { drawglyph(nil, mask, glyph, x, y, bbox); fz_droppixmap(glyph); } } } }
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"); }
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; }
fz_error pdf_loadpage(pdf_page **pagep, pdf_xref *xref, fz_obj *dict) { fz_error error; pdf_page *page; fz_obj *obj; fz_bbox bbox; pdf_logpage("load page {\n"); // TODO: move this to a more appropriate place /* Ensure that we have a store for resource objects */ if (!xref->store) xref->store = pdf_newstore(); page = fz_malloc(sizeof(pdf_page)); page->resources = nil; page->contents = nil; page->transparency = 0; page->list = nil; page->text = nil; page->links = nil; page->annots = nil; obj = fz_dictgets(dict, "MediaBox"); bbox = fz_roundrect(pdf_torect(obj)); if (fz_isemptyrect(pdf_torect(obj))) { fz_warn("cannot find page bounds, guessing page bounds."); bbox.x0 = 0; bbox.y0 = 0; bbox.x1 = 612; bbox.y1 = 792; } obj = fz_dictgets(dict, "CropBox"); if (fz_isarray(obj)) { fz_bbox cropbox = fz_roundrect(pdf_torect(obj)); bbox = fz_intersectbbox(bbox, cropbox); } page->mediabox.x0 = MIN(bbox.x0, bbox.x1); page->mediabox.y0 = MIN(bbox.y0, bbox.y1); page->mediabox.x1 = MAX(bbox.x0, bbox.x1); page->mediabox.y1 = MAX(bbox.y0, bbox.y1); if (page->mediabox.x1 - page->mediabox.x0 < 1 || page->mediabox.y1 - page->mediabox.y0 < 1) return fz_throw("invalid page size"); page->rotate = fz_toint(fz_dictgets(dict, "Rotate")); pdf_logpage("bbox [%d %d %d %d]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1); pdf_logpage("rotate %d\n", page->rotate); obj = fz_dictgets(dict, "Annots"); if (obj) { pdf_loadlinks(&page->links, xref, obj); pdf_loadannots(&page->annots, xref, obj); } page->resources = fz_dictgets(dict, "Resources"); if (page->resources) fz_keepobj(page->resources); obj = fz_dictgets(dict, "Contents"); error = pdf_loadpagecontents(&page->contents, xref, obj); if (error) { pdf_freepage(page); return fz_rethrow(error, "cannot load page contents (%d %d R)", fz_tonum(obj), fz_togen(obj)); } if (page->resources && pdf_resourcesuseblending(page->resources)) page->transparency = 1; pdf_logpage("} %p\n", page); *pagep = page; return fz_okay; }
void pdfmoz_open(pdfmoz_t *moz, char *filename) { SCROLLINFO si; fz_error error; fz_obj *obj; fz_irect bbox; int rot; int i; strcpy(moz->error, ""); error = fz_newrenderer(&moz->rast, pdf_devicergb, 0, 1024 * 512); if (error) pdfmoz_error(moz, error); /* * Open PDF and load xref table */ moz->filename = filename; moz->xref = pdf_newxref(); error = pdf_loadxref(moz->xref, filename); if (error) { error = pdf_repairxref(moz->xref, filename); if (error) pdfmoz_error(moz, error); } /* * Handle encrypted PDF files */ error = pdf_decryptxref(moz->xref); if (error) pdfmoz_error(moz, error); if (pdf_needspassword(moz->xref)) { pdfmoz_warn(moz, "PDF file is encrypted and needs a password."); } moz->pagecount = pdf_getpagecount(moz->xref); moz->pages = fz_malloc(sizeof(page_t) * moz->pagecount); for (i = 0; i < moz->pagecount; i++) { fz_obj *pageobj; pageobj = pdf_getpageobject(moz->xref, i); moz->pages[i].obj = fz_keepobj(pageobj); moz->pages[i].page = nil; moz->pages[i].image = nil; obj = fz_dictgets(moz->pages[i].obj, "CropBox"); if (!obj) obj = fz_dictgets(moz->pages[i].obj, "MediaBox"); bbox = fz_roundrect(pdf_torect(obj)); moz->pages[i].w = bbox.x1 - bbox.x0; moz->pages[i].h = bbox.y1 - bbox.y0; rot = fz_toint(fz_dictgets(moz->pages[i].obj, "Rotate")); if ((rot / 90) % 2) { int t = moz->pages[i].w; moz->pages[i].w = moz->pages[i].h; moz->pages[i].h = t; } moz->pages[i].px = 1 + PAD; } /* * Load meta information * TODO: move this into mupdf library */ obj = fz_dictgets(moz->xref->trailer, "Root"); moz->xref->root = fz_resolveindirect(obj); if (!moz->xref->root) pdfmoz_error(moz, fz_throw("syntaxerror: missing Root object")); if (moz->xref->root) fz_keepobj(moz->xref->root); obj = fz_dictgets(moz->xref->trailer, "Info"); moz->xref->info = fz_resolveindirect(obj); if (moz->xref->info) fz_keepobj(moz->xref->info); moz->doctitle = filename; if (strrchr(moz->doctitle, '\\')) moz->doctitle = strrchr(moz->doctitle, '\\') + 1; if (strrchr(moz->doctitle, '/')) moz->doctitle = strrchr(moz->doctitle, '/') + 1; if (moz->xref->info) { obj = fz_dictgets(moz->xref->info, "Title"); if (obj) moz->doctitle = pdf_toutf8(obj); } /* * Start at first page */ si.cbSize = sizeof(si); si.fMask = SIF_POS | SIF_RANGE; // XXX | SIF_PAGE; si.nPos = 0; si.nMin = 0; si.nMax = 1; si.nPage = 1; SetScrollInfo(moz->hwnd, SB_VERT, &si, TRUE); moz->scrollpage = 0; moz->scrollyofs = 0; InvalidateRect(moz->hwnd, NULL, FALSE); }
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(); }
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); }
static fz_error * renderimage(fz_renderer *gc, fz_imagenode *node, fz_matrix ctm) { fz_error *error; fz_image *image = node->image; fz_irect bbox; fz_irect clip; int dx, dy; fz_pixmap *tile; fz_pixmap *temp; fz_matrix imgmat; fz_matrix invmat; int fa, fb, fc, fd; int u0, v0; int x0, y0; int w, h; int tileheight; DEBUG("image %dx%d %d+%d %s\n{\n", image->w, image->h, image->n, image->a, image->cs?image->cs->name:"(nil)"); bbox = fz_roundrect(fz_boundnode((fz_node*)node, ctm)); clip = fz_intersectirects(gc->clip, bbox); if (fz_isemptyrect(clip)) return fz_okay; if (image->w == 0 || image->h == 0) return fz_okay; if (image->n + image->a == 0) return fz_okay; calcimagescale(ctm, image->w, image->h, &dx, &dy); /* try to fit tile into a typical L2 cachce */ tileheight = 512 * 1024 / (image->w * (image->n + image->a)); /* tileheight must be an even multiple of dy, except for last band */ tileheight = (tileheight + dy - 1) / dy * dy; if ((dx != 1 || dy != 1) && image->h > tileheight) { int y = 0; DEBUG(" load image tile size = %dx%d\n", image->w, tileheight); error = fz_newpixmap(&tile, 0, 0, image->w, tileheight, image->n + 1); if (error) return error; error = fz_newscaledpixmap(&temp, image->w, image->h, image->n + 1, dx, dy); if (error) goto cleanup; do { if (y + tileheight > image->h) tileheight = image->h - y; tile->y = y; tile->h = tileheight; DEBUG(" tile xywh=%d %d %d %d sxsy=1/%d 1/%d\n", 0, y, image->w, tileheight, dx, dy); error = image->loadtile(image, tile); if (error) goto cleanup1; error = fz_scalepixmaptile(temp, 0, y, tile, dx, dy); if (error) goto cleanup1; y += tileheight; } while (y < image->h); fz_droppixmap(tile); tile = temp; } else { DEBUG(" load image\n"); error = fz_newpixmap(&tile, 0, 0, image->w, image->h, image->n + 1); if (error) return error; error = image->loadtile(image, tile); if (error) goto cleanup; if (dx != 1 || dy != 1) { DEBUG(" scale image 1/%d 1/%d\n", dx, dy); error = fz_scalepixmap(&temp, tile, dx, dy); if (error) goto cleanup; fz_droppixmap(tile); tile = temp; } } if (image->cs && image->cs != gc->model) { DEBUG(" convert from %s to %s\n", image->cs->name, gc->model->name); error = fz_newpixmap(&temp, tile->x, tile->y, tile->w, tile->h, gc->model->n + 1); if (error) goto cleanup; fz_convertpixmap(image->cs, tile, gc->model, temp); fz_droppixmap(tile); tile = temp; } imgmat.a = 1.0 / tile->w; imgmat.b = 0.0; imgmat.c = 0.0; imgmat.d = -1.0 / tile->h; imgmat.e = 0.0; imgmat.f = 1.0; invmat = fz_invertmatrix(fz_concat(imgmat, ctm)); w = clip.x1 - clip.x0; h = clip.y1 - clip.y0; x0 = clip.x0; y0 = clip.y0; u0 = (invmat.a * (x0+0.5) + invmat.c * (y0+0.5) + invmat.e) * 65536; v0 = (invmat.b * (x0+0.5) + invmat.d * (y0+0.5) + invmat.f) * 65536; fa = invmat.a * 65536; fb = invmat.b * 65536; fc = invmat.c * 65536; fd = invmat.d * 65536; #define PSRC tile->samples, tile->w, tile->h #define PDST(p) p->samples + ((y0-p->y) * p->w + (x0-p->x)) * p->n, p->w * p->n #define PCTM u0, v0, fa, fb, fc, fd, w, h switch (gc->flag) { case FNONE: { DEBUG(" fnone %d x %d\n", w, h); if (image->cs) error = fz_newpixmapwithrect(&gc->dest, clip, gc->model->n + 1); else error = fz_newpixmapwithrect(&gc->dest, clip, 1); if (error) goto cleanup; if (image->cs) fz_img_4c4(PSRC, PDST(gc->dest), PCTM); else fz_img_1c1(PSRC, PDST(gc->dest), PCTM); } break; case FOVER: { DEBUG(" fover %d x %d\n", w, h); if (image->cs) fz_img_4o4(PSRC, PDST(gc->over), PCTM); else fz_img_1o1(PSRC, PDST(gc->over), PCTM); } break; case FOVER | FRGB: DEBUG(" fover+rgb %d x %d\n", w, h); fz_img_w4i1o4(gc->argb, PSRC, PDST(gc->over), PCTM); break; default: assert(!"impossible flag in image span function"); } DEBUG("}\n"); fz_droppixmap(tile); return fz_okay; cleanup1: fz_droppixmap(temp); cleanup: fz_droppixmap(tile); return error; }
void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage) { char buf[256]; fz_error *error; fz_matrix ctm; fz_rect bbox; fz_obj *obj; if (loadpage) { wincursor(app, WAIT); if (app->page) pdf_droppage(app->page); app->page = nil; obj = pdf_getpageobject(app->pages, app->pageno - 1); error = pdf_loadpage(&app->page, app->xref, obj); if (error) pdfapp_error(app, error); sprintf(buf, "%s - %d/%d", app->doctitle, app->pageno, pdf_getpagecount(app->pages)); wintitle(app, buf); } if (drawpage) { wincursor(app, WAIT); if (app->image) fz_droppixmap(app->image); app->image = nil; ctm = pdfapp_viewctm(app); bbox = fz_transformaabb(ctm, app->page->mediabox); error = fz_rendertree(&app->image, app->rast, app->page->tree, ctm, fz_roundrect(bbox), 1); if (error) pdfapp_error(app, error); 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); }
static fz_error * rendermask(fz_renderer *gc, fz_masknode *mask, fz_matrix ctm) { fz_error *error; int oldmaskonly; fz_pixmap *oldover; fz_irect oldclip; fz_irect bbox; fz_irect clip; fz_pixmap *shapepix = nil; fz_pixmap *colorpix = nil; fz_node *shape; fz_node *color; float rgb[3]; shape = mask->super.first; color = shape->next; /* special case black voodo */ if (gc->flag & FOVER) { if (fz_issolidnode(color)) { fz_solidnode *solid = (fz_solidnode*)color; fz_convertcolor(solid->cs, solid->samples, gc->model, rgb); gc->argb[0] = solid->a * 255; gc->argb[1] = rgb[0] * solid->a * 255; gc->argb[2] = rgb[1] * solid->a * 255; gc->argb[3] = rgb[2] * solid->a * 255; gc->argb[4] = rgb[0] * 255; gc->argb[5] = rgb[1] * 255; gc->argb[6] = rgb[2] * 255; gc->flag |= FRGB; /* we know these can handle the FRGB shortcut */ if (fz_ispathnode(shape)) return renderpath(gc, (fz_pathnode*)shape, ctm); if (fz_istextnode(shape)) return rendertext(gc, (fz_textnode*)shape, ctm); if (fz_isimagenode(shape)) return renderimage(gc, (fz_imagenode*)shape, ctm); } } oldclip = gc->clip; oldover = gc->over; bbox = fz_roundrect(fz_boundnode(shape, ctm)); clip = fz_intersectirects(bbox, gc->clip); bbox = fz_roundrect(fz_boundnode(color, ctm)); clip = fz_intersectirects(bbox, clip); if (fz_isemptyrect(clip)) return fz_okay; DEBUG("mask [%d %d %d %d]\n{\n", clip.x0, clip.y0, clip.x1, clip.y1); { fz_irect sbox = fz_roundrect(fz_boundnode(shape, ctm)); fz_irect cbox = fz_roundrect(fz_boundnode(color, ctm)); if (cbox.x0 >= sbox.x0 && cbox.x1 <= sbox.x1) if (cbox.y0 >= sbox.y0 && cbox.y1 <= sbox.y1) DEBUG("potentially useless mask\n"); } gc->clip = clip; gc->over = nil; oldmaskonly = gc->maskonly; gc->maskonly = 1; error = rendernode(gc, shape, ctm); if (error) goto cleanup; shapepix = gc->dest; gc->dest = nil; gc->maskonly = oldmaskonly; error = rendernode(gc, color, ctm); if (error) goto cleanup; colorpix = gc->dest; gc->dest = nil; gc->clip = oldclip; gc->over = oldover; if (shapepix && colorpix) { if (gc->over) { blendmask(gc, colorpix, shapepix, gc->over, 1); } else { clip.x0 = MAX(colorpix->x, shapepix->x); clip.y0 = MAX(colorpix->y, shapepix->y); clip.x1 = MIN(colorpix->x+colorpix->w, shapepix->x+shapepix->w); clip.y1 = MIN(colorpix->y+colorpix->h, shapepix->y+shapepix->h); error = fz_newpixmapwithrect(&gc->dest, clip, colorpix->n); if (error) goto cleanup; blendmask(gc, colorpix, shapepix, gc->dest, 0); } } DEBUG("}\n"); if (shapepix) fz_droppixmap(shapepix); if (colorpix) fz_droppixmap(colorpix); return fz_okay; cleanup: if (shapepix) fz_droppixmap(shapepix); if (colorpix) fz_droppixmap(colorpix); return error; }
static fz_error * renderimage(fz_renderer *gc, fz_imagenode *node, fz_matrix ctm) { fz_error *error; fz_image *image = node->image; fz_irect bbox; fz_irect clip; int dx, dy; fz_pixmap *tile; fz_pixmap *temp; fz_matrix imgmat; fz_matrix invmat; int fa, fb, fc, fd; int u0, v0; int x0, y0; int w, h; DEBUG("image %dx%d %d+%d %s\n{\n", image->w, image->h, image->n, image->a, image->cs?image->cs->name:"(nil)"); bbox = fz_roundrect(fz_boundnode((fz_node*)node, ctm)); clip = fz_intersectirects(gc->clip, bbox); if (fz_isemptyrect(clip)) return nil; calcimagescale(ctm, image->w, image->h, &dx, &dy); DEBUG(" load image\n"); error = fz_newpixmap(&tile, 0, 0, image->w, image->h, image->n + 1); if (error) return error; error = image->loadtile(image, tile); if (error) goto cleanup; if (dx != 1 || dy != 1) { DEBUG(" scale image 1/%d 1/%d\n", dx, dy); error = fz_scalepixmap(&temp, tile, dx, dy); if (error) goto cleanup; fz_droppixmap(tile); tile = temp; } if (image->cs && image->cs != gc->model) { DEBUG(" convert from %s to %s\n", image->cs->name, gc->model->name); error = fz_newpixmap(&temp, tile->x, tile->y, tile->w, tile->h, gc->model->n + 1); if (error) goto cleanup; fz_convertpixmap(image->cs, tile, gc->model, temp); fz_droppixmap(tile); tile = temp; } imgmat.a = 1.0 / tile->w; imgmat.b = 0.0; imgmat.c = 0.0; imgmat.d = -1.0 / tile->h; imgmat.e = 0.0; imgmat.f = 1.0; invmat = fz_invertmatrix(fz_concat(imgmat, ctm)); w = clip.x1 - clip.x0; h = clip.y1 - clip.y0; x0 = clip.x0; y0 = clip.y0; u0 = (invmat.a * (x0+0.5) + invmat.c * (y0+0.5) + invmat.e) * 65536; v0 = (invmat.b * (x0+0.5) + invmat.d * (y0+0.5) + invmat.f) * 65536; fa = invmat.a * 65536; fb = invmat.b * 65536; fc = invmat.c * 65536; fd = invmat.d * 65536; #define PSRC tile->samples, tile->w, tile->h #define PDST(p) p->samples + ((y0-p->y) * p->w + (x0-p->x)) * p->n, p->w * p->n #define PCTM u0, v0, fa, fb, fc, fd, w, h switch (gc->flag) { case FNONE: { DEBUG(" fnone %d x %d\n", w, h); if (image->cs) error = fz_newpixmapwithrect(&gc->dest, clip, gc->model->n + 1); else error = fz_newpixmapwithrect(&gc->dest, clip, 1); if (error) goto cleanup; if (image->cs) fz_img_4c4(PSRC, PDST(gc->dest), PCTM); else fz_img_1c1(PSRC, PDST(gc->dest), PCTM); } break; case FOVER: { DEBUG(" fover %d x %d\n", w, h); if (image->cs) fz_img_4o4(PSRC, PDST(gc->over), PCTM); else fz_img_1o1(PSRC, PDST(gc->over), PCTM); } break; case FOVER | FRGB: DEBUG(" fover+rgb %d x %d\n", w, h); fz_img_w3i1o4(gc->rgb, PSRC, PDST(gc->over), PCTM); break; default: assert(!"impossible flag in image span function"); } DEBUG("}\n"); fz_droppixmap(tile); return nil; cleanup: fz_droppixmap(tile); return error; }