void Mpdf::showPage() { fz_page *page = fz_load_page(doc, currentPage - 1); fz_matrix transform; fz_rotate(&transform, 0); fz_pre_scale(&transform, currentZoom / 100.0f, currentZoom / 100.0f); fz_rect bounds; fz_bound_page(doc, page, &bounds); fz_transform_rect(&bounds, &transform); fz_irect bbox; fz_round_rect(&bbox, &bounds); fz_pixmap *pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb, &bbox); fz_clear_pixmap_with_value(ctx, pix, 0xff); fz_device *dev = fz_new_draw_device(ctx, pix); fz_run_page(doc, page, dev, &transform, NULL); fz_free_device(dev); QString qpng = QString("%1.png").arg(currentPage); const char *ccpng = qpng.toStdString().c_str(); char *cpng = new char[strlen(ccpng) + 1]; strcpy(cpng, ccpng); fz_write_png(ctx, pix, cpng, 0); QPixmap qpix(qpng); pdfLabel->setPixmap(qpix); fz_drop_pixmap(ctx, pix); fz_free_page(doc, page); }
fz_pixmap * fz_new_pixmap_from_page_contents(fz_context *ctx, fz_page *page, const fz_matrix *ctm, fz_colorspace *cs) { fz_rect rect; fz_irect irect; fz_pixmap *pix; fz_device *dev; fz_bound_page(ctx, page, &rect); fz_transform_rect(&rect, ctm); fz_round_rect(&irect, &rect); pix = fz_new_pixmap_with_bbox(ctx, cs, &irect); fz_clear_pixmap_with_value(ctx, pix, 0xFF); fz_try(ctx) { dev = fz_new_draw_device(ctx, pix); fz_run_page_contents(ctx, page, dev, ctm, NULL); } fz_always(ctx) { fz_drop_device(ctx, dev); } fz_catch(ctx) { fz_drop_pixmap(ctx, pix); fz_rethrow(ctx); } return pix; }
void benchrenderpage(fz_context *ctx, pdf_document *xref, pdf_page *page, int pagenum) { fz_device *dev; fz_pixmap *pix; fz_bbox bbox; mstimer timer; timerstart(&timer); bbox = fz_round_rect(pdf_bound_page(xref, page)); pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb, bbox); fz_clear_pixmap_with_value(ctx, pix, 0xFF); dev = fz_new_draw_device(ctx, pix); fz_try(ctx) { pdf_run_page(xref, page, dev, fz_identity, NULL); timerstop(&timer); logbench("pagerender %3d: %.2f ms\n", pagenum, timeinms(&timer)); } fz_catch(ctx) { logbench("Error: pdf_run_page() failed\n"); } fz_drop_pixmap(ctx, pix); fz_free_device(dev); }
fz_pixmap * fz_new_pixmap_from_annot(fz_context *ctx, fz_annot *annot, const fz_matrix *ctm, fz_colorspace *cs, int alpha) { fz_rect rect; fz_irect irect; fz_pixmap *pix; fz_device *dev; fz_bound_annot(ctx, annot, &rect); fz_transform_rect(&rect, ctm); fz_round_rect(&irect, &rect); pix = fz_new_pixmap_with_bbox(ctx, cs, &irect, alpha); if (alpha) fz_clear_pixmap(ctx, pix); else fz_clear_pixmap_with_value(ctx, pix, 0xFF); fz_try(ctx) { dev = fz_new_draw_device(ctx, ctm, pix); fz_run_annot(ctx, annot, dev, &fz_identity, NULL); } fz_always(ctx) { fz_drop_device(ctx, dev); } fz_catch(ctx) { fz_drop_pixmap(ctx, pix); fz_rethrow(ctx); } return pix; }
fz_pixmap * fz_new_pixmap_from_display_list(fz_context *ctx, fz_display_list *list, const fz_matrix *ctm, fz_colorspace *cs, int background) { fz_rect rect; fz_irect irect; fz_pixmap *pix; fz_device *dev; fz_bound_display_list(ctx, list, &rect); fz_transform_rect(&rect, ctm); fz_round_rect(&irect, &rect); pix = fz_new_pixmap_with_bbox(ctx, cs, &irect); if (background) fz_clear_pixmap_with_value(ctx, pix, 0xFF); else fz_clear_pixmap(ctx, pix); fz_try(ctx) { dev = fz_new_draw_device(ctx, pix); fz_run_display_list(ctx, list, dev, ctm, NULL, NULL); } fz_always(ctx) { fz_drop_device(ctx, dev); } fz_catch(ctx) { fz_drop_pixmap(ctx, pix); fz_rethrow(ctx); } return pix; }
void * renderer(void *data) { int pagenumber = ((struct data *) data)->pagenumber; fz_context *ctx = ((struct data *) data)->ctx; fz_display_list *list = ((struct data *) data)->list; fz_bbox bbox = ((struct data *) data)->bbox; fz_pixmap *pix = ((struct data *) data)->pix; fprintf(stderr, "thread at page %d loading!\n", pagenumber); // The context pointer is pointing to the main thread's // context, so here we create a new context based on it for // use in this thread. ctx = fz_clone_context(ctx); // Next we run the display list through the draw device which // will render the request area of the page to the pixmap. fprintf(stderr, "thread at page %d rendering!\n", pagenumber); fz_device *dev = fz_new_draw_device(ctx, pix); fz_run_display_list(list, dev, fz_identity, bbox, NULL); fz_free_device(dev); // This threads context is freed. fz_free_context(ctx); fprintf(stderr, "thread at page %d done!\n", pagenumber); return data; }
fz_device * fz_new_draw_device_type3(fz_context *ctx, fz_glyph_cache *cache, fz_pixmap *dest) { fz_device *dev = fz_new_draw_device(ctx, cache, dest); fz_draw_device *ddev = dev->user; ddev->flags |= FZ_DRAWDEV_FLAGS_TYPE3; return dev; }
QImage Pdf::page(int i) { pdf_page* page = pdf_load_page(xref, i); if (page == 0) { printf("cannot load page %d\n", i); return QImage(); } static const float resolution = 300.0; const float zoom = resolution / 72.0; fz_matrix ctm = fz_translate(0, -page->mediabox.y1); ctm = fz_concat(ctm, fz_scale(zoom, -zoom)); ctm = fz_concat(ctm, fz_rotate(page->rotate)); fz_bbox bbox = fz_round_rect(fz_transform_rect(ctm, page->mediabox)); fz_pixmap* pix = fz_new_pixmap_with_rect(ctx, fz_device_gray, bbox); fz_clear_pixmap_with_color(pix, 255); fz_device* dev = fz_new_draw_device(ctx, cache, pix); pdf_run_page(xref, page, dev, ctm); fz_free_device(dev); int w = pix->w; int h = pix->h; QImage image(w, h, QImage::Format_MonoLSB); QVector<QRgb> ct(2); ct[0] = qRgb(255, 255, 255); ct[1] = qRgb(0, 0, 0); image.setColorTable(ct); uchar* s = pix->samples; int stride = image.bytesPerLine(); int bytes = w >> 3; for (int line = 0; line < h; ++line) { uchar* d = image.bits() + stride * line; for (int col = 0; col < bytes; ++col) { uchar data = 0; for (int i = 0; i < 8; ++i) { uchar v = *s++; s++; data >>= 1; if (v < 128) data |= 0x80; } *d++ = data; } } fz_drop_pixmap(ctx, pix); pdf_free_page(ctx, page); return image; }
static fz_pixmap *page_to_pixmap(fz_context *context, fz_document *doc, int pagenum) { fz_page *page; fz_pixmap *image; fz_device *dev; fz_rect bounds; fz_bbox bbox; fz_matrix ctm; float scale; printf("Rendering page %d\n", pagenum); page = fz_load_page(doc, pagenum); bounds = fz_bound_page(doc, page); /* XXX: There is a small risk of lw/lh being incorrect * due to a race condition during a refresh. * This shouldn't affect any visible pages though, as it causes renders * that will be discarded by finish_page_render to be faulty. */ ims = scale = lw / bounds.x1; printf("W, H: (%f, %f)\n", lw, lh); printf("Scale: %f\n", scale); ctm = fz_scale(scale, scale); pages[pagenum].w = bounds.x1; pages[pagenum].h = bounds.y1; bounds.x1 *= scale; bounds.y1 *= scale; pages[pagenum].sw = bounds.x1; pages[pagenum].sh = bounds.y1; bbox = fz_round_rect(bounds); printf("Size: (%d, %d)\n", bbox.x1, bbox.y1); image = fz_new_pixmap_with_bbox(context, fz_device_rgb, bbox); dev = fz_new_draw_device(context, image); fz_clear_pixmap_with_value(context, image, 255); fz_run_page(doc, page, dev, ctm, NULL); fz_free_device(dev); fz_free_page(doc, page); return image; }
static void _pdf_doc_render_page( struct _pdf_doc *self, cairo_t *cr, int x, int y, int pageno, mume_matrix_t ctm, mume_rect_t rect) { /* TODO: implement a fz_device to rendering directly to cairo. */ fz_colorspace *colorspace; fz_bbox bbox; fz_device *idev; fz_pixmap *pixmap; fz_display_list *list; cairo_format_t format; cairo_surface_t *surface; int stride; #ifdef _WIN32 colorspace = fz_device_bgr; #else colorspace = fz_device_rgb; #endif list = _pdf_doc_get_list(self, pageno); bbox = _mume_rect_to_fz_bbox(rect); pixmap = fz_new_pixmap_with_rect(colorspace, bbox); if (NULL == pixmap) { mume_error(("fz_new_pixmap_with_rect(%d, %d, %d, %d)\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1)); return; } fz_clear_pixmap_with_color(pixmap, 255); idev = fz_new_draw_device(self->glyph_cache, pixmap); fz_execute_display_list( list, idev, _mume_matrix_to_fz_matrix(ctm), bbox); fz_free_device(idev); /* Create cairo surface. */ format = CAIRO_FORMAT_ARGB32; stride = cairo_format_stride_for_width(format, pixmap->w); surface = cairo_image_surface_create_for_data( pixmap->samples, format, pixmap->w, pixmap->h, stride); if (surface) { cairo_set_source_surface(cr, surface, x, y); cairo_rectangle(cr, x, y, rect.width, rect.height); cairo_fill(cr); cairo_surface_destroy(surface); } fz_drop_pixmap(pixmap); }
QImage Document::RenderPage (int num, double xRes, double yRes) { auto page = WrapPage (pdf_load_page (MuDoc_, num), MuDoc_); if (!page) return QImage (); #if MUPDF_VERSION < 0x0102 const auto& rect = pdf_bound_page (MuDoc_, page.get ()); #else fz_rect rect; pdf_bound_page (MuDoc_, page.get (), &rect); #endif auto px = fz_new_pixmap (MuCtx_, fz_device_bgr, xRes * (rect.x1 - rect.x0), yRes * (rect.y1 - rect.y0)); fz_clear_pixmap (MuCtx_, px); auto dev = fz_new_draw_device (MuCtx_, px); #if MUPDF_VERSION < 0x0102 pdf_run_page (MuDoc_, page.get (), dev, fz_scale (xRes, yRes), NULL); #else fz_matrix matrix; pdf_run_page (MuDoc_, page.get (), dev, fz_scale (&matrix, xRes, yRes), NULL); #endif fz_free_device (dev); const int pxWidth = fz_pixmap_width (MuCtx_, px); const int pxHeight = fz_pixmap_height (MuCtx_, px); auto samples = fz_pixmap_samples (MuCtx_, px); QImage temp (samples, pxWidth, pxHeight, QImage::Format_ARGB32); QImage img (QSize (pxWidth, pxHeight), QImage::Format_ARGB32); for (int y = 0; y < pxHeight; ++y) { auto target = reinterpret_cast<QRgb*> (img.scanLine (y)); const auto source = reinterpret_cast<QRgb*> (temp.scanLine (y)); std::memcpy (target, source, sizeof (source [0]) * pxWidth); } fz_drop_pixmap (MuCtx_, px); temp = QImage (QSize (pxWidth, pxHeight), QImage::Format_ARGB32); QPainter p; p.begin (&temp); p.fillRect (QRect (QPoint (0, 0), temp.size ()), Qt::white); p.drawImage (0, 0, img); p.end (); return temp; }
fz_device * fz_new_draw_device_with_bbox(fz_context *ctx, fz_pixmap *dest, fz_bbox clip) { fz_device *dev = fz_new_draw_device(ctx, dest); fz_draw_device *ddev = dev->user; if (clip.x0 > ddev->stack[0].scissor.x0) ddev->stack[0].scissor.x0 = clip.x0; if (clip.x1 < ddev->stack[0].scissor.x1) ddev->stack[0].scissor.x1 = clip.x1; if (clip.y0 > ddev->stack[0].scissor.y0) ddev->stack[0].scissor.y0 = clip.y0; if (clip.y1 < ddev->stack[0].scissor.y1) ddev->stack[0].scissor.y1 = clip.y1; return dev; }
void PDFDocument::Render( Document::PixelWriter* pw, int page, float zoom, int rotation) { assert((page >= 0) && (page < GetNumPages())); std::unique_lock<std::mutex> lock(_render_mutex); // 1. Init MuPDF structures. const fz_matrix& m = Transform(zoom, rotation); pdf_page* page_struct = GetPage(page); const fz_irect& bbox = GetBoundingBox(page_struct, m); fz_pixmap* pixmap = fz_new_pixmap_with_bbox( _fz_context, fz_device_rgb(_fz_context), FZ_OBJ(bbox), nullptr, 1); fz_device* dev = fz_new_draw_device(_fz_context, FZ_OBJ(fz_identity), pixmap); // 2. Render page. fz_clear_pixmap_with_value(_fz_context, pixmap, 0xff); pdf_run_page( _fz_context, _pdf_document, page_struct, dev, FZ_OBJ(m), nullptr); // 3. Write pixmap to buffer. The page is vertically divided into n equal // stripes, each copied to pw by one thread. assert(fz_pixmap_components(_fz_context, pixmap) == 4); uint8_t* buffer = reinterpret_cast<uint8_t*>(fz_pixmap_samples(_fz_context, pixmap)); const int num_cols = fz_pixmap_width(_fz_context, pixmap); const int num_rows = fz_pixmap_height(_fz_context, pixmap); ExecuteInParallel([=](int num_threads, int i) { const int num_rows_per_thread = num_rows / num_threads; const int y_begin = i * num_rows_per_thread; const int y_end = (i == num_threads - 1) ? num_rows : (i + 1) * num_rows_per_thread; uint8_t* p = buffer + y_begin * num_cols * 4; for (int y = y_begin; y < y_end; ++y) { for (int x = 0; x < num_cols; ++x) { pw->Write(x, y, p[0], p[1], p[2]); p += 4; } } }); // 4. Clean up. fz_close_device(_fz_context, dev); fz_drop_device(_fz_context, dev); fz_drop_pixmap(_fz_context, pixmap); }
QImage render(qreal dpiX, qreal dpiY, const QRectF& rect) { if (m_init) { fz_scale(&m_matrix, dpiX / 72.0f, dpiY / 72.0f); fz_bound_page(m_ctx, m_page, &m_bound); fz_transform_rect(&m_bound, &m_matrix); m_init = false; } if (!m_list) { m_list = fz_new_display_list(m_ctx); } if (!m_dev) { m_dev = fz_new_list_device(m_ctx, m_list); fz_run_page(m_ctx, m_page, m_dev, &m_matrix, 0); } fz_matrix tile; fz_translate(&tile, -m_bound.x0, -m_bound.y0); fz_pre_translate(&tile, -rect.x(), -rect.y()); fz_rect tr; tr.x0 = tr.y0 = 0.0; int width = tr.x1 = rect.width(); int height = tr.y1 = rect.height(); QImage image(width, height, QImage::Format_RGB32); image.fill(Qt::white); // TODO: configurable fz_pixmap* pixmap = fz_new_pixmap_with_data(m_ctx, fz_device_bgr(m_ctx), image.width(), image.height(), image.bits()); fz_device *device = fz_new_draw_device(m_ctx, pixmap); fz_run_display_list(m_ctx, m_list, device, &tile, &tr, 0); fz_drop_device(m_ctx, device); fz_drop_pixmap(m_ctx, pixmap); return image; }
static void drawpage(xps_context *ctx, int pagenum) { xps_page *page; fz_display_list *list; fz_device *dev; int start; int code; if (showtime) { start = gettime(); } code = xps_load_page(&page, ctx, pagenum - 1); if (code) die(fz_rethrow(code, "cannot load page %d in file '%s'", pagenum, filename)); list = NULL; if (uselist) { list = fz_new_display_list(); dev = fz_new_list_device(list); xps_run_page(ctx, page, dev, fz_identity); fz_free_device(dev); } if (showxml) { dev = fz_new_trace_device(); printf("<page number=\"%d\">\n", pagenum); if (list) fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox); else xps_run_page(ctx, page, dev, fz_identity); printf("</page>\n"); fz_free_device(dev); } if (showtext) { fz_text_span *text = fz_new_text_span(); dev = fz_new_text_device(text); if (list) fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox); else xps_run_page(ctx, page, dev, fz_identity); fz_free_device(dev); printf("[Page %d]\n", pagenum); if (showtext > 1) fz_debug_text_span_xml(text); else fz_debug_text_span(text); printf("\n"); fz_free_text_span(text); } if (showmd5 || showtime) printf("page %s %d", filename, pagenum); if (output || showmd5 || showtime) { float zoom; fz_matrix ctm; fz_rect rect; fz_bbox bbox; fz_pixmap *pix; rect.x0 = rect.y0 = 0; rect.x1 = page->width; rect.y1 = page->height; zoom = resolution / 96; ctm = fz_translate(0, -page->height); ctm = fz_concat(ctm, fz_scale(zoom, zoom)); bbox = fz_round_rect(fz_transform_rect(ctm, rect)); /* TODO: banded rendering and multi-page ppm */ pix = fz_new_pixmap_with_rect(colorspace, bbox); if (savealpha) fz_clear_pixmap(pix); else fz_clear_pixmap_with_color(pix, 255); dev = fz_new_draw_device(glyphcache, pix); if (list) fz_execute_display_list(list, dev, ctm, bbox); else xps_run_page(ctx, page, dev, ctm); fz_free_device(dev); if (output) { char buf[512]; sprintf(buf, output, pagenum); if (strstr(output, ".pgm") || strstr(output, ".ppm") || strstr(output, ".pnm")) fz_write_pnm(pix, buf); else if (strstr(output, ".pam")) fz_write_pam(pix, buf, savealpha); else if (strstr(output, ".png")) fz_write_png(pix, buf, savealpha); } if (showmd5) { fz_md5 md5; unsigned char digest[16]; int i; fz_md5_init(&md5); fz_md5_update(&md5, pix->samples, pix->w * pix->h * pix->n); fz_md5_final(&md5, digest); printf(" "); for (i = 0; i < 16; i++) printf("%02x", digest[i]); } fz_drop_pixmap(pix); } if (list) fz_free_display_list(list); if (showtime) { int end = gettime(); int diff = end - start; if (diff < timing.min) { timing.min = diff; timing.minpage = pagenum; } if (diff > timing.max) { timing.max = diff; timing.maxpage = pagenum; } timing.total += diff; timing.count ++; printf(" %dms", diff); } if (showmd5 || showtime) printf("\n"); }
void render(char *filename, int pagenumber, int zoom, int rotation) { // Create a context to hold the exception stack and various caches. fz_context *ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED); // Open the PDF, XPS or CBZ document. fz_document *doc = fz_open_document(ctx, filename); // Retrieve the number of pages (not used in this example). int pagecount = fz_count_pages(doc); // Load the page we want. Page numbering starts from zero. fz_page *page = fz_load_page(doc, pagenumber - 1); // Calculate a transform to use when rendering. This transform // contains the scale and rotation. Convert zoom percentage to a // scaling factor. Without scaling the resolution is 72 dpi. fz_matrix transform; fz_rotate(&transform, rotation); fz_pre_scale(&transform, zoom / 100.0f, zoom / 100.0f); // Take the page bounds and transform them by the same matrix that // we will use to render the page. fz_rect bounds; fz_bound_page(doc, page, &bounds); fz_transform_rect(&bounds, &transform); // Create a blank pixmap to hold the result of rendering. The // pixmap bounds used here are the same as the transformed page // bounds, so it will contain the entire page. The page coordinate // space has the origin at the top left corner and the x axis // extends to the right and the y axis extends down. fz_irect bbox; fz_round_rect(&bbox, &bounds); fz_pixmap *pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), &bbox); fz_clear_pixmap_with_value(ctx, pix, 0xff); // A page consists of a series of objects (text, line art, images, // gradients). These objects are passed to a device when the // interpreter runs the page. There are several devices, used for // different purposes: // // draw device -- renders objects to a target pixmap. // // text device -- extracts the text in reading order with styling // information. This text can be used to provide text search. // // list device -- records the graphic objects in a list that can // be played back through another device. This is useful if you // need to run the same page through multiple devices, without // the overhead of parsing the page each time. // Create a draw device with the pixmap as its target. // Run the page with the transform. fz_device *dev = fz_new_draw_device(ctx, pix); fz_run_page(doc, page, dev, &transform, NULL); fz_free_device(dev); // Save the pixmap to a file. fz_write_png(ctx, pix, "out.png", 0); // Clean up. fz_drop_pixmap(ctx, pix); fz_free_page(doc, page); fz_close_document(doc); fz_free_context(ctx); }
static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) { fz_page *page; fz_link *links; fz_display_list *list = NULL; fz_device *dev = NULL; int start; fz_var(list); fz_var(dev); if (showtime) { start = gettime(); } fz_try(ctx) { page = fz_load_page(doc, pagenum - 1); } fz_catch(ctx) { fz_throw(ctx, "cannot load page %d in file '%s'", pagenum, filename); } fz_try(ctx) { links = fz_load_links(doc, page); } fz_catch(ctx) { fz_throw(ctx, "cannot load links for page %d in file '%s'", pagenum, filename); } if (uselist) { fz_try(ctx) { list = fz_new_display_list(ctx); dev = fz_new_list_device(ctx, list); fz_run_page(doc, page, dev, fz_identity, NULL); } fz_catch(ctx) { fz_free_device(dev); fz_free_display_list(ctx, list); fz_free_page(doc, page); fz_throw(ctx, "cannot draw page %d in file '%s'", pagenum, filename); } fz_free_device(dev); dev = NULL; } if (showjson) { fz_text_page *text = NULL; fz_var(text); fz_try(ctx) { text = fz_new_text_page(ctx, fz_bound_page(doc, page)); dev = fz_new_text_device(ctx, sheet, text); if (list) fz_run_display_list(list, dev, fz_identity, fz_infinite_bbox, NULL); else fz_run_page(doc, page, dev, fz_identity, NULL); fz_free_device(dev); dev = NULL; fz_print_text_page_json(ctx, stdout, text, links); printf("\f\n"); } fz_catch(ctx) { fz_free_device(dev); fz_free_text_page(ctx, text); fz_free_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow(ctx); } fz_free_text_page(ctx, text); } if (showmd5 || showtime) printf("page %s %d", filename, pagenum); if (output || showmd5 || showtime) { float zoom; fz_matrix ctm; fz_rect bounds, bounds2; fz_bbox bbox; fz_pixmap *pix = NULL; int w, h; fz_var(pix); bounds = fz_bound_page(doc, page); zoom = resolution / 72; ctm = fz_scale(zoom, zoom); ctm = fz_concat(ctm, fz_rotate(rotation)); bounds2 = fz_transform_rect(ctm, bounds); bbox = fz_round_rect(bounds2); /* Make local copies of our width/height */ w = width; h = height; /* If a resolution is specified, check to see whether w/h are * exceeded; if not, unset them. */ if (res_specified) { int t; t = bbox.x1 - bbox.x0; if (w && t <= w) w = 0; t = bbox.y1 - bbox.y0; if (h && t <= h) h = 0; } /* Now w or h will be 0 unless then need to be enforced. */ if (w || h) { float scalex = w/(bounds2.x1-bounds2.x0); float scaley = h/(bounds2.y1-bounds2.y0); if (fit) { if (w == 0) scalex = 1.0f; if (h == 0) scaley = 1.0f; } else { if (w == 0) scalex = scaley; if (h == 0) scaley = scalex; } if (!fit) { if (scalex > scaley) scalex = scaley; else scaley = scalex; } ctm = fz_concat(ctm, fz_scale(scalex, scaley)); bounds2 = fz_transform_rect(ctm, bounds); } bbox = fz_round_rect(bounds2); /* TODO: banded rendering and multi-page ppm */ fz_try(ctx) { pix = fz_new_pixmap_with_bbox(ctx, colorspace, bbox); if (savealpha) fz_clear_pixmap(ctx, pix); else fz_clear_pixmap_with_value(ctx, pix, 255); dev = fz_new_draw_device(ctx, pix); if (list) fz_run_display_list(list, dev, ctm, bbox, NULL); else fz_run_page(doc, page, dev, ctm, NULL); fz_free_device(dev); dev = NULL; if (invert) fz_invert_pixmap(ctx, pix); if (gamma_value != 1) fz_gamma_pixmap(ctx, pix, gamma_value); if (savealpha) fz_unmultiply_pixmap(ctx, pix); if (output) { char buf[512]; sprintf(buf, output, pagenum); if (strstr(output, ".pgm") || strstr(output, ".ppm") || strstr(output, ".pnm")) fz_write_pnm(ctx, pix, buf); else if (strstr(output, ".pam")) fz_write_pam(ctx, pix, buf, savealpha); else if (strstr(output, ".png")) fz_write_png(ctx, pix, buf, savealpha); else if (strstr(output, ".pbm")) { fz_bitmap *bit = fz_halftone_pixmap(ctx, pix, NULL); fz_write_pbm(ctx, bit, buf); fz_drop_bitmap(ctx, bit); } } if (showmd5) { unsigned char digest[16]; int i; fz_md5_pixmap(pix, digest); printf(" "); for (i = 0; i < 16; i++) printf("%02x", digest[i]); } fz_drop_pixmap(ctx, pix); } fz_catch(ctx) { fz_free_device(dev); fz_drop_pixmap(ctx, pix); fz_free_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow(ctx); } }
static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) { fz_page *page; fz_display_list *list = NULL; fz_device *dev = NULL; int start; fz_cookie cookie = { 0 }; int needshot = 0; fz_var(list); fz_var(dev); if (showtime) { start = gettime(); } fz_try(ctx) { page = fz_load_page(doc, pagenum - 1); } fz_catch(ctx) { fz_throw(ctx, "cannot load page %d in file '%s'", pagenum, filename); } if (mujstest_file) { fz_interactive *inter = fz_interact(doc); fz_widget *widget = NULL; if (inter) widget = fz_first_widget(inter, page); if (widget) { fprintf(mujstest_file, "GOTO %d\n", pagenum); needshot = 1; } for (;widget; widget = fz_next_widget(inter, widget)) { fz_rect rect = fz_widget_bbox(widget); int w = (rect.x1-rect.x0); int h = (rect.y1-rect.y0); int len; int type = fz_widget_get_type(widget); ++mujstest_count; switch (type) { default: fprintf(mujstest_file, "%% UNKNOWN %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1); break; case FZ_WIDGET_TYPE_PUSHBUTTON: fprintf(mujstest_file, "%% PUSHBUTTON %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1); break; case FZ_WIDGET_TYPE_CHECKBOX: fprintf(mujstest_file, "%% CHECKBOX %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1); break; case FZ_WIDGET_TYPE_RADIOBUTTON: fprintf(mujstest_file, "%% RADIOBUTTON %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1); break; case FZ_WIDGET_TYPE_TEXT: { int maxlen = fz_text_widget_max_len(inter, widget); int texttype = fz_text_widget_content_type(inter, widget); /* If height is low, assume a single row, and base * the width off that. */ if (h < 10) { w = (w+h-1) / (h ? h : 1); h = 1; } /* Otherwise, if width is low, work off height */ else if (w < 10) { h = (w+h-1) / (w ? w : 1); w = 1; } else { w = (w+9)/10; h = (h+9)/10; } len = w*h; if (len < 2) len = 2; if (len > maxlen) len = maxlen; fprintf(mujstest_file, "%% TEXT %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1); switch (texttype) { default: case FZ_WIDGET_CONTENT_UNRESTRAINED: fprintf(mujstest_file, "TEXT %d ", mujstest_count); escape_string(mujstest_file, len-3, lorem); fprintf(mujstest_file, "\n"); break; case FZ_WIDGET_CONTENT_NUMBER: fprintf(mujstest_file, "TEXT %d\n", mujstest_count); break; case FZ_WIDGET_CONTENT_SPECIAL: fprintf(mujstest_file, "TEXT %lld\n", 46702919800LL + mujstest_count); break; case FZ_WIDGET_CONTENT_DATE: fprintf(mujstest_file, "TEXT Jun %d 1979\n", 1 + ((13 + mujstest_count) % 30)); break; case FZ_WIDGET_CONTENT_TIME: ++mujstest_count; fprintf(mujstest_file, "TEXT %02d:%02d\n", ((mujstest_count/60) % 24), mujstest_count % 60); break; } break; } case FZ_WIDGET_TYPE_LISTBOX: fprintf(mujstest_file, "%% LISTBOX %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1); break; case FZ_WIDGET_TYPE_COMBOBOX: fprintf(mujstest_file, "%% COMBOBOX %0.2f %0.2f %0.2f %0.2f\n", rect.x0, rect.y0, rect.x1, rect.y1); break; } fprintf(mujstest_file, "CLICK %0.2f %0.2f\n", (rect.x0+rect.x1)/2, (rect.y0+rect.y1)/2); } } if (uselist) { fz_try(ctx) { list = fz_new_display_list(ctx); dev = fz_new_list_device(ctx, list); fz_run_page(doc, page, dev, fz_identity, &cookie); } fz_always(ctx) { fz_free_device(dev); dev = NULL; } fz_catch(ctx) { fz_free_display_list(ctx, list); fz_free_page(doc, page); fz_throw(ctx, "cannot draw page %d in file '%s'", pagenum, filename); } } if (showxml) { fz_try(ctx) { dev = fz_new_trace_device(ctx); fz_printf(out, "<page number=\"%d\">\n", pagenum); if (list) fz_run_display_list(list, dev, fz_identity, fz_infinite_rect, &cookie); else fz_run_page(doc, page, dev, fz_identity, &cookie); fz_printf(out, "</page>\n"); } fz_always(ctx) { fz_free_device(dev); dev = NULL; } fz_catch(ctx) { fz_free_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow(ctx); } } if (showtext) { fz_text_page *text = NULL; fz_var(text); fz_try(ctx) { text = fz_new_text_page(ctx, fz_bound_page(doc, page)); dev = fz_new_text_device(ctx, sheet, text); if (list) fz_run_display_list(list, dev, fz_identity, fz_infinite_rect, &cookie); else fz_run_page(doc, page, dev, fz_identity, &cookie); fz_free_device(dev); dev = NULL; if (showtext == TEXT_XML) { fz_print_text_page_xml(ctx, out, text); } else if (showtext == TEXT_HTML) { fz_print_text_page_html(ctx, out, text); } else if (showtext == TEXT_PLAIN) { fz_print_text_page(ctx, out, text); fz_printf(out, "\f\n"); } } fz_always(ctx) { fz_free_device(dev); dev = NULL; fz_free_text_page(ctx, text); } fz_catch(ctx) { fz_free_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow(ctx); } } if (showmd5 || showtime) printf("page %s %d", filename, pagenum); #ifdef GDI_PLUS_BMP_RENDERER // hack: use -G0 to "enable GDI+" when saving as TGA if (output && (strstr(output, ".bmp") || strstr(output, ".tga") && !gamma_value)) drawbmp(ctx, doc, page, list, pagenum); else #endif if (output || showmd5 || showtime) { float zoom; fz_matrix ctm; fz_rect bounds, tbounds; fz_bbox ibounds; fz_pixmap *pix = NULL; int w, h; fz_var(pix); bounds = fz_bound_page(doc, page); zoom = resolution / 72; ctm = fz_scale(zoom, zoom); ctm = fz_concat(ctm, fz_rotate(rotation)); tbounds = fz_transform_rect(ctm, bounds); ibounds = fz_round_rect(tbounds); /* convert to integers */ /* Make local copies of our width/height */ w = width; h = height; /* If a resolution is specified, check to see whether w/h are * exceeded; if not, unset them. */ if (res_specified) { int t; t = ibounds.x1 - ibounds.x0; if (w && t <= w) w = 0; t = ibounds.y1 - ibounds.y0; if (h && t <= h) h = 0; } /* Now w or h will be 0 unless they need to be enforced. */ if (w || h) { float scalex = w / (tbounds.x1 - tbounds.x0); float scaley = h / (tbounds.y1 - tbounds.y0); if (fit) { if (w == 0) scalex = 1.0f; if (h == 0) scaley = 1.0f; } else { if (w == 0) scalex = scaley; if (h == 0) scaley = scalex; } if (!fit) { if (scalex > scaley) scalex = scaley; else scaley = scalex; } ctm = fz_concat(ctm, fz_scale(scalex, scaley)); tbounds = fz_transform_rect(ctm, bounds); } ibounds = fz_round_rect(tbounds); /* TODO: banded rendering and multi-page ppm */ fz_try(ctx) { pix = fz_new_pixmap_with_bbox(ctx, colorspace, ibounds); if (savealpha) fz_clear_pixmap(ctx, pix); else fz_clear_pixmap_with_value(ctx, pix, 255); dev = fz_new_draw_device(ctx, pix); if (list) fz_run_display_list(list, dev, ctm, tbounds, &cookie); else fz_run_page(doc, page, dev, ctm, &cookie); fz_free_device(dev); dev = NULL; if (invert) fz_invert_pixmap(ctx, pix); if (gamma_value != 1) fz_gamma_pixmap(ctx, pix, gamma_value); if (savealpha) fz_unmultiply_pixmap(ctx, pix); if (output) { char buf[512]; sprintf(buf, output, pagenum); if (strstr(output, ".pgm") || strstr(output, ".ppm") || strstr(output, ".pnm")) fz_write_pnm(ctx, pix, buf); else if (strstr(output, ".pam")) fz_write_pam(ctx, pix, buf, savealpha); else if (strstr(output, ".png")) fz_write_png(ctx, pix, buf, savealpha); else if (strstr(output, ".pbm")) { fz_bitmap *bit = fz_halftone_pixmap(ctx, pix, NULL); fz_write_pbm(ctx, bit, buf); fz_drop_bitmap(ctx, bit); } /* SumatraPDF: support TGA as output format */ else if (strstr(output, ".tga")) fz_write_tga(ctx, pix, buf, savealpha); } if (showmd5) { unsigned char digest[16]; int i; fz_md5_pixmap(pix, digest); printf(" "); for (i = 0; i < 16; i++) printf("%02x", digest[i]); } } fz_always(ctx) { fz_free_device(dev); dev = NULL; fz_drop_pixmap(ctx, pix); } fz_catch(ctx) { fz_free_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow(ctx); } }
static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) { fz_page *page; fz_display_list *list = NULL; fz_device *dev = NULL; int start; fz_cookie cookie = { 0 }; fz_var(list); fz_var(dev); fz_try(ctx) { page = fz_load_page(doc, pagenum - 1); } fz_catch(ctx) { fz_throw(ctx, "cannot load page %d in file '%s'", pagenum, filename); } float zoom; fz_matrix ctm; fz_rect bounds, bounds2; fz_bbox bbox; fz_pixmap *pix = NULL; int w, h; fz_var(pix); bounds = fz_bound_page(doc, page); zoom = resolution / 72; ctm = fz_scale(zoom, zoom); ctm = fz_concat(ctm, fz_rotate(rotation)); bounds2 = fz_transform_rect(ctm, bounds); bbox = fz_round_rect(bounds2); /* Make local copies of our width/height */ w = width; h = height; /* If a resolution is specified, check to see whether w/h are * exceeded; if not, unset them. */ if (res_specified) { int t; t = bbox.x1 - bbox.x0; if (w && t <= w) w = 0; t = bbox.y1 - bbox.y0; if (h && t <= h) h = 0; } /* Now w or h will be 0 unless then need to be enforced. */ if (w || h) { float scalex = w/(bounds2.x1-bounds2.x0); float scaley = h/(bounds2.y1-bounds2.y0); if (fit) { if (w == 0) scalex = 1.0f; if (h == 0) scaley = 1.0f; } else { if (w == 0) scalex = scaley; if (h == 0) scaley = scalex; } if (!fit) { if (scalex > scaley) scalex = scaley; else scaley = scalex; } ctm = fz_concat(ctm, fz_scale(scalex, scaley)); bounds2 = fz_transform_rect(ctm, bounds); } bbox = fz_round_rect(bounds2); /* TODO: banded rendering and multi-page ppm */ fz_try(ctx) { pix = fz_new_pixmap_with_bbox(ctx, colorspace, bbox); fz_clear_pixmap_with_value(ctx, pix, 255); dev = fz_new_draw_device(ctx, pix); if (list) fz_run_display_list(list, dev, ctm, bbox, &cookie); else fz_run_page(doc, page, dev, ctm, &cookie); fz_free_device(dev); dev = NULL; int size = fz_pixmap_height(ctx, pix) * fz_pixmap_width(ctx, pix); inplace_reorder(fz_pixmap_samples(ctx, pix), size); size_t x_offset = (width - fz_pixmap_width(ctx, pix)) / 2; size_t y_offset = (height - fz_pixmap_height(ctx, pix)) / 2;; if (toggle_decors) { x_offset += decor_left_width; y_offset += decor_top_height; } for (int i = 0; i < fz_pixmap_height(ctx, pix); ++i) { memcpy(&GFX(gfx_ctx, x_offset, y_offset + i), &fz_pixmap_samples(ctx, pix)[fz_pixmap_width(ctx, pix) * i * 4], fz_pixmap_width(ctx, pix) * 4); } } fz_always(ctx) { fz_free_device(dev); dev = NULL; fz_drop_pixmap(ctx, pix); } fz_catch(ctx) { fz_free_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow(ctx); } if (list) fz_free_display_list(ctx, list); fz_free_page(doc, page); fz_flush_warnings(ctx); if (cookie.errors) errored = 1; }
static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint) { char buf[256]; fz_device *idev; fz_device *tdev; fz_colorspace *colorspace; fz_matrix ctm; fz_bbox bbox; wincursor(app, WAIT); if (loadpage) { if (app->page_list) fz_free_display_list(app->page_list); if (app->page_text) fz_free_text_span(app->page_text); if (app->page_links) pdf_free_link(app->page_links); if (app->xref) pdfapp_loadpage_pdf(app); if (app->xps) pdfapp_loadpage_xps(app); /* Zero search hit position */ app->hit = -1; app->hitlen = 0; /* Extract text */ app->page_text = fz_new_text_span(); tdev = fz_new_text_device(app->page_text); fz_execute_display_list(app->page_list, tdev, fz_identity, fz_infinite_bbox); fz_free_device(tdev); } if (drawpage) { sprintf(buf, "%s - %d/%d (%d dpi)", app->doctitle, app->pageno, app->pagecount, app->resolution); wintitle(app, buf); ctm = pdfapp_viewctm(app); bbox = fz_round_rect(fz_transform_rect(ctm, app->page_bbox)); /* Draw */ if (app->image) fz_drop_pixmap(app->image); if (app->grayscale) colorspace = fz_device_gray; else #ifdef _WIN32 colorspace = fz_device_bgr; #else colorspace = fz_device_rgb; #endif app->image = fz_new_pixmap_with_rect(colorspace, bbox); fz_clear_pixmap_with_color(app->image, 255); idev = fz_new_draw_device(app->cache, app->image); fz_execute_display_list(app->page_list, idev, ctm, bbox); fz_free_device(idev); } if (repaint) { 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); } fz_flush_warnings(); }
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_device *dev = NULL; float zoom; fz_matrix ctm; fz_bbox bbox; fz_pixmap *pix = NULL; float xscale, yscale; fz_bbox rect; page_cache *pc = &pages[current]; int hq = (patchW < pageW || patchH < pageH); if (pc->page == NULL) return 0; fz_var(pix); fz_var(dev); 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(%d)=%dx%d patch=[%d,%d,%d,%d]", pc->number, pageW, pageH, patchX, patchY, patchW, patchH); fz_try(ctx) { fz_interactive *idoc = fz_interact(doc); // Call fz_update_page now to ensure future calls yield the // changes from the current state fz_update_page(idoc, pc->page); if (hq) { // This is a rendering of the hq patch. Ensure there's a second copy of the // page for use when updating this patch if (pc->hq_page) { if (idoc) fz_update_page(idoc, pc->hq_page); } else { // There is only ever one hq patch, so we need // cache only one page object for the sake of hq clear_hq_pages(); pc->hq_page = fz_load_page(doc, pc->number); } } if (pc->page_list == NULL) { /* Render to list */ pc->page_list = fz_new_display_list(ctx); dev = fz_new_list_device(ctx, pc->page_list); fz_run_page_contents(doc, pc->page, dev, fz_identity, NULL); } if (pc->annot_list == NULL) { fz_annot *annot; if (dev) { fz_free_device(dev); dev = NULL; } pc->annot_list = fz_new_display_list(ctx); dev = fz_new_list_device(ctx, pc->annot_list); for (annot = fz_first_annot(doc, pc->page); annot; annot = fz_next_annot(doc, annot)) fz_run_annot(doc, pc->page, annot, dev, fz_identity, NULL); } rect.x0 = patchX; rect.y0 = patchY; rect.x1 = patchX + patchW; rect.y1 = patchY + patchH; pix = fz_new_pixmap_with_bbox_and_data(ctx, colorspace, rect, pixels); if (pc->page_list == NULL && pc->annot_list == NULL) { fz_clear_pixmap_with_value(ctx, pix, 0xd0); break; } fz_clear_pixmap_with_value(ctx, pix, 0xff); zoom = resolution / 72; ctm = fz_scale(zoom, zoom); bbox = fz_round_rect(fz_transform_rect(ctm, pc->media_box)); /* 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)); bbox = fz_round_rect(fz_transform_rect(ctm, pc->media_box)); dev = fz_new_draw_device(ctx, pix); #ifdef TIME_DISPLAY_LIST { clock_t time; int i; LOGE("Executing display list"); time = clock(); for (i=0; i<100;i++) { #endif if (pc->page_list) fz_run_display_list(pc->page_list, dev, ctm, bbox, NULL); if (pc->annot_list) fz_run_display_list(pc->annot_list, dev, ctm, bbox, NULL); #ifdef TIME_DISPLAY_LIST } time = clock() - time; LOGE("100 renders in %d (%d per sec)", time, CLOCKS_PER_SEC); } #endif fz_free_device(dev); dev = NULL; fz_drop_pixmap(ctx, pix); LOGE("Rendered"); } fz_catch(ctx) { fz_free_device(dev); LOGE("Render failed"); } AndroidBitmap_unlockPixels(env, bitmap); return 1; }
JNIEXPORT jboolean JNICALL JNI_FN(MuPDF_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_device *dev = NULL; float zoom; fz_matrix ctm; fz_irect bbox; fz_rect rect; fz_pixmap *pix = NULL; float xscale, yscale; globals *glo = get_globals(env, thiz); fz_context *ctx = glo->ctx; fz_document *doc = glo->doc; page_cache *pc = &glo->pages[glo->current]; int hq = (patchW < pageW || patchH < pageH); fz_matrix scale; if (pc->page == NULL) return 0; fz_var(pix); fz_var(dev); 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(%d)=%dx%d patch=[%d,%d,%d,%d]", pc->number, pageW, pageH, patchX, patchY, patchW, patchH); fz_try(ctx) { if (pc->page_list == NULL) { /* Render to list */ pc->page_list = fz_new_display_list(ctx); dev = fz_new_list_device(ctx, pc->page_list); fz_run_page_contents(doc, pc->page, dev, &fz_identity, NULL); } if (pc->annot_list == NULL) { fz_annot *annot; if (dev) { fz_free_device(dev); dev = NULL; } pc->annot_list = fz_new_display_list(ctx); dev = fz_new_list_device(ctx, pc->annot_list); for (annot = fz_first_annot(doc, pc->page); annot; annot = fz_next_annot(doc, annot)) fz_run_annot(doc, pc->page, annot, dev, &fz_identity, NULL); } bbox.x0 = patchX; bbox.y0 = patchY; bbox.x1 = patchX + patchW; bbox.y1 = patchY + patchH; pix = fz_new_pixmap_with_bbox_and_data(ctx, glo->colorspace, &bbox, pixels); if (pc->page_list == NULL && pc->annot_list == NULL) { fz_clear_pixmap_with_value(ctx, pix, 0xd0); break; } fz_clear_pixmap_with_value(ctx, pix, 0xff); zoom = glo->resolution / 72; fz_scale(&ctm, zoom, zoom); rect = pc->media_box; fz_round_rect(&bbox, fz_transform_rect(&rect, &ctm)); /* 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); fz_concat(&ctm, &ctm, fz_scale(&scale, xscale, yscale)); rect = pc->media_box; fz_transform_rect(&rect, &ctm); dev = fz_new_draw_device(ctx, pix); #ifdef TIME_DISPLAY_LIST { clock_t time; int i; LOGE("Executing display list"); time = clock(); for (i=0; i<100;i++) { #endif if (pc->page_list) fz_run_display_list(pc->page_list, dev, &ctm, &rect, NULL); if (pc->annot_list) fz_run_display_list(pc->annot_list, dev, &ctm, &rect, NULL); #ifdef TIME_DISPLAY_LIST } time = clock() - time; LOGE("100 renders in %d (%d per sec)", time, CLOCKS_PER_SEC); } #endif fz_free_device(dev); dev = NULL; fz_drop_pixmap(ctx, pix); LOGE("Rendered"); } fz_catch(ctx) { fz_free_device(dev); LOGE("Render failed"); } AndroidBitmap_unlockPixels(env, bitmap); return 1; }
QImage Pdf::page(int i) { fz_page* page = fz_load_page(doc, i); if (page == 0) { printf("cannot load page %d\n", i); return QImage(); } static const float resolution = 300.0; const float zoom = resolution / 72.0; fz_rect bounds = fz_bound_page(doc, page); fz_matrix ctm = fz_scale(zoom, zoom); fz_bbox bbox = fz_round_rect(fz_transform_rect(ctm, bounds)); fz_pixmap* pix = fz_new_pixmap_with_bbox(ctx, fz_device_gray, bbox); fz_clear_pixmap_with_value(ctx, pix, 255); fz_device* dev = fz_new_draw_device(ctx, pix); fz_run_page(doc, page, dev, ctm, NULL); fz_free_device(dev); dev = NULL; int w = fz_pixmap_width(ctx, pix); int h = fz_pixmap_height(ctx, pix); if (fz_pixmap_components(ctx, pix) != 2) { printf("omg: pixmap not bw? %d\n", fz_pixmap_components(ctx, pix)); return QImage(); } QImage image(w, h, QImage::Format_MonoLSB); QVector<QRgb> ct(2); ct[0] = qRgb(255, 255, 255); ct[1] = qRgb(0, 0, 0); image.setColorTable(ct); uchar* s = fz_pixmap_samples(ctx, pix); int bytes = w / 8; int bits = w % 8; for (int line = 0; line < h; ++line) { uchar* d = image.scanLine(line); for (int col = 0; col < bytes; ++col) { uchar data = 0; for (int i = 0; i < 8; ++i) { uchar v = *s; s += 2; data >>= 1; if (v < 128) { // convert grayscale to bw data |= 0x80; } } *d++ = data; } uchar data = 0; for (int col = 0; col < bits; ++col) { uchar v = *s; s += 2; data >>= 1; if (v < 128) data |= 0x80; } } fz_drop_pixmap(ctx, pix); return image; }
DrPage * DrPDFExtractor::ExtractPage(unsigned int pageno) { fz_page * page = fz_load_page(m_doc, pageno); if (page == NULL) { return NULL; } DrPage * dpage = new DrPage; dpage->SetPageNo(pageno); std::list<DrChar *> charlist; std::list<DrPhrase *> phraselist; std::list<DrLine *> linelist; std::list<DrZone *> &zonelist = dpage->m_zonelist; fz_matrix transform; fz_rotate(&transform,0); fz_pre_scale(&transform, 1.0f, 1.0f); fz_rect bounds; fz_bound_page(m_doc, page, &bounds); fz_transform_rect(&bounds, &transform); fz_irect bbox; fz_round_rect(&bbox, &bounds); fz_matrix ttransform = transform; fz_pixmap *pix = fz_new_pixmap_with_bbox(m_ctx, fz_device_rgb(m_ctx), &bbox); fz_clear_pixmap_with_value(m_ctx, pix, 0xff); fz_device * dev = fz_new_draw_device(m_ctx,pix); fz_run_page(m_doc, page, dev, &transform, NULL); fz_free_device(dev); fz_text_sheet * sheet = fz_new_text_sheet(m_ctx); fz_text_page * tpage = fz_new_text_page(m_ctx); fz_device * cdev = fz_new_text_device(m_ctx, sheet, tpage); fz_run_page(m_doc, page, cdev, &ttransform, NULL); ExtractChars(charlist,tpage); fz_free_device(cdev); // DrThumbnail * thumb = new DrThumbnail(m_ctx,pix,pageno); // dpage->m_thumbnail = thumb; DrTextGrouper::TextGroup(phraselist, charlist); std::list<DrPhrase *>::iterator itphrase = phraselist.begin(); while (itphrase != phraselist.end()) { if ((*itphrase)->IsSpacePhrase()) { delete *itphrase; itphrase = phraselist.erase(itphrase); } else itphrase++; } DrTextGrouper::TextGroup(linelist, phraselist); DrTextGrouper::TextGroup(zonelist, linelist); dpage->CalculatePageBox(); // fz_free_text_sheet(m_ctx, tsheet); // fz_free_text_page(m_ctx, tpage); fz_free_page(m_doc, page); return dpage; }
HRESULT MuPDFDoc::DrawPage(unsigned char *bitmap, int x, int y, int width, int height, bool invert) { m_cts->abort = 0; fz_device *dev = nullptr; fz_pixmap *pixmap = nullptr; fz_var(dev); fz_var(pixmap); PageCache *pageCache = &m_pages[m_currentPage]; fz_try(m_context) { fz_interactive *idoc = fz_interact(m_document); // Call fz_update_page now to ensure future calls yield the // changes from the current state if (idoc) fz_update_page(idoc, pageCache->page); if (!pageCache->pageList) { /* Render to list */ pageCache->pageList = fz_new_display_list(m_context); dev = fz_new_list_device(m_context, pageCache->pageList); fz_run_page_contents(m_document, pageCache->page, dev, fz_identity, *&m_cts); } if (!pageCache->annotList) { if (dev) { fz_free_device(dev); dev = nullptr; } pageCache->annotList = fz_new_display_list(m_context); dev = fz_new_list_device(m_context, pageCache->annotList); for (fz_annot *annot = fz_first_annot(m_document, pageCache->page); annot; annot = fz_next_annot(m_document, annot)) fz_run_annot(m_document, pageCache->page, annot, dev, fz_identity, *&m_cts); } fz_bbox rect; rect.x0 = x; rect.y0 = y; rect.x1 = x + width; rect.y1 = y + height; pixmap = fz_new_pixmap_with_bbox_and_data(m_context, fz_device_bgr, rect, bitmap); if (!pageCache->pageList && !pageCache->annotList) { fz_clear_pixmap_with_value(m_context, pixmap, 0xd0); break; } fz_clear_pixmap_with_value(m_context, pixmap, 0xff); // fz_matrix ctm = CalcConvertMatrix(); fz_bbox bbox = fz_round_rect(fz_transform_rect(ctm, pageCache->mediaBox)); /* Now, adjust ctm so that it would give the correct page width * heights. */ float xscale = (float)width/(float)(bbox.x1-bbox.x0); float yscale = (float)height/(float)(bbox.y1-bbox.y0); ctm = fz_concat(ctm, fz_scale(xscale, yscale)); bbox = fz_round_rect(fz_transform_rect(ctm, pageCache->mediaBox)); if (dev) { fz_free_device(dev); dev = nullptr; } dev = fz_new_draw_device(m_context, pixmap); if (pageCache->pageList) fz_run_display_list(pageCache->pageList, dev, ctm, bbox, *&m_cts); about = m_cts->abort; if (pageCache->annotList) fz_run_display_list(pageCache->annotList, dev, ctm, bbox, *&m_cts); if (invert) fz_invert_pixmap(m_context, pixmap); } fz_always(m_context) { if (dev) { fz_free_device(dev); dev = nullptr; } if (pixmap) { fz_drop_pixmap(m_context, pixmap); } } fz_catch(m_context) { return E_FAIL; } return S_OK; }
int bmpmupdf_pdffile_to_bmp(WILLUSBITMAP *bmp,char *filename,int pageno,double dpi, int bpp) { fz_context *ctx; fz_colorspace *colorspace; fz_document *doc; fz_page *page; fz_display_list *list; fz_device *dev; fz_pixmap *pix; double dpp; fz_rect bounds,bounds2; fz_matrix ctm; fz_irect bbox; // fz_glyph_cache *glyphcache; // fz_error error; int np,status; dev=NULL; list=NULL; page=NULL; doc=NULL; status=0; if (pageno<1) return(-99); ctx = fz_new_context(NULL,NULL,FZ_STORE_DEFAULT); if (!ctx) return(-1); fz_try(ctx) { fz_register_document_handlers(ctx); fz_set_aa_level(ctx,8); /* Sumatra version of MuPDF v1.4 -- use locally installed fonts */ pdf_install_load_system_font_funcs(ctx); // fz_accelerate(); // glyphcache=fz_new_glyph_cache(); colorspace=(bpp==8 ? fz_device_gray(ctx) : fz_device_rgb(ctx)); fz_try(ctx) { doc=fz_open_document(ctx,filename); } fz_catch(ctx) { fz_free_context(ctx); return(-1); } /* if (fz_needs_password(doc) && !fz_authenticate_password(doc,password)) return(-2); */ // error=pdf_load_page_tree(xref); // if (error) // { // pdf_free_xref(xref); // return(-2); // } np=fz_count_pages(doc); if (pageno>np) return(-99); fz_try(ctx) { page = fz_load_page(doc,pageno-1); } fz_catch(ctx) { fz_close_document(doc); fz_free_context(ctx); return(-3); } fz_try(ctx) { list=fz_new_display_list(ctx); dev=fz_new_list_device(ctx,list); fz_run_page(doc,page,dev,&fz_identity,NULL); } fz_catch(ctx) { fz_free_device(dev); fz_drop_display_list(ctx,list); fz_free_page(doc,page); fz_close_document(doc); fz_free_context(ctx); return(-4); } fz_free_device(dev); dev=NULL; dpp=dpi/72.; pix=NULL; fz_var(pix); fz_bound_page(doc,page,&bounds); ctm=fz_identity; fz_scale(&ctm,dpp,dpp); // ctm=fz_concat(ctm,fz_rotate(rotation)); bounds2=bounds; fz_transform_rect(&bounds2,&ctm); fz_round_rect(&bbox,&bounds2); // ctm=fz_translate(0,-page->mediabox.y1); // ctm=fz_concat(ctm,fz_scale(dpp,-dpp)); // ctm=fz_concat(ctm,fz_rotate(page->rotate)); // ctm=fz_concat(ctm,fz_rotate(0)); // bbox=fz_round_rect(fz_transform_rect(ctm,page->mediabox)); // pix=fz_new_pixmap_with_rect(colorspace,bbox); fz_try(ctx) { pix=fz_new_pixmap_with_bbox(ctx,colorspace,&bbox); fz_clear_pixmap_with_value(ctx,pix,255); dev=fz_new_draw_device(ctx,pix); if (list) fz_run_display_list(list,dev,&ctm,&bounds2,NULL); else fz_run_page(doc,page,dev,&ctm,NULL); fz_free_device(dev); dev=NULL; status=bmpmupdf_pixmap_to_bmp(bmp,ctx,pix); fz_drop_pixmap(ctx,pix); } fz_catch(ctx) { fz_free_device(dev); fz_drop_pixmap(ctx,pix); fz_drop_display_list(ctx,list); fz_free_page(doc,page); fz_close_document(doc); fz_free_context(ctx); return(-5); } if (list) fz_drop_display_list(ctx,list); fz_free_page(doc,page); // pdf_free_xref(xref); fz_close_document(doc); fz_flush_warnings(ctx); } /* fz_catch before registering handlers */ fz_catch(ctx) /* Error registering */ { status = -10; } fz_free_context(ctx); // fz_free_glyph_cache(glyphcache); // fz_flush_warnings(); if (status<0) return(status-10); return(0); }
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_device *dev = NULL; float zoom; fz_matrix ctm; fz_bbox bbox; fz_pixmap *pix = NULL; float xscale, yscale; fz_bbox rect; fz_var(pix); fz_var(dev); 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); fz_try(ctx) { rect.x0 = patchX; rect.y0 = patchY; rect.x1 = patchX + patchW; rect.y1 = patchY + patchH; pix = fz_new_pixmap_with_rect_and_data(ctx, colorspace, rect, pixels); if (currentPageList == NULL) { fz_clear_pixmap_with_value(pix, 0xd0); break; } fz_clear_pixmap_with_value(pix, 0xff); zoom = resolution / 72; ctm = fz_scale(zoom, zoom); bbox = fz_round_rect(fz_transform_rect(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)); bbox = fz_round_rect(fz_transform_rect(ctm,currentMediabox)); dev = fz_new_draw_device(ctx, pix); #ifdef TIME_DISPLAY_LIST { clock_t time; int i; LOGE("Executing display list"); time = clock(); for (i=0; i<100;i++) { #endif fz_run_display_list(currentPageList, dev, ctm, bbox, NULL); #ifdef TIME_DISPLAY_LIST } time = clock() - time; LOGE("100 renders in %d (%d per sec)", time, CLOCKS_PER_SEC); } #endif fz_free_device(dev); dev = NULL; fz_drop_pixmap(ctx, pix); LOGE("Rendered"); } fz_catch(ctx) { fz_free_device(dev); LOGE("Render failed"); } AndroidBitmap_unlockPixels(env, bitmap); return 1; }
HRESULT MuPDFDoc::Renderer(Data *data, int part, int numParts) { if (m_cts->abort == 1) return S_OK; int pagenumber = data->pagenumber; fz_context *ctx = data->ctx; fz_display_list *list = data->list; fz_display_list *annotList = data->annotList; fz_rect rect = data->rect; fz_pixmap *pix = data->pix; fz_device *dev = nullptr; int width = data->width; int height = data->height / numParts; // The context pointer is pointing to the main thread's // context, so here we create a new context based on it for // use in this thread. ctx = fz_clone_context(ctx); fz_try(ctx) { if (part == 1 && numParts == 2) { rect.y1 = rect.y1/2; } if (part == 2 && numParts == 2) { rect.y0 = rect.y1/2; } fz_matrix ctm = CalcConvertMatrix(); fz_bbox bbox = fz_round_rect(fz_transform_rect(ctm, rect)); /* Now, adjust ctm so that it would give the correct page width * heights. */ float xscale = (float)width/(float)(bbox.x1-bbox.x0); float yscale = (float)height/(float)(bbox.y1-bbox.y0); ctm = fz_concat(ctm, fz_scale(xscale, yscale)); bbox = fz_round_rect(fz_transform_rect(ctm, rect)); dev = fz_new_draw_device(ctx, pix); if (list) fz_run_display_list(list, dev, ctm, bbox, *&m_cts); if (m_cts->abort == 1) break; if (annotList) fz_run_display_list(annotList, dev, ctm, bbox, *&m_cts); } fz_always(ctx) { if (dev) { fz_free_device(dev); dev = nullptr; } if (pix) { fz_drop_pixmap(m_context, pix); } } fz_catch(ctx) { return E_FAIL; } fz_free_context(ctx); return S_OK; }