fz_matrix PDFDocument::Transform(float zoom, int rotation) { fz_matrix transformation_matrix, scale_matrix, rotate_matrix; #if MUPDF_VERSION >= 10014 scale_matrix = fz_scale(zoom, zoom); rotate_matrix = fz_rotate(rotation); transformation_matrix = fz_concat(scale_matrix, rotate_matrix); #else fz_scale(&scale_matrix, zoom, zoom); fz_rotate(&rotate_matrix, rotation); fz_concat(&transformation_matrix, &scale_matrix, &rotate_matrix); #endif return transformation_matrix; }
/* SumatraPDF: synthesize appearance streams for a few more annotations */ static pdf_annot * pdf_create_annot(fz_context *ctx, fz_rect rect, fz_obj *base_obj, fz_buffer *content, fz_obj *resources, int transparency) { pdf_annot *annot; pdf_xobject *form; int rotate = fz_to_int(ctx, fz_dict_gets(ctx, fz_dict_gets(ctx, base_obj, "MK"), "R")); form = fz_malloc(ctx, sizeof(pdf_xobject)); memset(form, 0, sizeof(pdf_xobject)); form->refs = 1; form->matrix = fz_rotate(rotate); form->bbox.x1 = (rotate % 180 == 0) ? rect.x1 - rect.x0 : rect.y1 - rect.y0; form->bbox.y1 = (rotate % 180 == 0) ? rect.y1 - rect.y0 : rect.x1 - rect.x0; form->transparency = transparency; form->isolated = !transparency; form->contents = content; form->resources = resources; annot = fz_malloc(ctx, sizeof(pdf_annot)); annot->obj = base_obj; annot->rect = rect; annot->ap = form; annot->next = NULL; pdf_transform_annot(annot); return annot; }
fz_matrix PDFDocument::Transform(float zoom, int rotation) { fz_matrix transformation_matrix, scale_matrix, rotate_matrix; fz_scale(&scale_matrix, zoom, zoom); fz_rotate(&rotate_matrix, rotation); fz_concat(&transformation_matrix, &scale_matrix, & rotate_matrix); return transformation_matrix; }
static mume_matrix_t _pdf_doc_get_matrix( struct _pdf_doc *self, int pageno, float zoom, int rotate) { mume_matrix_t m; fz_matrix ctm = fz_identity; fz_rect mbox = self->media_boxes[pageno]; int rotation = (self->page_rotates[pageno] + rotate) % 360; if (rotation < 0) rotation = rotation + 360; if (90 == rotation) { ctm = fz_concat(ctm, fz_translate(-mbox.x0, -mbox.y0)); } else if (180 == rotation) { ctm = fz_concat(ctm, fz_translate(-mbox.x1, -mbox.y0)); } else if (270 == rotation) { ctm = fz_concat(ctm, fz_translate(-mbox.x1, -mbox.y1)); } else { ctm = fz_concat(ctm, fz_translate(-mbox.x0, -mbox.y1)); } ctm = fz_concat(ctm, fz_scale(zoom, -zoom)); ctm = fz_concat(ctm, fz_rotate(rotation)); m.a = ctm.a; m.b = ctm.b; m.c = ctm.c; m.d = ctm.d; m.e = ctm.e; m.f = ctm.f; return m; }
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); }
static fz_matrix pdfViewctm(PDFContext* ctx) { fz_matrix ctm; ctm = fz_identity(); ctm = fz_concat(ctm, fz_translate(0, -ctx->page->mediabox.y1)); ctm = fz_concat(ctm, fz_scale(ctx->zoom, -ctx->zoom)); ctm = fz_concat(ctm, fz_rotate(ctx->rotate + ctx->page->rotate)); return ctm; }
fz_matrix pdfapp_viewctm(pdfapp_t *app) { fz_matrix ctm; ctm = fz_identity(); ctm = fz_concat(ctm, fz_translate(0, -app->page->mediabox.y1)); ctm = fz_concat(ctm, fz_scale(app->zoom, -app->zoom)); ctm = fz_concat(ctm, fz_rotate(app->rotate + app->page->rotate)); return ctm; }
fz_rect * pdf_bound_page(pdf_document *doc, pdf_page *page, fz_rect *bounds) { fz_matrix mtx; fz_rect mediabox = page->mediabox; fz_transform_rect(&mediabox, fz_rotate(&mtx, page->rotate)); bounds->x0 = bounds->y0 = 0; bounds->x1 = mediabox.x1 - mediabox.x0; bounds->y1 = mediabox.y1 - mediabox.y0; return bounds; }
static fz_matrix pdfapp_viewctm(pdfapp_t *app) { fz_matrix ctm; ctm = fz_identity; ctm = fz_concat(ctm, fz_translate(0, -app->page_bbox.y1)); if (app->xref) ctm = fz_concat(ctm, fz_scale(app->resolution/72.0f, -app->resolution/72.0f)); else ctm = fz_concat(ctm, fz_scale(app->resolution/96.0f, app->resolution/96.0f)); ctm = fz_concat(ctm, fz_rotate(app->rotate + app->page_rotate)); return ctm; }
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; }
JNIEXPORT void JNICALL Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal( JNIEnv *env, jobject thiz, int page) { float zoom; fz_matrix ctm; fz_obj *pageobj; fz_bbox bbox; fz_error error; fz_device *dev; pdf_page *currentPage; /* In the event of an error, ensure we give a non-empty page */ pageWidth = 100; pageHeight = 100; LOGE("Goto page %d...", page); if (currentPageList != NULL) { fz_freedisplaylist(currentPageList); currentPageList = NULL; } pagenum = page; pageobj = pdf_getpageobject(xref, pagenum); if (pageobj == NULL) return; error = pdf_loadpage(¤tPage, xref, pageobj); if (error) return; zoom = resolution / 72; currentMediabox = currentPage->mediabox; currentRotate = currentPage->rotate; ctm = fz_translate(0, -currentMediabox.y1); ctm = fz_concat(ctm, fz_scale(zoom, -zoom)); ctm = fz_concat(ctm, fz_rotate(currentRotate)); bbox = fz_roundrect(fz_transformrect(ctm, currentMediabox)); pageWidth = bbox.x1-bbox.x0; pageHeight = bbox.y1-bbox.y0; /* Render to list */ currentPageList = fz_newdisplaylist(); dev = fz_newlistdevice(currentPageList); error = pdf_runpage(xref, currentPage, dev, fz_identity); pdf_freepage(currentPage); if (error) LOGE("cannot make displaylist from page %d", pagenum); fz_freedevice(dev); }
int adjust_page_position(fz_context *ctx, pdf_document *doc, pdf_page *page, struct pos_info *pos) { /* if page is rotated we must add this to the desired rotation of the page */ pos->rotate = (pos->rotate + page->rotate) % 360; fz_matrix rotation_mtx; /* tranformation of the user-space due to the rotation */ fz_rotate(&rotation_mtx, page->rotate); /* get the media-box (with rotation applied) */ pdf_obj *media_box = juggler_lookup_inherited_page_item(ctx, doc, page->me, "MediaBox"); if(!pdf_is_array(ctx, media_box) || pdf_array_len(ctx, media_box) != 4) return(-1); /* the specification forces a valid media-box... */ fz_rect media_rect; pdf_to_rect(ctx, media_box, &media_rect); fz_transform_rect(&media_rect, &rotation_mtx); /* get trim-box */ pdf_obj *trim_box = juggler_lookup_inherited_page_item(ctx, doc, page->me, "TrimBox"); if(trim_box == NULL) trim_box = media_box; if(!pdf_is_array(ctx, trim_box) || pdf_array_len(ctx, trim_box) != 4) return(-2); fz_rect trim_rect; pdf_to_rect(ctx, trim_box, &trim_rect); fz_transform_rect(&trim_rect, &rotation_mtx); // TODO: Take scale into account double available_width = pos->width; double available_height = pos->height; double page_width = trim_rect.x1 - trim_rect.x0; double page_height = trim_rect.y1 - trim_rect.y0; /* position the page in the middle of the destination area */ pos->content_translate_x = media_rect.x0 - trim_rect.x0 + (available_width - page_width) / 2; pos->content_translate_y = media_rect.y0 - trim_rect.y0 + (available_height - page_height) / 2; /* if needed, clip the contents to the bleed-box */ if(adjust_bleed_clipping(ctx, doc, page, pos) < 0) return(-2); return(0); }
fz_matrix pdfmoz_pagectm(pdfmoz_t *moz, int pagenum) { page_t *page = moz->pages + pagenum; fz_matrix ctm; float zoom; RECT rc; GetClientRect(moz->hwnd, &rc); zoom = (rc.right - rc.left) / (float) page->w; ctm = fz_identity(); ctm = fz_concat(ctm, fz_translate(0, -page->page->mediabox.y1)); ctm = fz_concat(ctm, fz_scale(zoom, -zoom)); ctm = fz_concat(ctm, fz_rotate(page->page->rotate)); return ctm; }
void j_mu_render_page(void* p_ctx, void* p_page) { fz_context* ctx = (fz_context*) p_ctx; pdf_page* page = (pdf_page*)p_page; fz_matrix transform; fz_rotate(&transform, 0); fz_pre_scale(&transform, 100 / 100.0f, 100 / 100.0f); fz_rect bounds; pdf_bound_page(ctx, 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(ctx), &bbox); fz_pixmap_set_resolution(pix, 300); fz_clear_pixmap_with_value(ctx, pix, 0xff); }
static void pdf_write_free_text_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect, fz_rect *bbox, fz_matrix *matrix, pdf_obj **res) { const char *font; float size, color[3]; const char *text; float w, h, t, b; int q, r; /* /Rotate is an undocumented annotation property supported by Adobe */ text = pdf_annot_contents(ctx, annot); r = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(Rotate)); q = pdf_annot_quadding(ctx, annot); pdf_annot_default_appearance(ctx, annot, &font, &size, color); w = rect->x1 - rect->x0; h = rect->y1 - rect->y0; if (r == 90 || r == 270) t = h, h = w, w = t; *matrix = fz_rotate(r); *bbox = fz_make_rect(0, 0, w, h); if (pdf_write_fill_color_appearance(ctx, annot, buf)) fz_append_printf(ctx, buf, "0 0 %g %g re\nf\n", w, h); b = pdf_write_border_appearance(ctx, annot, buf); if (b > 0) { fz_append_printf(ctx, buf, "%g %g %g RG\n", color[0], color[1], color[2]); fz_append_printf(ctx, buf, "%g %g %g %g re\nS\n", b/2, b/2, w-b, h-b); } fz_append_printf(ctx, buf, "%g %g %g %g re\nW\nn\n", b, b, w-b*2, h-b*2); write_variable_text(ctx, annot, buf, res, text, font, size, color, q, w, h, b*2, 0.8f, 1.2f, 1, 0, 0); }
static void pdf_update_button_appearance(fz_context *ctx, pdf_annot *annot) { int ff = pdf_field_flags(ctx, annot->obj); fz_rect rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect)); fz_matrix matrix; fz_rect bbox; float w, h, t; int r; r = pdf_dict_get_int(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(R)); w = rect.x1 - rect.x0; h = rect.y1 - rect.y0; if (r == 90 || r == 270) t = h, h = w, w = t; matrix = fz_rotate(r); bbox = fz_make_rect(0, 0, w, h); if (ff & PDF_BTN_FIELD_IS_PUSHBUTTON) { pdf_obj *ap_n = NULL; pdf_obj *ap_d = NULL; fz_var(ap_n); fz_var(ap_d); fz_try(ctx) { pdf_obj *ap, *MK, *CA, *AC; const char *font; const char *label; float size, color[3]; pdf_annot_default_appearance(ctx, annot, &font, &size, color); MK = pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)); CA = pdf_dict_get(ctx, MK, PDF_NAME(CA)); AC = pdf_dict_get(ctx, MK, PDF_NAME(AC)); label = pdf_to_text_string(ctx, CA); ap_n = draw_push_button(ctx, annot, bbox, matrix, w, h, label, font, size, color, 0); label = pdf_to_text_string(ctx, AC ? AC : CA); ap_d = draw_push_button(ctx, annot, bbox, matrix, w, h, label, font, size, color, 1); ap = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(AP), 2); pdf_dict_put(ctx, ap, PDF_NAME(N), ap_n); pdf_dict_put(ctx, ap, PDF_NAME(D), ap_d); pdf_drop_obj(ctx, annot->ap); if (annot->is_hot && annot->is_active) annot->ap = pdf_keep_obj(ctx, ap_d); else annot->ap = pdf_keep_obj(ctx, ap_n); annot->has_new_ap = 1; } fz_always(ctx) { pdf_drop_obj(ctx, ap_n); pdf_drop_obj(ctx, ap_d); } fz_catch(ctx) fz_rethrow(ctx); }
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); }
/* Some explaination of the parameters here is warranted. See: http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes Add an arc segment to path, that describes a section of an elliptical arc from the current point of path to (point_x,point_y), such that: The arc segment is taken from an elliptical arc of semi major radius size_x, semi minor radius size_y, where the semi major axis of the ellipse is rotated by rotation_angle. If is_large_arc, then the arc segment is selected to be > 180 degrees. If is_clockwise, then the arc sweeps clockwise. */ static void xps_draw_arc(fz_context *doc, fz_path *path, float size_x, float size_y, float rotation_angle, int is_large_arc, int is_clockwise, float point_x, float point_y) { fz_matrix rotmat, revmat; fz_matrix mtx; fz_point pt; float rx, ry; float x1, y1, x2, y2; float x1t, y1t; float cxt, cyt, cx, cy; float t1, t2, t3; float sign; float th1, dth; pt = fz_currentpoint(doc, path); x1 = pt.x; y1 = pt.y; x2 = point_x; y2 = point_y; rx = size_x; ry = size_y; if (is_clockwise != is_large_arc) sign = 1; else sign = -1; fz_rotate(&rotmat, rotation_angle); fz_rotate(&revmat, -rotation_angle); /* http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes */ /* Conversion from endpoint to center parameterization */ /* F.6.6.1 -- ensure radii are positive and non-zero */ rx = fabsf(rx); ry = fabsf(ry); if (rx < 0.001f || ry < 0.001f || (x1 == x2 && y1 == y2)) { fz_lineto(doc, path, x2, y2); return; } /* F.6.5.1 */ pt.x = (x1 - x2) / 2; pt.y = (y1 - y2) / 2; fz_transform_vector(&pt, &revmat); x1t = pt.x; y1t = pt.y; /* F.6.6.2 -- ensure radii are large enough */ t1 = (x1t * x1t) / (rx * rx) + (y1t * y1t) / (ry * ry); if (t1 > 1) { rx = rx * sqrtf(t1); ry = ry * sqrtf(t1); } /* F.6.5.2 */ t1 = (rx * rx * ry * ry) - (rx * rx * y1t * y1t) - (ry * ry * x1t * x1t); t2 = (rx * rx * y1t * y1t) + (ry * ry * x1t * x1t); t3 = t1 / t2; /* guard against rounding errors; sqrt of negative numbers is bad for your health */ if (t3 < 0) t3 = 0; t3 = sqrtf(t3); cxt = sign * t3 * (rx * y1t) / ry; cyt = sign * t3 * -(ry * x1t) / rx; /* F.6.5.3 */ pt.x = cxt; pt.y = cyt; fz_transform_vector(&pt, &rotmat); cx = pt.x + (x1 + x2) / 2; cy = pt.y + (y1 + y2) / 2; /* F.6.5.4 */ { fz_point coord1, coord2, coord3, coord4; coord1.x = 1; coord1.y = 0; coord2.x = (x1t - cxt) / rx; coord2.y = (y1t - cyt) / ry; coord3.x = (x1t - cxt) / rx; coord3.y = (y1t - cyt) / ry; coord4.x = (-x1t - cxt) / rx; coord4.y = (-y1t - cyt) / ry; th1 = angle_between(coord1, coord2); dth = angle_between(coord3, coord4); if (dth < 0 && !is_clockwise) dth += (((float)M_PI / 180) * 360); if (dth > 0 && is_clockwise) dth -= (((float)M_PI / 180) * 360); } fz_pre_scale(fz_pre_rotate(fz_translate(&mtx, cx, cy), rotation_angle), rx, ry); xps_draw_arc_segment(doc, path, &mtx, th1, th1 + dth, is_clockwise); fz_lineto(doc, path, point_x, point_y); }
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_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 pdf_write_stamp_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect, fz_rect *bbox, pdf_obj **res) { fz_font *font; pdf_obj *res_font; pdf_obj *name; float w, h, xs, ys; fz_matrix rotate; name = pdf_dict_get(ctx, annot->obj, PDF_NAME(Name)); if (!name) name = PDF_NAME(Draft); h = rect->y1 - rect->y0; w = rect->x1 - rect->x0; xs = w / 190; ys = h / 50; font = fz_new_base14_font(ctx, "Times-Bold"); fz_try(ctx) { /* /Resources << /Font << /Times %d 0 R >> >> */ *res = pdf_new_dict(ctx, annot->page->doc, 1); res_font = pdf_dict_put_dict(ctx, *res, PDF_NAME(Font), 1); pdf_dict_put_drop(ctx, res_font, PDF_NAME(Times), pdf_add_simple_font(ctx, annot->page->doc, font, 0)); pdf_write_fill_color_appearance(ctx, annot, buf); pdf_write_stroke_color_appearance(ctx, annot, buf); rotate = fz_rotate(0.6f); fz_append_printf(ctx, buf, "%M cm\n", &rotate); fz_append_string(ctx, buf, "2 w\n2 2 186 44 re\nS\n"); if (name == PDF_NAME(Approved)) write_stamp(ctx, buf, font, "APPROVED", 13, 30); else if (name == PDF_NAME(AsIs)) write_stamp(ctx, buf, font, "AS IS", 13, 30); else if (name == PDF_NAME(Confidential)) write_stamp(ctx, buf, font, "CONFIDENTIAL", 17, 20); else if (name == PDF_NAME(Departmental)) write_stamp(ctx, buf, font, "DEPARTMENTAL", 17, 20); else if (name == PDF_NAME(Experimental)) write_stamp(ctx, buf, font, "EXPERIMENTAL", 17, 20); else if (name == PDF_NAME(Expired)) write_stamp(ctx, buf, font, "EXPIRED", 13, 30); else if (name == PDF_NAME(Final)) write_stamp(ctx, buf, font, "FINAL", 13, 30); else if (name == PDF_NAME(ForComment)) write_stamp(ctx, buf, font, "FOR COMMENT", 17, 20); else if (name == PDF_NAME(ForPublicRelease)) { write_stamp(ctx, buf, font, "FOR PUBLIC", 26, 18); write_stamp(ctx, buf, font, "RELEASE", 8.5f, 18); } else if (name == PDF_NAME(NotApproved)) write_stamp(ctx, buf, font, "NOT APPROVED", 17, 20); else if (name == PDF_NAME(NotForPublicRelease)) { write_stamp(ctx, buf, font, "NOT FOR", 26, 18); write_stamp(ctx, buf, font, "PUBLIC RELEASE", 8.5, 18); } else if (name == PDF_NAME(Sold)) write_stamp(ctx, buf, font, "SOLD", 13, 30); else if (name == PDF_NAME(TopSecret)) write_stamp(ctx, buf, font, "TOP SECRET", 14, 26); else if (name == PDF_NAME(Draft)) write_stamp(ctx, buf, font, "DRAFT", 13, 30); else write_stamp(ctx, buf, font, pdf_to_name(ctx, name), 17, 20); } fz_always(ctx) fz_drop_font(ctx, font); fz_catch(ctx) fz_rethrow(ctx); *bbox = fz_make_rect(0, 0, 190, 50); if (xs > ys) { float xc = (rect->x1+rect->x0) / 2; rect->x0 = xc - 95 * ys; rect->x1 = xc + 95 * ys; } else { float yc = (rect->y1+rect->y0) / 2; rect->y0 = yc - 25 * xs; rect->y1 = yc + 25 * xs; } }
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); } }
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, &bounds); fz_matrix ctm; fz_pre_scale(fz_rotate(&ctm, 0.0), zoom, zoom); fz_irect ibounds; fz_rect tbounds; fz_round_rect(&ibounds, fz_transform_rect(&tbounds, &ctm)); fz_pixmap* pix = fz_new_pixmap_with_bbox(ctx, fz_device_gray, &ibounds); 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; }
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_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); } }
/* * Parse unicode and indices strings and encode glyphs. * Calculate metrics for positioning. */ static fz_text * xps_parse_glyphs_imp(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, fz_font *font, float size, float originx, float originy, int is_sideways, int bidi_level, char *indices, char *unicode) { xps_glyph_metrics mtx; fz_text *text; fz_matrix tm; float e, f; float x = originx; float y = originy; char *us = unicode; char *is = indices; int un = 0; if (!unicode && !indices) fz_warn(ctx, "glyphs element with neither characters nor indices"); if (us) { if (us[0] == '{' && us[1] == '}') us = us + 2; un = strlen(us); } if (is_sideways) { fz_pre_scale(fz_rotate(&tm, 90), -size, size); } else fz_scale(&tm, size, -size); text = fz_new_text(ctx, font, &tm, is_sideways); while ((us && un > 0) || (is && *is)) { int char_code = '?'; int code_count = 1; int glyph_count = 1; if (is && *is) { is = xps_parse_cluster_mapping(is, &code_count, &glyph_count); } if (code_count < 1) code_count = 1; if (glyph_count < 1) glyph_count = 1; /* TODO: add code chars with cluster mappings for text extraction */ while (code_count--) { if (us && un > 0) { int t = fz_chartorune(&char_code, us); us += t; un -= t; } } while (glyph_count--) { int glyph_index = -1; float u_offset = 0; float v_offset = 0; float advance; if (is && *is) is = xps_parse_glyph_index(is, &glyph_index); if (glyph_index == -1) glyph_index = xps_encode_font_char(font, char_code); xps_measure_font_glyph(ctx, doc, font, glyph_index, &mtx); if (is_sideways) advance = mtx.vadv * 100; else if (bidi_level & 1) advance = -mtx.hadv * 100; else advance = mtx.hadv * 100; if (font->ft_bold) advance *= 1.02f; if (is && *is) { is = xps_parse_glyph_metrics(is, &advance, &u_offset, &v_offset); if (*is == ';') is ++; } if (bidi_level & 1) u_offset = -mtx.hadv * 100 - u_offset; u_offset = u_offset * 0.01f * size; v_offset = v_offset * 0.01f * size; if (is_sideways) { e = x + u_offset + (mtx.vorg * size); f = y - v_offset + (mtx.hadv * 0.5f * size); } else { e = x + u_offset; f = y - v_offset; } fz_add_text(ctx, text, glyph_index, char_code, e, f); x += advance * 0.01f * size; } } return text; }
static void drawpnm(int pagenum, struct benchmark *loadtimes, struct benchmark *drawtimes) { fz_error error; fz_matrix ctm; fz_irect bbox; fz_pixmap *pix; char name[256]; char pnmhdr[256]; int i, x, y, w, h, b, bh; int fd = -1; long start; long end; long elapsed; fz_md5 digest; if (!drawpattern) fz_md5init(&digest); drawloadpage(pagenum, loadtimes); if (benchmark) gettime(&start); ctm = fz_identity(); ctm = fz_concat(ctm, fz_translate(0, -drawpage->mediabox.y1)); ctm = fz_concat(ctm, fz_scale(drawzoom, -drawzoom)); ctm = fz_concat(ctm, fz_rotate(drawrotate + drawpage->rotate)); bbox = fz_roundrect(fz_transformaabb(ctm, drawpage->mediabox)); w = bbox.x1 - bbox.x0; h = bbox.y1 - bbox.y0; bh = h / drawbands; if (drawpattern) { sprintf(name, drawpattern, drawcount++); fd = open(name, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666); if (fd < 0) die(fz_throw("ioerror: could not open file '%s'", name)); sprintf(pnmhdr, "P6\n%d %d\n255\n", w, h); write(fd, pnmhdr, strlen(pnmhdr)); } error = fz_newpixmap(&pix, bbox.x0, bbox.y0, w, bh, 4); if (error) die(error); memset(pix->samples, 0xff, pix->h * pix->w * pix->n); for (b = 0; b < drawbands; b++) { if (drawbands > 1) fprintf(stderr, "drawing band %d / %d\n", b + 1, drawbands); error = fz_rendertreeover(drawgc, pix, drawpage->tree, ctm); if (error) die(error); if (drawpattern) { for (y = 0; y < pix->h; y++) { unsigned char *src = pix->samples + y * pix->w * 4; unsigned char *dst = src; for (x = 0; x < pix->w; x++) { dst[x * 3 + 0] = src[x * 4 + 1]; dst[x * 3 + 1] = src[x * 4 + 2]; dst[x * 3 + 2] = src[x * 4 + 3]; } write(fd, dst, pix->w * 3); memset(src, 0xff, pix->w * 4); } } if (!drawpattern) fz_md5update(&digest, pix->samples, pix->h * pix->w * 4); pix->y += bh; if (pix->y + pix->h > bbox.y1) pix->h = bbox.y1 - pix->y; } fz_droppixmap(pix); if (!drawpattern) { unsigned char buf[16]; fz_md5final(&digest, buf); for (i = 0; i < 16; i++) fprintf(stderr, "%02x", buf[i]); } if (drawpattern) close(fd); drawfreepage(); if (benchmark) { gettime(&end); elapsed = end - start; if (elapsed < drawtimes->min) { drawtimes->min = elapsed; drawtimes->minpage = pagenum; } if (elapsed > drawtimes->max) { drawtimes->max = elapsed; drawtimes->maxpage = pagenum; } drawtimes->avg += elapsed; drawtimes->pages++; fprintf(stderr, " time %.3fs", elapsed / 1000000.0); } fprintf(stderr, "\n"); }
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; }
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); } }
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); }