void fz_write_pixmap(fz_context *ctx, fz_pixmap *img, char *file, int rgb) { char name[1024]; fz_pixmap *converted = NULL; if (!img) return; if (rgb && img->colorspace && img->colorspace != fz_device_rgb) { fz_irect bbox; converted = fz_new_pixmap_with_bbox(ctx, fz_device_rgb, fz_pixmap_bbox(ctx, img, &bbox)); fz_convert_pixmap(ctx, converted, img); img = converted; } if (img->n <= 4) { sprintf(name, "%s.png", file); printf("extracting image %s\n", name); fz_write_png(ctx, img, name, 0); } else { sprintf(name, "%s.pam", file); printf("extracting image %s\n", name); fz_write_pam(ctx, img, name, 0); } fz_drop_pixmap(ctx, converted); }
static void writepixmap(fz_context *ctx, fz_pixmap *pix, char *file, int rgb) { char buf[1024]; fz_pixmap *converted = NULL; if (!pix) return; if (rgb && pix->colorspace && pix->colorspace != fz_device_rgb(ctx)) { fz_irect bbox; converted = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), fz_pixmap_bbox(ctx, pix, &bbox), pix->alpha); fz_convert_pixmap(ctx, converted, pix); pix = converted; } if (pix->n <= 4) { snprintf(buf, sizeof(buf), "%s.png", file); printf("extracting image %s\n", buf); fz_save_pixmap_as_png(ctx, pix, buf); } else { snprintf(buf, sizeof(buf), "%s.pam", file); printf("extracting image %s\n", buf); fz_save_pixmap_as_pam(ctx, pix, buf); } fz_drop_pixmap(ctx, converted); }
static fz_image * pdf_load_jpx_imp(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask) { fz_image *image = pdf_load_jpx(ctx, doc, dict, forcemask); if (forcemask) { fz_pixmap_image *cimg = (fz_pixmap_image *)image; fz_pixmap *mask_pixmap; fz_pixmap *tile = fz_pixmap_image_tile(ctx, cimg); if (tile->n != 1) { fz_pixmap *gray = fz_convert_pixmap(ctx, tile, fz_device_gray(ctx), NULL, NULL, fz_default_color_params(ctx), 0); fz_drop_pixmap(ctx, tile); tile = gray; } mask_pixmap = fz_alpha_from_gray(ctx, tile); fz_drop_pixmap(ctx, tile); fz_set_pixmap_image_tile(ctx, cimg, mask_pixmap); } return image; }
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); }
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_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); }
fz_pixmap * fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *defcs) { fz_pixmap *img; opj_event_mgr_t evtmgr; opj_dparameters_t params; opj_dinfo_t *info; opj_cio_t *cio; opj_image_t *jpx; fz_colorspace *colorspace; unsigned char *p; int format; int a, n, w, h, depth, sgnd; int x, y, k, v; if (size < 2) fz_throw(ctx, "not enough data to determine image format"); /* Check for SOC marker -- if found we have a bare J2K stream */ if (data[0] == 0xFF && data[1] == 0x4F) format = CODEC_J2K; else format = CODEC_JP2; memset(&evtmgr, 0, sizeof(evtmgr)); evtmgr.error_handler = fz_opj_error_callback; evtmgr.warning_handler = fz_opj_warning_callback; evtmgr.info_handler = fz_opj_info_callback; opj_set_default_decoder_parameters(¶ms); info = opj_create_decompress(format); opj_set_event_mgr((opj_common_ptr)info, &evtmgr, ctx); opj_setup_decoder(info, ¶ms); cio = opj_cio_open((opj_common_ptr)info, data, size); jpx = opj_decode(info, cio); opj_cio_close(cio); opj_destroy_decompress(info); if (!jpx) fz_throw(ctx, "opj_decode failed"); for (k = 1; k < jpx->numcomps; k++) { if (jpx->comps[k].w != jpx->comps[0].w) fz_throw(ctx, "image components have different width"); if (jpx->comps[k].h != jpx->comps[0].h) fz_throw(ctx, "image components have different height"); if (jpx->comps[k].prec != jpx->comps[0].prec) fz_throw(ctx, "image components have different precision"); } n = jpx->numcomps; w = jpx->comps[0].w; h = jpx->comps[0].h; depth = jpx->comps[0].prec; sgnd = jpx->comps[0].sgnd; if (jpx->color_space == CLRSPC_SRGB && n == 4) { n = 3; a = 1; } else if (jpx->color_space == CLRSPC_SYCC && n == 4) { n = 3; a = 1; } else if (n == 2) { n = 1; a = 1; } else if (n > 4) { n = 4; a = 1; } else { a = 0; } if (defcs) { if (defcs->n == n) { colorspace = defcs; } else { fz_warn(ctx, "jpx file and dict colorspaces do not match"); defcs = NULL; } } if (!defcs) { switch (n) { case 1: colorspace = fz_device_gray; break; case 3: colorspace = fz_device_rgb; break; case 4: colorspace = fz_device_cmyk; break; } } fz_try(ctx) { img = fz_new_pixmap(ctx, colorspace, w, h); } fz_catch(ctx) { opj_image_destroy(jpx); fz_throw(ctx, "out of memory"); } p = img->samples; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { for (k = 0; k < n + a; k++) { v = jpx->comps[k].data[y * w + x]; if (sgnd) v = v + (1 << (depth - 1)); if (depth > 8) v = v >> (depth - 8); *p++ = v; } if (!a) *p++ = 255; } } if (a) { if (n == 4) { fz_pixmap *tmp = fz_new_pixmap(ctx, fz_device_rgb, w, h); fz_convert_pixmap(ctx, img, tmp); fz_drop_pixmap(ctx, img); img = tmp; } fz_premultiply_pixmap(ctx, img); } opj_image_destroy(jpx); return img; }
static void fz_draw_fill_image(fz_device *devp, fz_image *image, fz_matrix ctm, float alpha) { fz_draw_device *dev = devp->user; fz_pixmap *converted = NULL; fz_pixmap *scaled = NULL; fz_pixmap *pixmap; fz_pixmap *orig_pixmap; int after; int dx, dy; fz_context *ctx = dev->ctx; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; fz_bbox clip = fz_pixmap_bbox(ctx, state->dest); clip = fz_intersect_bbox(clip, state->scissor); fz_var(scaled); if (!model) { fz_warn(dev->ctx, "cannot render image directly to an alpha mask"); return; } if (image->w == 0 || image->h == 0) return; dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); pixmap = fz_image_to_pixmap(ctx, image, dx, dy); orig_pixmap = pixmap; /* 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 */ fz_try(ctx) { if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); after = 0; if (pixmap->colorspace == fz_device_gray) after = 1; if (pixmap->colorspace != model && !after) { converted = fz_new_pixmap_with_bbox(ctx, model, fz_pixmap_bbox(ctx, pixmap)); fz_convert_pixmap(ctx, converted, pixmap); pixmap = converted; } if (dx < pixmap->w && dy < pixmap->h) { int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); scaled = fz_transform_pixmap(ctx, pixmap, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip); if (!scaled) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; scaled = fz_scale_pixmap(ctx, pixmap, pixmap->x, pixmap->y, dx, dy, NULL); } if (scaled) pixmap = scaled; } if (pixmap->colorspace != model) { if ((pixmap->colorspace == fz_device_gray && model == fz_device_rgb) || (pixmap->colorspace == fz_device_gray && model == fz_device_bgr)) { /* We have special case rendering code for gray -> rgb/bgr */ } else { converted = fz_new_pixmap_with_bbox(ctx, model, fz_pixmap_bbox(ctx, pixmap)); fz_convert_pixmap(ctx, converted, pixmap); pixmap = converted; } } fz_paint_image(state->dest, state->scissor, state->shape, pixmap, ctm, alpha * 255); if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); } fz_always(ctx) { fz_drop_pixmap(ctx, scaled); fz_drop_pixmap(ctx, converted); fz_drop_pixmap(ctx, orig_pixmap); } fz_catch(ctx) { fz_rethrow(ctx); } }
fz_pixmap * fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *defcs, int indexed) { fz_pixmap *img; fz_colorspace *origcs; opj_dparameters_t params; opj_codec_t *codec; opj_image_t *jpx; opj_stream_t *stream; fz_colorspace *colorspace; unsigned char *p; OPJ_CODEC_FORMAT format; int a, n, w, h, depth, sgnd; int x, y, k, v; stream_block sb; if (size < 2) fz_throw(ctx, FZ_ERROR_GENERIC, "not enough data to determine image format"); /* Check for SOC marker -- if found we have a bare J2K stream */ if (data[0] == 0xFF && data[1] == 0x4F) format = OPJ_CODEC_J2K; else format = OPJ_CODEC_JP2; opj_set_default_decoder_parameters(¶ms); if (indexed) params.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG; codec = opj_create_decompress(format); opj_set_info_handler(codec, fz_opj_info_callback, ctx); opj_set_warning_handler(codec, fz_opj_warning_callback, ctx); opj_set_error_handler(codec, fz_opj_error_callback, ctx); if (!opj_setup_decoder(codec, ¶ms)) { fz_throw(ctx, FZ_ERROR_GENERIC, "j2k decode failed"); } stream = opj_stream_default_create(OPJ_TRUE); sb.data = data; sb.pos = 0; sb.size = size; opj_stream_set_read_function(stream, fz_opj_stream_read); opj_stream_set_skip_function(stream, fz_opj_stream_skip); opj_stream_set_seek_function(stream, fz_opj_stream_seek); opj_stream_set_user_data(stream, &sb); /* Set the length to avoid an assert */ opj_stream_set_user_data_length(stream, size); if (!opj_read_header(stream, codec, &jpx)) { opj_stream_destroy(stream); opj_destroy_codec(codec); fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to read JPX header"); } if (!opj_decode(codec, stream, jpx)) { opj_stream_destroy(stream); opj_destroy_codec(codec); opj_image_destroy(jpx); fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to decode JPX image"); } opj_stream_destroy(stream); opj_destroy_codec(codec); /* jpx should never be NULL here, but check anyway */ if (!jpx) fz_throw(ctx, FZ_ERROR_GENERIC, "opj_decode failed"); for (k = 1; k < (int)jpx->numcomps; k++) { if (!jpx->comps[k].data) { opj_image_destroy(jpx); fz_throw(ctx, FZ_ERROR_GENERIC, "image components are missing data"); } if (jpx->comps[k].w != jpx->comps[0].w) { opj_image_destroy(jpx); fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different width"); } if (jpx->comps[k].h != jpx->comps[0].h) { opj_image_destroy(jpx); fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different height"); } if (jpx->comps[k].prec != jpx->comps[0].prec) { opj_image_destroy(jpx); fz_throw(ctx, FZ_ERROR_GENERIC, "image components have different precision"); } } n = jpx->numcomps; w = jpx->comps[0].w; h = jpx->comps[0].h; depth = jpx->comps[0].prec; sgnd = jpx->comps[0].sgnd; if (jpx->color_space == OPJ_CLRSPC_SRGB && n == 4) { n = 3; a = 1; } else if (jpx->color_space == OPJ_CLRSPC_SYCC && n == 4) { n = 3; a = 1; } else if (n == 2) { n = 1; a = 1; } else if (n > 4) { n = 4; a = 1; } else { a = 0; } origcs = defcs; if (defcs) { if (defcs->n == n) { colorspace = defcs; } else { fz_warn(ctx, "jpx file and dict colorspaces do not match"); defcs = NULL; } } if (!defcs) { switch (n) { case 1: colorspace = fz_device_gray(ctx); break; case 3: colorspace = fz_device_rgb(ctx); break; case 4: colorspace = fz_device_cmyk(ctx); break; } } fz_try(ctx) { img = fz_new_pixmap(ctx, colorspace, w, h); } fz_catch(ctx) { opj_image_destroy(jpx); fz_rethrow_message(ctx, "out of memory loading jpx"); } p = img->samples; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { for (k = 0; k < n + a; k++) { v = jpx->comps[k].data[y * w + x]; if (sgnd) v = v + (1 << (depth - 1)); if (depth > 8) v = v >> (depth - 8); *p++ = v; } if (!a) *p++ = 255; } } opj_image_destroy(jpx); if (a) { if (n == 4) { fz_pixmap *tmp = fz_new_pixmap(ctx, fz_device_rgb(ctx), w, h); fz_convert_pixmap(ctx, tmp, img); fz_drop_pixmap(ctx, img); img = tmp; } fz_premultiply_pixmap(ctx, img); } if (origcs != defcs) { fz_pixmap *tmp = fz_new_pixmap(ctx, origcs, w, h); fz_convert_pixmap(ctx, tmp, img); fz_drop_pixmap(ctx, img); img = tmp; } return img; }