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_stext_page * fz_new_stext_page_from_display_list(fz_context *ctx, fz_display_list *list, fz_stext_sheet *sheet) { fz_stext_page *text; fz_device *dev; fz_rect mediabox; if (list == NULL) return NULL; text = fz_new_stext_page(ctx, fz_bound_display_list(ctx, list, &mediabox)); fz_try(ctx) { dev = fz_new_stext_device(ctx, sheet, text); fz_run_display_list(ctx, list, dev, &fz_identity, NULL, NULL); fz_close_device(ctx, dev); } fz_always(ctx) { fz_drop_device(ctx, dev); } fz_catch(ctx) { fz_drop_stext_page(ctx, text); fz_rethrow(ctx); } return text; }
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; }
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; }
fz_text_page * fz_new_text_page_from_display_list(fz_context *ctx, fz_display_list *list, fz_text_sheet *sheet) { fz_text_page *text; fz_device *dev; text = fz_new_text_page(ctx); fz_try(ctx) { dev = fz_new_text_device(ctx, sheet, text); fz_run_display_list(ctx, list, dev, &fz_identity, NULL, NULL); } fz_always(ctx) { fz_drop_device(ctx, dev); } fz_catch(ctx) { fz_drop_text_page(ctx, text); fz_rethrow(ctx); } return text; }
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 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 drawbmp(fz_context *ctx, fz_document *doc, fz_page *page, fz_display_list *list, int pagenum) { float zoom; fz_matrix ctm; fz_bbox bbox; fz_rect bounds, bounds2; int w, h; fz_device *dev; HDC dc, dc_main; RECT rc; HBRUSH bg_brush; HBITMAP hbmp; BITMAPINFO bmi = { 0 }; int bmp_data_len; char *bmp_data; 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); w = width; h = height; if (res_specified) { bbox = fz_round_rect(bounds2); if (w && bbox.x1 - bbox.x0 <= w) w = 0; if (h && bbox.y1 - bbox.y0 <= h) h = 0; } if (w || h) { float scalex = w / (bounds2.x1 - bounds2.x0); float scaley = h / (bounds2.y1 - bounds2.y0); if (w == 0) scalex = fit ? 1.0f : scaley; if (h == 0) scaley = fit ? 1.0f : scalex; if (!fit) scalex = scaley = min(scalex, scaley); ctm = fz_concat(ctm, fz_scale(scalex, scaley)); bounds2 = fz_transform_rect(ctm, bounds); } bbox = fz_round_rect(bounds2); w = bbox.x1 - bbox.x0; h = bbox.y1 - bbox.y0; dc_main = GetDC(NULL); dc = CreateCompatibleDC(dc_main); hbmp = CreateCompatibleBitmap(dc_main, w, h); DeleteObject(SelectObject(dc, hbmp)); SetRect(&rc, 0, 0, w, h); bg_brush = CreateSolidBrush(RGB(0xFF,0xFF,0xFF)); FillRect(dc, &rc, bg_brush); DeleteObject(bg_brush); dev = fz_new_gdiplus_device(ctx, dc, fz_rect_from_bbox(bbox)); if (list) fz_run_display_list(list, dev, ctm, fz_rect_from_bbox(bbox), NULL); else fz_run_page(doc, page, dev, ctm, NULL); fz_free_device(dev); bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); bmi.bmiHeader.biWidth = w; bmi.bmiHeader.biHeight = h; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 24; bmi.bmiHeader.biCompression = BI_RGB; bmp_data_len = ((w * 3 + 3) / 4) * 4 * h; bmp_data = fz_malloc(ctx, bmp_data_len + 1); if (!GetDIBits(dc, hbmp, 0, h, bmp_data, &bmi, DIB_RGB_COLORS)) fz_throw(ctx, "cannot draw page %d in PDF file '%s'", pagenum, filename); DeleteDC(dc); ReleaseDC(NULL, dc_main); DeleteObject(hbmp); if (output) { char buf[512]; FILE *f; sprintf(buf, output, pagenum); f = fopen(buf, "wb"); if (!f) fz_throw(ctx, "could not create raster file '%s'", buf); if (strstr(output, ".bmp")) { BITMAPFILEHEADER bmpfh = { 0 }; static const int one = 1; if (!*(char *)&one) fz_throw(ctx, "rendering to BMP is not supported on big-endian architectures"); bmpfh.bfType = MAKEWORD('B', 'M'); bmpfh.bfOffBits = sizeof(bmpfh) + sizeof(bmi); bmpfh.bfSize = bmpfh.bfOffBits + bmp_data_len; fwrite(&bmpfh, sizeof(bmpfh), 1, f); fwrite(&bmi, sizeof(bmi), 1, f); fwrite(bmp_data, 1, bmp_data_len, f); } else { unsigned short width = w, height = h, k; fwrite("\0\0\x0A\0\0\0\0\0\0\0\0\0", 1, 12, f); putc(width & 0xFF, f); putc((width >> 8) & 0xFF, f); putc(height & 0xFF, f); putc((height >> 8) & 0xFF, f); fwrite("\x18\0", 1, 2, f); for (k = 0; k < height; k++) { int i, j; char *line = bmp_data + bmp_data_len / h * k; for (i = 0, j = 1; i < width; i += j, j = 1) { #define memeq3(a, b) (*(WORD *)(a) == *(WORD *)(b) && (a)[2] == (b)[2]) for (; i + j < width && j < 128 && memeq3(line + i * 3, line + (i + j) * 3); j++); if (j > 1) { putc(j - 1 + 128, f); fwrite(line + i * 3, 1, 3, f); } else { for (; i + j < width && j <= 128 && !memeq3(line + (i + j - 1) * 3, line + (i + j) * 3) != 0; j++); if (i + j < width || j > 128) j--; putc(j - 1, f); fwrite(line + i * 3, 1, j * 3, f); } #undef memeq3 } } fwrite("\0\0\0\0\0\0\0\0TRUEVISION-XFILE.\0", 1, 26, f); } fclose(f); } if (showmd5) { fz_pixmap *pix = fz_new_pixmap_with_data(ctx, fz_device_rgb, bmp_data_len / 4 / h, h, bmp_data); 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_free(ctx, bmp_data); }
HRESULT MuPDFDoc::UpdatePage(int pageNumber, unsigned char *bitmap, int x, int y, int width, int height, bool invert) { int index = FindPageInCache(pageNumber); if (index < 0) { //TODO: get rid of this side effect!!! HRESULT result = GotoPage(pageNumber); if (FAILED(result)) { return result; } return DrawPage(bitmap, x, y, width, height, invert); } 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, nullptr); } 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, nullptr); } 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); // 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; } fz_annot *annot; while (idoc && (annot = fz_poll_changed_annot(idoc, pageCache->page))) { fz_bbox abox = fz_round_rect(fz_transform_rect(ctm, fz_bound_annot(m_document, annot))); abox = fz_intersect_bbox(abox, rect); if (!fz_is_empty_bbox(abox)) { fz_clear_pixmap_rect_with_value(m_context, pixmap, 0xff, abox); dev = fz_new_draw_device_with_bbox(m_context, pixmap, abox); if (pageCache->pageList) fz_run_display_list(pageCache->pageList, dev, ctm, abox, nullptr); if (pageCache->annotList) fz_run_display_list(pageCache->annotList, dev, ctm, abox, nullptr); fz_free_device(dev); dev = nullptr; if (invert) fz_invert_pixmap_rect(pixmap, abox); } } } 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; }
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_rethrow_message(ctx, "cannot load page %d in file '%s'", pagenum, filename); } if (mujstest_file) { pdf_document *inter = pdf_specifics(doc); pdf_widget *widget = NULL; if (inter) widget = pdf_first_widget(inter, (pdf_page *)page); if (widget) { fprintf(mujstest_file, "GOTO %d\n", pagenum); needshot = 1; } for (;widget; widget = pdf_next_widget(widget)) { fz_rect rect; int w, h, len; int type = pdf_widget_get_type(widget); pdf_bound_widget(widget, &rect); w = (rect.x1 - rect.x0); h = (rect.y1 - rect.y0); ++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 PDF_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 PDF_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 PDF_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 PDF_WIDGET_TYPE_TEXT: { int maxlen = pdf_text_widget_max_len(inter, widget); int texttype = pdf_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 PDF_WIDGET_CONTENT_UNRESTRAINED: fprintf(mujstest_file, "TEXT %d ", mujstest_count); escape_string(mujstest_file, len-3, lorem); fprintf(mujstest_file, "\n"); break; case PDF_WIDGET_CONTENT_NUMBER: fprintf(mujstest_file, "TEXT %d\n", mujstest_count); break; case PDF_WIDGET_CONTENT_SPECIAL: #ifdef __MINGW32__ fprintf(mujstest_file, "TEXT %I64d\n", 46702919800LL + mujstest_count); #else fprintf(mujstest_file, "TEXT %lld\n", 46702919800LL + mujstest_count); #endif break; case PDF_WIDGET_CONTENT_DATE: fprintf(mujstest_file, "TEXT Jun %d 1979\n", 1 + ((13 + mujstest_count) % 30)); break; case PDF_WIDGET_CONTENT_TIME: ++mujstest_count; fprintf(mujstest_file, "TEXT %02d:%02d\n", ((mujstest_count/60) % 24), mujstest_count % 60); break; } break; } case PDF_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 PDF_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_drop_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow_message(ctx, "cannot draw page %d in file '%s'", pagenum, filename); } } if (showxml) { fz_try(ctx) { dev = fz_new_trace_device(ctx); 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_always(ctx) { fz_free_device(dev); dev = NULL; } fz_catch(ctx) { fz_drop_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); dev = fz_new_text_device(ctx, sheet, text); if (showtext == TEXT_HTML) fz_disable_device_hints(dev, FZ_IGNORE_IMAGE); 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_analyze_text(ctx, sheet, text); 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_drop_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow(ctx); } } if (showmd5 || showtime) printf("page %s %d", filename, pagenum); if (pdfout) { fz_matrix ctm; fz_rect bounds, tbounds; pdf_page *newpage; fz_bound_page(doc, page, &bounds); fz_rotate(&ctm, rotation); tbounds = bounds; fz_transform_rect(&tbounds, &ctm); newpage = pdf_create_page(pdfout, bounds, 72, 0); fz_try(ctx) { dev = pdf_page_write(pdfout, newpage); 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; } fz_always(ctx) { fz_free_device(dev); dev = NULL; } fz_catch(ctx) { fz_drop_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow(ctx); } pdf_insert_page(pdfout, newpage, INT_MAX); pdf_free_page(pdfout, newpage); } if (output && output_format == OUT_SVG) { float zoom; fz_matrix ctm; fz_rect bounds, tbounds; char buf[512]; FILE *file; fz_output *out; if (!strcmp(output, "-")) file = stdout; else { sprintf(buf, output, pagenum); file = fopen(buf, "wb"); if (file == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", buf, strerror(errno)); } out = fz_new_output_with_file(ctx, file); fz_bound_page(doc, page, &bounds); zoom = resolution / 72; fz_pre_rotate(fz_scale(&ctm, zoom, zoom), rotation); tbounds = bounds; fz_transform_rect(&tbounds, &ctm); fz_try(ctx) { dev = fz_new_svg_device(ctx, out, tbounds.x1-tbounds.x0, tbounds.y1-tbounds.y0); 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; } fz_always(ctx) { fz_free_device(dev); dev = NULL; fz_close_output(out); if (file != stdout) fclose(file); } fz_catch(ctx) { fz_drop_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow(ctx); } }
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; }
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_updatePageInternal(JNIEnv *env, jobject thiz, jobject bitmap, int page, 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_interactive *idoc; page_cache *pc = NULL; int hq = (patchW < pageW || patchH < pageH); int i; for (i = 0; i < NUM_CACHE; i++) { if (pages[i].page != NULL && pages[i].number == page) { pc = &pages[i]; break; } } if (pc == NULL || (hq && pc->hq_page == NULL)) { Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(env, thiz, page); return Java_com_artifex_mupdf_MuPDFCore_drawPage(env, thiz, bitmap, pageW, pageH, patchX, patchY, patchW, patchH); } idoc = fz_interact(doc); 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_annot *annot; // Unimportant which page object we use for rendering but we // must use the correct one for calculating updates fz_page *page = hq ? pc->hq_page : pc->page; fz_update_page(idoc, page); 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, page, dev, fz_identity, NULL); } if (pc->annot_list == NULL) { 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, page); annot; annot = fz_next_annot(doc, annot)) fz_run_annot(doc, 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); 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)); LOGI("Start polling for updates"); while ((annot = fz_poll_changed_annot(idoc, page)) != NULL) { fz_bbox abox = fz_round_rect(fz_transform_rect(ctm, fz_bound_annot(doc, annot))); abox = fz_intersect_bbox(abox, rect); LOGI("Update rectanglefor %s - (%d, %d, %d, %d)", widget_type_string(fz_widget_get_type((fz_widget*)annot)), abox.x0, abox.y0, abox.x1, abox.y1); if (!fz_is_empty_bbox(abox)) { LOGI("And it isn't empty"); fz_clear_pixmap_rect_with_value(ctx, pix, 0xff, abox); dev = fz_new_draw_device_with_bbox(ctx, pix, abox); if (pc->page_list) fz_run_display_list(pc->page_list, dev, ctm, abox, NULL); if (pc->annot_list) fz_run_display_list(pc->annot_list, dev, ctm, abox, NULL); fz_free_device(dev); dev = NULL; } } LOGI("Done polling for updates"); LOGE("Rendered"); } fz_catch(ctx) { fz_free_device(dev); LOGE("Render failed"); } fz_drop_pixmap(ctx, pix); AndroidBitmap_unlockPixels(env, bitmap); return 1; }
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; }
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; }
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); if (showtime) { start = gettime(); } fz_try(ctx) { page = fz_load_page(doc, pagenum - 1); } fz_catch(ctx) { fz_rethrow_message(ctx, "cannot load 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, &cookie); } fz_always(ctx) { fz_free_device(dev); dev = NULL; } fz_catch(ctx) { fz_drop_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow_message(ctx, "cannot draw page %d in file '%s'", pagenum, filename); } } if (showxml) { fz_try(ctx) { dev = fz_new_trace_device(ctx); 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_always(ctx) { fz_free_device(dev); dev = NULL; } fz_catch(ctx) { fz_drop_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); dev = fz_new_text_device(ctx, sheet, text); if (showtext == TEXT_HTML) fz_disable_device_hints(dev, FZ_IGNORE_IMAGE); 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_analyze_text(ctx, sheet, text); 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_drop_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow(ctx); } } if (showmd5 || showtime || showfeatures) printf("page %s %d", filename, pagenum); if (showfeatures) { int iscolor; dev = fz_new_test_device(ctx, &iscolor, 0.02f); fz_try(ctx) { if (list) fz_run_display_list(list, dev, &fz_identity, &fz_infinite_rect, NULL); else fz_run_page(doc, page, dev, &fz_identity, &cookie); } fz_always(ctx) { fz_free_device(dev); dev = NULL; } fz_catch(ctx) { fz_rethrow(ctx); } printf(" %s", iscolor ? "color" : "grayscale"); } if (pdfout) { fz_matrix ctm; fz_rect bounds, tbounds; pdf_page *newpage; fz_bound_page(doc, page, &bounds); fz_rotate(&ctm, rotation); tbounds = bounds; fz_transform_rect(&tbounds, &ctm); newpage = pdf_create_page(pdfout, bounds, 72, 0); fz_try(ctx) { dev = pdf_page_write(pdfout, newpage); 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; } fz_always(ctx) { fz_free_device(dev); dev = NULL; } fz_catch(ctx) { fz_drop_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow(ctx); } pdf_insert_page(pdfout, newpage, INT_MAX); pdf_free_page(pdfout, newpage); } if (output && output_format == OUT_SVG) { float zoom; fz_matrix ctm; fz_rect bounds, tbounds; char buf[512]; FILE *file; fz_output *out; if (!strcmp(output, "-")) file = stdout; else { sprintf(buf, output, pagenum); file = fopen(buf, "wb"); if (file == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", buf, strerror(errno)); } out = fz_new_output_with_file(ctx, file); fz_bound_page(doc, page, &bounds); zoom = resolution / 72; fz_pre_rotate(fz_scale(&ctm, zoom, zoom), rotation); tbounds = bounds; fz_transform_rect(&tbounds, &ctm); fz_try(ctx) { dev = fz_new_svg_device(ctx, out, tbounds.x1-tbounds.x0, tbounds.y1-tbounds.y0); 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; } fz_always(ctx) { fz_free_device(dev); dev = NULL; fz_close_output(out); if (file != stdout) fclose(file); } fz_catch(ctx) { fz_drop_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow(ctx); } }
static void drawbmp(fz_context *ctx, fz_document *doc, fz_page *page, fz_display_list *list, int pagenum, fz_cookie *cookie) { float zoom; fz_matrix ctm; fz_irect ibounds; fz_rect bounds, tbounds; int w, h; fz_device *dev; HDC dc, dc_main; RECT rc; HBRUSH bg_brush; HBITMAP hbmp; BITMAPINFO bmi = { 0 }; int bmp_data_len; unsigned char *bmp_data; fz_bound_page(doc, page, &bounds); zoom = resolution / 72; fz_pre_scale(fz_rotate(&ctm, rotation), zoom, zoom); tbounds = bounds; fz_round_rect(&ibounds, fz_transform_rect(&tbounds, &ctm)); w = width; h = height; if (res_specified) { fz_round_rect(&ibounds, &tbounds); if (w && ibounds.x1 - ibounds.x0 <= w) w = 0; if (h && ibounds.y1 - ibounds.y0 <= h) h = 0; } if (w || h) { float scalex = w / (tbounds.x1 - tbounds.x0); float scaley = h / (tbounds.y1 - tbounds.y0); fz_matrix scale_mat; if (w == 0) scalex = fit ? 1.0f : scaley; if (h == 0) scaley = fit ? 1.0f : scalex; if (!fit) scalex = scaley = min(scalex, scaley); fz_concat(&ctm, &ctm, fz_scale(&scale_mat, scalex, scaley)); tbounds = bounds; fz_transform_rect(&tbounds, &ctm); } fz_round_rect(&ibounds, &tbounds); fz_rect_from_irect(&tbounds, &ibounds); w = ibounds.x1 - ibounds.x0; h = ibounds.y1 - ibounds.y0; dc_main = GetDC(NULL); dc = CreateCompatibleDC(dc_main); hbmp = CreateCompatibleBitmap(dc_main, w, h); DeleteObject(SelectObject(dc, hbmp)); SetRect(&rc, 0, 0, w, h); bg_brush = CreateSolidBrush(RGB(0xFF,0xFF,0xFF)); FillRect(dc, &rc, bg_brush); DeleteObject(bg_brush); dev = fz_new_gdiplus_device(ctx, dc, &tbounds); if (list) fz_run_display_list(list, dev, &ctm, &tbounds, cookie); else fz_run_page(doc, page, dev, &ctm, cookie); fz_free_device(dev); bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); bmi.bmiHeader.biWidth = w; bmi.bmiHeader.biHeight = output_format == OUT_TGA ? -h : h; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = output_format == OUT_TGA ? 32 : 24; bmi.bmiHeader.biCompression = BI_RGB; bmp_data_len = output_format == OUT_TGA ? w * h * 4 : ((w * 3 + 3) / 4) * 4 * h; bmp_data = fz_malloc(ctx, bmp_data_len); if (!GetDIBits(dc, hbmp, 0, h, bmp_data, &bmi, DIB_RGB_COLORS)) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot draw page %d in PDF file '%s'", pagenum, filename); DeleteDC(dc); ReleaseDC(NULL, dc_main); DeleteObject(hbmp); if (output) { char buf[512]; FILE *f; sprintf(buf, output, pagenum); f = fopen(buf, "wb"); if (!f) fz_throw(ctx, FZ_ERROR_GENERIC, "could not create raster file '%s'", buf); if (output_format == OUT_TGA) { fz_pixmap *pix = fz_new_pixmap_with_data(ctx, fz_device_bgr(ctx), w, h, bmp_data); fz_write_tga(ctx, pix, buf, 0); fz_drop_pixmap(ctx, pix); } else { BITMAPFILEHEADER bmpfh = { 0 }; static const int one = 1; if (!*(char *)&one) fz_throw(ctx, FZ_ERROR_GENERIC, "rendering to BMP is not supported on big-endian architectures"); bmpfh.bfType = MAKEWORD('B', 'M'); bmpfh.bfOffBits = sizeof(bmpfh) + sizeof(bmi); bmpfh.bfSize = bmpfh.bfOffBits + bmp_data_len; fwrite(&bmpfh, sizeof(bmpfh), 1, f); fwrite(&bmi, sizeof(bmi), 1, f); fwrite(bmp_data, 1, bmp_data_len, f); } fclose(f); } if (showmd5) { fz_pixmap *pix = fz_new_pixmap_with_data(ctx, fz_device_bgr(ctx), bmp_data_len / 4 / h, h, bmp_data); 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_free(ctx, bmp_data); }
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); } }
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; }