static void fz_draw_clip_stroke_path(fz_context *ctx, void *user, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; fz_pixmap *mask, *dest, *shape; fz_bbox bbox; if (dev->top == dev->stack_max) fz_grow_stack(dev); if (linewidth * expansion < 0.1f) linewidth = 1 / expansion; fz_reset_gel(dev->gel, dev->scissor); if (stroke->dash_len > 0) fz_flatten_dash_path(ctx, dev->gel, path, stroke, ctm, flatness, linewidth); else fz_flatten_stroke_path(ctx, dev->gel, path, stroke, ctm, flatness, linewidth); fz_sort_gel(dev->gel); bbox = fz_bound_gel(dev->gel); bbox = fz_intersect_bbox(bbox, dev->scissor); if (rect) bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect)); mask = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(mask); dest = fz_new_pixmap_with_rect(ctx, model, bbox); /* FIXME: See note #1 */ fz_clear_pixmap(dest); if (dev->shape) { shape = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(shape); } else shape = NULL; if (!fz_is_empty_rect(bbox)) fz_scan_convert(dev->gel, 0, bbox, mask, NULL); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].shape = dev->shape; /* FIXME: See note #1 */ dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED; dev->scissor = bbox; dev->dest = dest; dev->shape = shape; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Clip (stroke) begin\n"); #endif dev->top++; }
static void fz_knockout_begin(fz_context *ctx, void *user) { fz_draw_device *dev = user; fz_bbox bbox; fz_pixmap *dest, *shape; int isolated = dev->blendmode & FZ_BLEND_ISOLATED; if ((dev->blendmode & FZ_BLEND_KNOCKOUT) == 0) return; if (dev->top == dev->stack_max) fz_grow_stack(dev); bbox = fz_bound_pixmap(dev->dest); bbox = fz_intersect_bbox(bbox, dev->scissor); dest = fz_new_pixmap_with_rect(ctx, dev->dest->colorspace, bbox); if (isolated) { fz_clear_pixmap(dest); } else { fz_pixmap *prev; int i = dev->top; do prev = dev->stack[--i].dest; while (prev == NULL); fz_copy_pixmap_rect(dest, prev, bbox); } if (dev->blendmode == 0 && isolated || 1 /* SumatraPDF: disable crashy shape code */) { /* We can render direct to any existing shape plane. If there * isn't one, we don't need to make one. */ shape = dev->shape; } else { shape = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); fz_clear_pixmap(shape); } dev->stack[dev->top].blendmode = dev->blendmode; dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].shape = dev->shape; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Knockout begin\n"); #endif dev->top++; dev->scissor = bbox; dev->dest = dest; dev->shape = shape; dev->blendmode &= ~FZ_BLEND_MODEMASK; }
static void fz_draw_end_mask(fz_context *ctx, void *user) { fz_draw_device *dev = user; fz_pixmap *mask = dev->dest; fz_pixmap *maskshape = dev->shape; fz_pixmap *temp, *dest; fz_bbox bbox; int luminosity; if (dev->top == dev->stack_max) fz_grow_stack(dev); if (dev->top > 0) { /* pop soft mask buffer */ dev->top--; luminosity = dev->stack[dev->top].luminosity; dev->scissor = dev->stack[dev->top].scissor; dev->dest = dev->stack[dev->top].dest; dev->shape = dev->stack[dev->top].shape; /* convert to alpha mask */ temp = fz_alpha_from_gray(ctx, mask, luminosity); fz_drop_pixmap(ctx, mask); fz_drop_pixmap(ctx, maskshape); /* create new dest scratch buffer */ bbox = fz_bound_pixmap(temp); dest = fz_new_pixmap_with_rect(ctx, dev->dest->colorspace, bbox); /* FIXME: See note #1 */ fz_clear_pixmap(dest); /* push soft mask as clip mask */ dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = temp; dev->stack[dev->top].dest = dev->dest; /* FIXME: See note #1 */ dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED; /* If we have a shape, then it'll need to be masked with the * clip mask when we pop. So create a new shape now. */ if (dev->shape) { dev->stack[dev->top].shape = dev->shape; dev->shape = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(dev->shape); } dev->scissor = bbox; dev->dest = dest; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Mask -> Clip\n"); #endif dev->top++; } }
void fz_paint_shade(fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox) { unsigned char clut[256][FZ_MAX_COLORS]; fz_pixmap *temp, *conv; float color[FZ_MAX_COLORS]; int i, k; ctm = fz_concat(shade->matrix, ctm); if (shade->use_function) { for (i = 0; i < 256; i++) { fz_convert_color(shade->colorspace, shade->function[i], dest->colorspace, color); for (k = 0; k < dest->colorspace->n; k++) clut[i][k] = color[k] * 255; clut[i][k] = shade->function[i][shade->colorspace->n] * 255; } conv = fz_new_pixmap_with_rect(dest->colorspace, bbox); temp = fz_new_pixmap_with_rect(fz_device_gray, bbox); fz_clear_pixmap(temp); } else { temp = dest; } switch (shade->type) { case FZ_LINEAR: fz_paint_linear(shade, ctm, temp, bbox); break; case FZ_RADIAL: fz_paint_radial(shade, ctm, temp, bbox); break; case FZ_MESH: fz_paint_mesh(shade, ctm, temp, bbox); break; } if (shade->use_function) { unsigned char *s = temp->samples; unsigned char *d = conv->samples; int len = temp->w * temp->h; while (len--) { int v = *s++; int a = fz_mul255(*s++, clut[v][conv->n - 1]); for (k = 0; k < conv->n - 1; k++) *d++ = fz_mul255(clut[v][k], a); *d++ = a; } fz_paint_pixmap(dest, conv, 255); fz_drop_pixmap(conv); fz_drop_pixmap(temp); } }
static void fz_draw_clip_path(void *user, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; fz_pixmap *mask, *dest; fz_bbox bbox; if (dev->top == STACK_SIZE) { fz_warn("assert: too many buffers on stack"); return; } fz_reset_gel(dev->gel, dev->scissor); fz_flatten_fill_path(dev->gel, path, ctm, flatness); fz_sort_gel(dev->gel); bbox = fz_bound_gel(dev->gel); bbox = fz_intersect_bbox(bbox, dev->scissor); if (rect) { bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect)); } if (fz_is_empty_rect(bbox) || fz_is_rect_gel(dev->gel)) { dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = NULL; dev->stack[dev->top].dest = NULL; dev->scissor = bbox; dev->top++; return; } mask = fz_new_pixmap_with_rect(NULL, bbox); dest = fz_new_pixmap_with_rect(model, bbox); fz_clear_pixmap(mask); fz_clear_pixmap(dest); fz_scan_convert(dev->gel, even_odd, bbox, mask, NULL); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->scissor = bbox; dev->dest = dest; dev->top++; }
static void fz_draw_clip_stroke_path(void *user, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; fz_pixmap *mask, *dest; fz_bbox bbox; if (dev->top == STACK_SIZE) { fz_warn("assert: too many buffers on stack"); return; } if (linewidth * expansion < 0.1f) linewidth = 1 / expansion; fz_reset_gel(dev->gel, dev->scissor); if (stroke->dash_len > 0) fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth); else fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth); fz_sort_gel(dev->gel); bbox = fz_bound_gel(dev->gel); bbox = fz_intersect_bbox(bbox, dev->scissor); if (rect) bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect)); mask = fz_new_pixmap_with_rect(NULL, bbox); dest = fz_new_pixmap_with_rect(model, bbox); fz_clear_pixmap(mask); fz_clear_pixmap(dest); if (!fz_is_empty_rect(bbox)) fz_scan_convert(dev->gel, 0, bbox, mask, NULL); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->scissor = bbox; dev->dest = dest; dev->top++; }
static void fz_draw_begin_tile(void *user, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_pixmap *dest; fz_bbox bbox; /* area, view, xstep, ystep are in pattern space */ /* ctm maps from pattern space to device space */ if (dev->top == STACK_SIZE) { fz_warn("assert: too many buffers on stack"); return; } bbox = fz_round_rect(fz_transform_rect(ctm, view)); dest = fz_new_pixmap_with_rect(model, bbox); fz_clear_pixmap(dest); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].xstep = xstep; dev->stack[dev->top].ystep = ystep; dev->stack[dev->top].area = area; dev->stack[dev->top].ctm = ctm; dev->top++; dev->scissor = bbox; dev->dest = dest; }
static void fz_draw_begin_group(void *user, fz_rect rect, int isolated, int knockout, int blendmode, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *dest; if (dev->top == STACK_SIZE) { fz_warn("assert: too many buffers on stack"); return; } bbox = fz_round_rect(rect); bbox = fz_intersect_bbox(bbox, dev->scissor); dest = fz_new_pixmap_with_rect(model, bbox); fz_clear_pixmap(dest); dev->stack[dev->top].alpha = alpha; dev->stack[dev->top].blendmode = blendmode; dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; dev->top++; dev->scissor = bbox; dev->dest = dest; }
static void fz_draw_begin_tile(fz_context *ctx, void *user, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_pixmap *dest; fz_bbox bbox; /* area, view, xstep, ystep are in pattern space */ /* ctm maps from pattern space to device space */ if (dev->top == dev->stack_max) fz_grow_stack(dev); if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); bbox = fz_round_rect(fz_transform_rect(ctm, view)); /* We should never have a bbox that entirely covers our destination. * If we do, then the check for only 1 tile being visible above has * failed. */ /* SumatraPDF: assertion intentionally disabled assert(bbox.x0 > dev->dest->x || bbox.x1 < dev->dest->x + dev->dest->w || bbox.y0 > dev->dest->y || bbox.y1 < dev->dest->y + dev->dest->h); /* cf. http://bugs.ghostscript.com/show_bug.cgi?id=692418 */ dest = fz_new_pixmap_with_limit(ctx, model, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0); if (dest) { dest->x = bbox.x0; dest->y = bbox.y0; } else { bbox.x1 = bbox.x0; bbox.y1 = bbox.y0; dest = fz_new_pixmap_with_rect(ctx, model, bbox); } /* FIXME: See note #1 */ fz_clear_pixmap(dest); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].shape = dev->shape; /* FIXME: See note #1 */ dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED; dev->stack[dev->top].xstep = xstep; dev->stack[dev->top].ystep = ystep; dev->stack[dev->top].area = area; dev->stack[dev->top].ctm = ctm; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Tile begin\n"); #endif dev->top++; dev->scissor = bbox; dev->dest = dest; }
static void fz_draw_begin_mask(fz_context *ctx, void *user, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *colorfv) { fz_draw_device *dev = user; fz_pixmap *dest; fz_pixmap *shape = dev->shape; fz_bbox bbox; if (dev->top == dev->stack_max) fz_grow_stack(dev); bbox = fz_round_rect(rect); bbox = fz_intersect_bbox(bbox, dev->scissor); dest = fz_new_pixmap_with_rect(ctx, fz_device_gray, bbox); if (dev->shape) { /* FIXME: If we ever want to support AIS true, then we * probably want to create a shape pixmap here, using: * shape = fz_new_pixmap_with_rect(NULL, bbox); * then, in the end_mask code, we create the mask from this * rather than dest. */ shape = NULL; } if (luminosity) { float bc; if (!colorspace) colorspace = fz_device_gray; fz_convert_color(ctx, colorspace, colorfv, fz_device_gray, &bc); fz_clear_pixmap_with_color(dest, bc * 255); if (shape) fz_clear_pixmap_with_color(shape, 255); } else { fz_clear_pixmap(dest); if (shape) fz_clear_pixmap(shape); } dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].luminosity = luminosity; dev->stack[dev->top].shape = dev->shape; dev->stack[dev->top].blendmode = dev->blendmode; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Mask begin\n"); #endif dev->top++; dev->scissor = bbox; dev->dest = dest; dev->shape = shape; }
QImage Pdf::page(int i) { pdf_page* page = pdf_load_page(xref, i); if (page == 0) { printf("cannot load page %d\n", i); return QImage(); } static const float resolution = 300.0; const float zoom = resolution / 72.0; fz_matrix ctm = fz_translate(0, -page->mediabox.y1); ctm = fz_concat(ctm, fz_scale(zoom, -zoom)); ctm = fz_concat(ctm, fz_rotate(page->rotate)); fz_bbox bbox = fz_round_rect(fz_transform_rect(ctm, page->mediabox)); fz_pixmap* pix = fz_new_pixmap_with_rect(ctx, fz_device_gray, bbox); fz_clear_pixmap_with_color(pix, 255); fz_device* dev = fz_new_draw_device(ctx, cache, pix); pdf_run_page(xref, page, dev, ctm); fz_free_device(dev); int w = pix->w; int h = pix->h; QImage image(w, h, QImage::Format_MonoLSB); QVector<QRgb> ct(2); ct[0] = qRgb(255, 255, 255); ct[1] = qRgb(0, 0, 0); image.setColorTable(ct); uchar* s = pix->samples; int stride = image.bytesPerLine(); int bytes = w >> 3; for (int line = 0; line < h; ++line) { uchar* d = image.bits() + stride * line; for (int col = 0; col < bytes; ++col) { uchar data = 0; for (int i = 0; i < 8; ++i) { uchar v = *s++; s++; data >>= 1; if (v < 128) data |= 0x80; } *d++ = data; } } fz_drop_pixmap(ctx, pix); pdf_free_page(ctx, page); return image; }
static void _pdf_doc_render_page( struct _pdf_doc *self, cairo_t *cr, int x, int y, int pageno, mume_matrix_t ctm, mume_rect_t rect) { /* TODO: implement a fz_device to rendering directly to cairo. */ fz_colorspace *colorspace; fz_bbox bbox; fz_device *idev; fz_pixmap *pixmap; fz_display_list *list; cairo_format_t format; cairo_surface_t *surface; int stride; #ifdef _WIN32 colorspace = fz_device_bgr; #else colorspace = fz_device_rgb; #endif list = _pdf_doc_get_list(self, pageno); bbox = _mume_rect_to_fz_bbox(rect); pixmap = fz_new_pixmap_with_rect(colorspace, bbox); if (NULL == pixmap) { mume_error(("fz_new_pixmap_with_rect(%d, %d, %d, %d)\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1)); return; } fz_clear_pixmap_with_color(pixmap, 255); idev = fz_new_draw_device(self->glyph_cache, pixmap); fz_execute_display_list( list, idev, _mume_matrix_to_fz_matrix(ctm), bbox); fz_free_device(idev); /* Create cairo surface. */ format = CAIRO_FORMAT_ARGB32; stride = cairo_format_stride_for_width(format, pixmap->w); surface = cairo_image_surface_create_for_data( pixmap->samples, format, pixmap->w, pixmap->h, stride); if (surface) { cairo_set_source_surface(cr, surface, x, y); cairo_rectangle(cr, x, y, rect.width, rect.height); cairo_fill(cr); cairo_surface_destroy(surface); } fz_drop_pixmap(pixmap); }
static void fz_draw_end_mask(void *user) { fz_draw_device *dev = user; fz_pixmap *mask = dev->dest; fz_pixmap *temp, *dest; fz_bbox bbox; int luminosity; if (dev->top == STACK_SIZE) { fz_warn("assert: too many buffers on stack"); return; } if (dev->top > 0) { /* pop soft mask buffer */ dev->top--; luminosity = dev->stack[dev->top].luminosity; dev->scissor = dev->stack[dev->top].scissor; dev->dest = dev->stack[dev->top].dest; /* convert to alpha mask */ temp = fz_alpha_from_gray(mask, luminosity); fz_drop_pixmap(mask); /* create new dest scratch buffer */ bbox = fz_bound_pixmap(temp); dest = fz_new_pixmap_with_rect(dev->dest->colorspace, bbox); fz_clear_pixmap(dest); /* push soft mask as clip mask */ dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = temp; dev->stack[dev->top].dest = dev->dest; dev->scissor = bbox; dev->dest = dest; dev->top++; } }
fz_pixmap * pdf_expand_indexed_pixmap(fz_pixmap *src) { struct indexed *idx; fz_pixmap *dst; unsigned char *s, *d; int y, x, k, n, high; unsigned char *lookup; assert(src->colorspace->to_rgb == indexed_to_rgb); assert(src->n == 2); idx = src->colorspace->data; high = idx->high; lookup = idx->lookup; n = idx->base->n; dst = fz_new_pixmap_with_rect(idx->base, fz_bound_pixmap(src)); s = src->samples; d = dst->samples; for (y = 0; y < src->h; y++) { for (x = 0; x < src->w; x++) { int v = *s++; int a = *s++; v = MIN(v, high); for (k = 0; k < n; k++) *d++ = fz_mul255(lookup[v * n + k], a); *d++ = a; } } if (src->mask) dst->mask = fz_keep_pixmap(src->mask); dst->interpolate = src->interpolate; return dst; }
static void saveimage(int num) { fz_error error; fz_pixmap *img; fz_obj *ref; char name[1024]; ref = fz_new_indirect(ctx, num, 0, xref); /* TODO: detect DCTD and save as jpeg */ error = pdf_load_image(&img, xref, ref); if (error) die(error); if (dorgb && img->colorspace && img->colorspace != fz_device_rgb) { fz_pixmap *temp; temp = fz_new_pixmap_with_rect(ctx, fz_device_rgb, fz_bound_pixmap(img)); fz_convert_pixmap(ctx, img, temp); fz_drop_pixmap(ctx, img); img = temp; } if (img->n <= 4) { sprintf(name, "img-%04d.png", num); printf("extracting image %s\n", name); fz_write_png(ctx, img, name, 0); } else { sprintf(name, "img-%04d.pam", num); printf("extracting image %s\n", name); fz_write_pam(ctx, img, name, 0); } fz_drop_pixmap(ctx, img); fz_drop_obj(ctx, ref); }
fz_pixmap * fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray, int luminosity) { fz_pixmap *alpha; unsigned char *sp, *dp; int len; assert(gray->n == 2); alpha = fz_new_pixmap_with_rect(ctx, NULL, fz_bound_pixmap(gray)); dp = alpha->samples; sp = gray->samples; if (!luminosity) sp ++; len = gray->w * gray->h; while (len--) { *dp++ = sp[0]; sp += 2; } return alpha; }
static void fz_draw_begin_mask(void *user, fz_rect rect, int luminosity, fz_colorspace *colorspace, float *colorfv) { fz_draw_device *dev = user; fz_pixmap *dest; fz_bbox bbox; if (dev->top == STACK_SIZE) { fz_warn("assert: too many buffers on stack"); return; } bbox = fz_round_rect(rect); bbox = fz_intersect_bbox(bbox, dev->scissor); dest = fz_new_pixmap_with_rect(fz_device_gray, bbox); if (luminosity) { float bc; if (!colorspace) colorspace = fz_device_gray; fz_convert_color(colorspace, colorfv, fz_device_gray, &bc); fz_clear_pixmap_with_color(dest, bc * 255); } else fz_clear_pixmap(dest); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].luminosity = luminosity; dev->top++; dev->scissor = bbox; dev->dest = dest; }
static void fz_draw_fill_image(fz_context *ctx, void *user, fz_pixmap *image, fz_matrix ctm, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_pixmap *converted = NULL; fz_pixmap *scaled = NULL; int after; int dx, dy; if (!model) { fz_warn(ctx, "cannot render image directly to an alpha mask"); return; } if (image->w == 0 || image->h == 0) return; /* convert images with more components (cmyk->rgb) before scaling */ /* convert images with fewer components (gray->rgb after scaling */ /* convert images with expensive colorspace transforms after scaling */ if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); after = 0; if (image->colorspace == fz_device_gray) after = 1; if (image->colorspace != model && !after) { converted = fz_new_pixmap_with_rect(ctx, model, fz_bound_pixmap(image)); fz_convert_pixmap(ctx, image, converted); image = converted; } dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); if (dx < image->w && dy < image->h) { int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); scaled = fz_transform_pixmap(ctx, image, &ctm, dev->dest->x, dev->dest->y, dx, dy, gridfit); if (scaled == NULL) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; scaled = fz_scale_pixmap(ctx, image, image->x, image->y, dx, dy); } if (scaled != NULL) image = scaled; } if (image->colorspace != model) { if ((image->colorspace == fz_device_gray && model == fz_device_rgb) || (image->colorspace == fz_device_gray && model == fz_device_bgr)) { /* We have special case rendering code for gray -> rgb/bgr */ } else { converted = fz_new_pixmap_with_rect(ctx, model, fz_bound_pixmap(image)); fz_convert_pixmap(ctx, image, converted); image = converted; } } fz_paint_image(dev->dest, dev->scissor, dev->shape, image, ctm, alpha * 255); if (scaled) fz_drop_pixmap(ctx, scaled); if (converted) fz_drop_pixmap(ctx, converted); if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); }
static void fz_draw_fill_shade(fz_context *ctx, void *user, fz_shade *shade, fz_matrix ctm, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_pixmap *dest = dev->dest; fz_rect bounds; fz_bbox bbox, scissor; float colorfv[FZ_MAX_COLORS]; unsigned char colorbv[FZ_MAX_COLORS + 1]; bounds = fz_bound_shade(shade, ctm); bbox = fz_intersect_bbox(fz_round_rect(bounds), dev->scissor); scissor = dev->scissor; // TODO: proper clip by shade->bbox if (fz_is_empty_rect(bbox)) return; if (!model) { fz_warn(ctx, "cannot render shading directly to an alpha mask"); return; } if (alpha < 1) { dest = fz_new_pixmap_with_rect(ctx, dev->dest->colorspace, bbox); fz_clear_pixmap(dest); } if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); if (shade->use_background) { unsigned char *s; int x, y, n, i; fz_convert_color(ctx, shade->colorspace, shade->background, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = 255; n = dest->n; for (y = scissor.y0; y < scissor.y1; y++) { s = dest->samples + ((scissor.x0 - dest->x) + (y - dest->y) * dest->w) * dest->n; for (x = scissor.x0; x < scissor.x1; x++) { for (i = 0; i < n; i++) *s++ = colorbv[i]; } } if (dev->shape) { for (y = scissor.y0; y < scissor.y1; y++) { s = dev->shape->samples + (scissor.x0 - dev->shape->x) + (y - dev->shape->y) * dev->shape->w; for (x = scissor.x0; x < scissor.x1; x++) { *s++ = 255; } } } } fz_paint_shade(ctx, shade, ctm, dest, bbox); if (dev->shape) fz_clear_pixmap_rect_with_color(dev->shape, 255, bbox); if (alpha < 1) { fz_paint_pixmap(dev->dest, dest, alpha * 255); fz_drop_pixmap(ctx, dest); } if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); }
static void fz_draw_clip_stroke_text(fz_context *ctx, void *user, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *mask, *dest, *shape; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; if (dev->top == dev->stack_max) fz_grow_stack(dev); /* make the mask the exact size needed */ bbox = fz_round_rect(fz_bound_text(text, ctm)); bbox = fz_intersect_bbox(bbox, dev->scissor); mask = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(mask); dest = fz_new_pixmap_with_rect(ctx, model, bbox); /* FIXME: See note #1 */ fz_clear_pixmap(dest); if (dev->shape) { shape = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(shape); } else shape = dev->shape; dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].shape = dev->shape; /* FIXME: See note #1 */ dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED; dev->scissor = bbox; dev->dest = dest; dev->shape = shape; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Clip (stroke text) begin\n"); #endif dev->top++; if (!fz_is_empty_rect(bbox)) { tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->items[i].gid; if (gid < 0) continue; tm.e = text->items[i].x; tm.f = text->items[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); glyph = fz_render_stroked_glyph(ctx, dev->cache, text->font, gid, trm, ctm, stroke); if (glyph) { draw_glyph(NULL, mask, glyph, x, y, bbox); if (dev->shape) draw_glyph(NULL, dev->shape, glyph, x, y, bbox); fz_drop_pixmap(ctx, glyph); } } } }
static void fz_draw_clip_text(fz_context *ctx, void *user, fz_text *text, fz_matrix ctm, int accumulate) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *mask, *dest, *shape; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; /* If accumulate == 0 then this text object is guaranteed complete */ /* If accumulate == 1 then this text object is the first (or only) in a sequence */ /* If accumulate == 2 then this text object is a continuation */ if (dev->top == dev->stack_max) fz_grow_stack(dev); if (accumulate == 0) { /* make the mask the exact size needed */ bbox = fz_round_rect(fz_bound_text(text, ctm)); bbox = fz_intersect_bbox(bbox, dev->scissor); } else { /* be conservative about the size of the mask needed */ bbox = dev->scissor; } if (accumulate == 0 || accumulate == 1) { mask = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(mask); dest = fz_new_pixmap_with_rect(ctx, model, bbox); /* FIXME: See note #1 */ fz_clear_pixmap(dest); if (dev->shape) { shape = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(shape); } else shape = NULL; dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].shape = dev->shape; /* FIXME: See note #1 */ dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED; dev->scissor = bbox; dev->dest = dest; dev->shape = shape; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Clip (text) begin\n"); #endif dev->top++; } else { mask = dev->stack[dev->top-1].mask; } if (!fz_is_empty_rect(bbox)) { tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->items[i].gid; if (gid < 0) continue; tm.e = text->items[i].x; tm.f = text->items[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); glyph = fz_render_glyph(ctx, dev->cache, text->font, gid, trm, model); if (glyph) { draw_glyph(NULL, mask, glyph, x, y, bbox); if (dev->shape) draw_glyph(NULL, dev->shape, glyph, x, y, bbox); fz_drop_pixmap(ctx, glyph); } } } }
static void fz_draw_fill_text(fz_context *ctx, void *user, fz_text *text, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; unsigned char colorbv[FZ_MAX_COLORS + 1]; unsigned char shapebv; float colorfv[FZ_MAX_COLORS]; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); fz_convert_color(ctx, colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; shapebv = 255; tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->items[i].gid; if (gid < 0) continue; tm.e = text->items[i].x; tm.f = text->items[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); glyph = fz_render_glyph(ctx, dev->cache, text->font, gid, trm, model); if (glyph) { /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1746 */ if (glyph->n > 1 && text->font->t3procs) { float light; fz_convert_color(ctx, colorspace, color, fz_device_gray, &light); if (light != 0) { fz_pixmap *gray = fz_new_pixmap_with_rect(ctx, fz_device_gray, fz_bound_pixmap(glyph)); fz_convert_pixmap(ctx, glyph, gray); fz_drop_pixmap(ctx, glyph); glyph = fz_alpha_from_gray(ctx, gray, 0); fz_drop_pixmap(ctx, gray); } } if (glyph->n == 1) { draw_glyph(colorbv, dev->dest, glyph, x, y, dev->scissor); if (dev->shape) draw_glyph(&shapebv, dev->shape, glyph, x, y, dev->scissor); } else { fz_matrix ctm = {glyph->w, 0.0, 0.0, -glyph->h, x + glyph->x, y + glyph->y + glyph->h}; fz_paint_image(dev->dest, dev->scissor, dev->shape, glyph, ctm, alpha * 255); } fz_drop_pixmap(ctx, glyph); } } if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); }
static void fz_draw_clip_path(fz_context *ctx, void *user, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; fz_pixmap *mask, *dest, *shape; fz_bbox bbox; if (dev->top == dev->stack_max) fz_grow_stack(dev); fz_reset_gel(dev->gel, dev->scissor); fz_flatten_fill_path(ctx, dev->gel, path, ctm, flatness); fz_sort_gel(dev->gel); bbox = fz_bound_gel(dev->gel); bbox = fz_intersect_bbox(bbox, dev->scissor); if (rect) bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect)); if (fz_is_empty_rect(bbox) || fz_is_rect_gel(dev->gel)) { dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = NULL; dev->stack[dev->top].dest = NULL; dev->stack[dev->top].shape = dev->shape; dev->stack[dev->top].blendmode = dev->blendmode; dev->scissor = bbox; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Clip (rectangular) begin\n"); #endif dev->top++; return; } mask = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(mask); dest = fz_new_pixmap_with_rect(ctx, model, bbox); /* FIXME: See note #1 */ fz_clear_pixmap(dest); if (dev->shape) { shape = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(shape); } else shape = NULL; fz_scan_convert(dev->gel, even_odd, bbox, mask, NULL); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].shape = dev->shape; /* FIXME: See note #1 */ dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED; dev->scissor = bbox; dev->dest = dest; dev->shape = shape; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Clip (non-rectangular) begin\n"); #endif dev->top++; }
static void fz_draw_clip_text(void *user, fz_text *text, fz_matrix ctm, int accumulate) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *mask, *dest; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; /* If accumulate == 0 then this text object is guaranteed complete */ /* If accumulate == 1 then this text object is the first (or only) in a sequence */ /* If accumulate == 2 then this text object is a continuation */ if (dev->top == STACK_SIZE) { fz_warn("assert: too many buffers on stack"); return; } if (accumulate == 0) { /* make the mask the exact size needed */ bbox = fz_round_rect(fz_bound_text(text, ctm)); bbox = fz_intersect_bbox(bbox, dev->scissor); } else { /* be conservative about the size of the mask needed */ bbox = dev->scissor; } if (accumulate == 0 || accumulate == 1) { mask = fz_new_pixmap_with_rect(NULL, bbox); dest = fz_new_pixmap_with_rect(model, bbox); fz_clear_pixmap(mask); fz_clear_pixmap(dest); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->scissor = bbox; dev->dest = dest; dev->top++; } else { mask = dev->stack[dev->top-1].mask; } if (!fz_is_empty_rect(bbox)) { tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->items[i].gid; if (gid < 0) continue; tm.e = text->items[i].x; tm.f = text->items[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); glyph = fz_render_glyph(dev->cache, text->font, gid, trm); if (glyph) { draw_glyph(NULL, mask, glyph, x, y, bbox); fz_drop_pixmap(glyph); } } } }
static void fz_draw_begin_group(fz_context *ctx, void *user, fz_rect rect, int isolated, int knockout, int blendmode, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *dest, *shape; if (dev->top == dev->stack_max) { fz_warn(ctx, "assert: too many buffers on stack"); return; } if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); bbox = fz_round_rect(rect); bbox = fz_intersect_bbox(bbox, dev->scissor); dest = fz_new_pixmap_with_rect(ctx, model, bbox); #ifndef ATTEMPT_KNOCKOUT_AND_ISOLATED knockout = 0; isolated = 1; #endif if (isolated) { fz_clear_pixmap(dest); } else { fz_copy_pixmap_rect(dest, dev->dest, bbox); } if (blendmode == 0 && alpha == 1.0 && isolated || 1 /* SumatraPDF: disable crashy shape code */) { /* We can render direct to any existing shape plane. If there * isn't one, we don't need to make one. */ shape = dev->shape; } else { shape = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(shape); } dev->stack[dev->top].alpha = alpha; dev->stack[dev->top].blendmode = dev->blendmode; dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].shape = dev->shape; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Group Begin\n"); #endif dev->top++; dev->scissor = bbox; dev->dest = dest; dev->shape = shape; dev->blendmode = blendmode | (isolated ? FZ_BLEND_ISOLATED : 0) | (knockout ? FZ_BLEND_KNOCKOUT : 0); }
static void fz_draw_clip_stroke_text(void *user, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *mask, *dest; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; if (dev->top == STACK_SIZE) { fz_warn("assert: too many buffers on stack"); return; } /* make the mask the exact size needed */ bbox = fz_round_rect(fz_bound_text(text, ctm)); bbox = fz_intersect_bbox(bbox, dev->scissor); mask = fz_new_pixmap_with_rect(NULL, bbox); dest = fz_new_pixmap_with_rect(model, bbox); fz_clear_pixmap(mask); fz_clear_pixmap(dest); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->scissor = bbox; dev->dest = dest; dev->top++; if (!fz_is_empty_rect(bbox)) { tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->items[i].gid; if (gid < 0) continue; tm.e = text->items[i].x; tm.f = text->items[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); glyph = fz_render_stroked_glyph(dev->cache, text->font, gid, trm, ctm, stroke); if (glyph) { draw_glyph(NULL, mask, glyph, x, y, bbox); fz_drop_pixmap(glyph); } } } }
static void fz_draw_clip_image_mask(void *user, fz_pixmap *image, fz_rect *rect, fz_matrix ctm) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *mask, *dest; fz_pixmap *scaled = NULL; int dx, dy; if (dev->top == STACK_SIZE) { fz_warn("assert: too many buffers on stack"); return; } if (image->w == 0 || image->h == 0) { dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = NULL; dev->stack[dev->top].dest = NULL; dev->scissor = fz_empty_bbox; dev->top++; return; } bbox = fz_round_rect(fz_transform_rect(ctm, fz_unit_rect)); bbox = fz_intersect_bbox(bbox, dev->scissor); if (rect) bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect)); mask = fz_new_pixmap_with_rect(NULL, bbox); dest = fz_new_pixmap_with_rect(model, bbox); fz_clear_pixmap(mask); fz_clear_pixmap(dest); dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); if (dx < image->w && dy < image->h) { scaled = fz_transform_pixmap(image, &ctm, dev->dest->x, dev->dest->y, dx, dy); if (scaled == NULL) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; scaled = fz_scale_pixmap(image, image->x, image->y, dx, dy); } if (scaled != NULL) image = scaled; } fz_paint_image(mask, bbox, image, ctm, 255); if (scaled) fz_drop_pixmap(scaled); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->scissor = bbox; dev->dest = dest; dev->top++; }
static void fz_draw_clip_image_mask(fz_context *ctx, void *user, fz_pixmap *image, fz_rect *rect, fz_matrix ctm) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *mask, *dest, *shape; fz_pixmap *scaled = NULL; int dx, dy; if (dev->top == dev->stack_max) fz_grow_stack(dev); #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Clip (image mask) begin\n"); #endif if (image->w == 0 || image->h == 0) { dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = NULL; dev->stack[dev->top].dest = NULL; dev->stack[dev->top].blendmode = dev->blendmode; dev->scissor = fz_empty_bbox; dev->top++; return; } bbox = fz_round_rect(fz_transform_rect(ctm, fz_unit_rect)); bbox = fz_intersect_bbox(bbox, dev->scissor); if (rect) bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect)); mask = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(mask); dest = fz_new_pixmap_with_rect(ctx, model, bbox); /* FIXME: See note #1 */ fz_clear_pixmap(dest); if (dev->shape) { shape = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(shape); } else shape = NULL; dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); if (dx < image->w && dy < image->h) { int gridfit = !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); scaled = fz_transform_pixmap(ctx, image, &ctm, dev->dest->x, dev->dest->y, dx, dy, gridfit); if (scaled == NULL) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; scaled = fz_scale_pixmap(ctx, image, image->x, image->y, dx, dy); } if (scaled != NULL) image = scaled; } fz_paint_image(mask, bbox, dev->shape, image, ctm, 255); if (scaled) fz_drop_pixmap(ctx, scaled); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].shape = dev->shape; /* FIXME: See note #1 */ dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED; dev->scissor = bbox; dev->dest = dest; dev->shape = shape; dev->top++; }
static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint) { char buf[256]; fz_device *idev; fz_device *tdev; fz_colorspace *colorspace; fz_matrix ctm; fz_bbox bbox; wincursor(app, WAIT); if (loadpage) { if (app->page_list) fz_free_display_list(app->page_list); if (app->page_text) fz_free_text_span(app->page_text); if (app->page_links) pdf_free_link(app->page_links); if (app->xref) pdfapp_loadpage_pdf(app); if (app->xps) pdfapp_loadpage_xps(app); /* Zero search hit position */ app->hit = -1; app->hitlen = 0; /* Extract text */ app->page_text = fz_new_text_span(); tdev = fz_new_text_device(app->page_text); fz_execute_display_list(app->page_list, tdev, fz_identity, fz_infinite_bbox); fz_free_device(tdev); } if (drawpage) { sprintf(buf, "%s - %d/%d (%d dpi)", app->doctitle, app->pageno, app->pagecount, app->resolution); wintitle(app, buf); ctm = pdfapp_viewctm(app); bbox = fz_round_rect(fz_transform_rect(ctm, app->page_bbox)); /* Draw */ if (app->image) fz_drop_pixmap(app->image); if (app->grayscale) colorspace = fz_device_gray; else #ifdef _WIN32 colorspace = fz_device_bgr; #else colorspace = fz_device_rgb; #endif app->image = fz_new_pixmap_with_rect(colorspace, bbox); fz_clear_pixmap_with_color(app->image, 255); idev = fz_new_draw_device(app->cache, app->image); fz_execute_display_list(app->page_list, idev, ctm, bbox); fz_free_device(idev); } if (repaint) { pdfapp_panview(app, app->panx, app->pany); if (app->shrinkwrap) { int w = app->image->w; int h = app->image->h; if (app->winw == w) app->panx = 0; if (app->winh == h) app->pany = 0; if (w > app->scrw * 90 / 100) w = app->scrw * 90 / 100; if (h > app->scrh * 90 / 100) h = app->scrh * 90 / 100; if (w != app->winw || h != app->winh) winresize(app, w, h); } winrepaint(app); wincursor(app, ARROW); } fz_flush_warnings(); }
static void drawpage(xps_context *ctx, int pagenum) { xps_page *page; fz_display_list *list; fz_device *dev; int start; int code; if (showtime) { start = gettime(); } code = xps_load_page(&page, ctx, pagenum - 1); if (code) die(fz_rethrow(code, "cannot load page %d in file '%s'", pagenum, filename)); list = NULL; if (uselist) { list = fz_new_display_list(); dev = fz_new_list_device(list); xps_run_page(ctx, page, dev, fz_identity); fz_free_device(dev); } if (showxml) { dev = fz_new_trace_device(); printf("<page number=\"%d\">\n", pagenum); if (list) fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox); else xps_run_page(ctx, page, dev, fz_identity); printf("</page>\n"); fz_free_device(dev); } if (showtext) { fz_text_span *text = fz_new_text_span(); dev = fz_new_text_device(text); if (list) fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox); else xps_run_page(ctx, page, dev, fz_identity); fz_free_device(dev); printf("[Page %d]\n", pagenum); if (showtext > 1) fz_debug_text_span_xml(text); else fz_debug_text_span(text); printf("\n"); fz_free_text_span(text); } if (showmd5 || showtime) printf("page %s %d", filename, pagenum); if (output || showmd5 || showtime) { float zoom; fz_matrix ctm; fz_rect rect; fz_bbox bbox; fz_pixmap *pix; rect.x0 = rect.y0 = 0; rect.x1 = page->width; rect.y1 = page->height; zoom = resolution / 96; ctm = fz_translate(0, -page->height); ctm = fz_concat(ctm, fz_scale(zoom, zoom)); bbox = fz_round_rect(fz_transform_rect(ctm, rect)); /* TODO: banded rendering and multi-page ppm */ pix = fz_new_pixmap_with_rect(colorspace, bbox); if (savealpha) fz_clear_pixmap(pix); else fz_clear_pixmap_with_color(pix, 255); dev = fz_new_draw_device(glyphcache, pix); if (list) fz_execute_display_list(list, dev, ctm, bbox); else xps_run_page(ctx, page, dev, ctm); fz_free_device(dev); if (output) { char buf[512]; sprintf(buf, output, pagenum); if (strstr(output, ".pgm") || strstr(output, ".ppm") || strstr(output, ".pnm")) fz_write_pnm(pix, buf); else if (strstr(output, ".pam")) fz_write_pam(pix, buf, savealpha); else if (strstr(output, ".png")) fz_write_png(pix, buf, savealpha); } if (showmd5) { fz_md5 md5; unsigned char digest[16]; int i; fz_md5_init(&md5); fz_md5_update(&md5, pix->samples, pix->w * pix->h * pix->n); fz_md5_final(&md5, digest); printf(" "); for (i = 0; i < 16; i++) printf("%02x", digest[i]); } fz_drop_pixmap(pix); } if (list) fz_free_display_list(list); if (showtime) { int end = gettime(); int diff = end - start; if (diff < timing.min) { timing.min = diff; timing.minpage = pagenum; } if (diff > timing.max) { timing.max = diff; timing.maxpage = pagenum; } timing.total += diff; timing.count ++; printf(" %dms", diff); } if (showmd5 || showtime) printf("\n"); }