static fz_pixmap * pnm_read_image(fz_context *ctx, struct info *pnm, unsigned char *p, size_t total, int onlymeta) { unsigned char *e = p + total; char signature[3] = { 0 }; p = pnm_read_signature(ctx, p, e, signature); p = pnm_read_white(ctx, p, e, 0); if (!strcmp(signature, "P1")) { if (!onlymeta) pnm->cs = fz_device_gray(ctx); return pnm_ascii_read_image(ctx, pnm, p, e, onlymeta, 1); } else if (!strcmp(signature, "P2")) { if (!onlymeta) pnm->cs = fz_device_gray(ctx); return pnm_ascii_read_image(ctx, pnm, p, e, onlymeta, 0); } else if (!strcmp(signature, "P3")) { if (!onlymeta) pnm->cs = fz_device_rgb(ctx); return pnm_ascii_read_image(ctx, pnm, p, e, onlymeta, 0); } else if (!strcmp(signature, "P4")) { if (!onlymeta) pnm->cs = fz_device_gray(ctx); return pnm_binary_read_image(ctx, pnm, p, e, onlymeta, 1); } else if (!strcmp(signature, "P5")) { if (!onlymeta) pnm->cs = fz_device_gray(ctx); return pnm_binary_read_image(ctx, pnm, p, e, onlymeta, 0); } else if (!strcmp(signature, "P6")) { if (!onlymeta) pnm->cs = fz_device_rgb(ctx); return pnm_binary_read_image(ctx, pnm, p, e, onlymeta, 0); } else if (!strcmp(signature, "P7")) return pam_binary_read_image(ctx, pnm, p, e, onlymeta); else fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported portable anymap signature (0x%02x, 0x%02x)", signature[0], signature[1]); }
static void fz_test_color(fz_context *ctx, fz_device *dev, fz_colorspace *colorspace, const float *color) { fz_test_device *t = (fz_test_device*)dev; if (!*t->is_color && colorspace && colorspace != fz_device_gray(ctx)) { if (colorspace == fz_device_rgb(ctx)) { if (is_rgb_color(t->threshold, color[0], color[1], color[2])) { *t->is_color = 1; dev->hints |= FZ_IGNORE_IMAGE; fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); } } else { float rgb[3]; fz_convert_color(ctx, fz_device_rgb(ctx), rgb, colorspace, color); if (is_rgb_color(t->threshold, rgb[0], rgb[1], rgb[2])) { *t->is_color = 1; dev->hints |= FZ_IGNORE_IMAGE; fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); } } } }
fz_document_writer * fz_new_pixmap_writer(fz_context *ctx, const char *path, const char *options, const char *default_path, int n, void (*save)(fz_context *ctx, fz_pixmap *pix, const char *filename)) { fz_pixmap_writer *wri = fz_new_derived_document_writer(ctx, fz_pixmap_writer, pixmap_begin_page, pixmap_end_page, NULL, pixmap_drop_writer); fz_try(ctx) { fz_parse_draw_options(ctx, &wri->options, options); wri->path = fz_strdup(ctx, path ? path : default_path); wri->save = save; switch (n) { case 1: wri->options.colorspace = fz_device_gray(ctx); break; case 3: wri->options.colorspace = fz_device_rgb(ctx); break; case 4: wri->options.colorspace = fz_device_cmyk(ctx); break; } } fz_catch(ctx) { fz_free(ctx, wri); fz_rethrow(ctx); } return (fz_document_writer*)wri; }
static fz_colorspace * load_icc_based(pdf_document *doc, pdf_obj *dict) { int n; n = pdf_to_int(pdf_dict_gets(dict, "N")); /* SumatraPDF: support alternate colorspaces for ICCBased */ if (pdf_dict_gets(dict, "Alternate")) { fz_colorspace *cs_alt = pdf_load_colorspace(doc, pdf_dict_gets(dict, "Alternate")); if (cs_alt->n != n) { fz_drop_colorspace(doc->ctx, cs_alt); fz_throw(doc->ctx, FZ_ERROR_GENERIC, "ICCBased /Alternate colorspace must have %d components (not %d)", n, cs_alt->n); } return cs_alt; } switch (n) { case 1: return fz_device_gray(doc->ctx); case 3: return fz_device_rgb(doc->ctx); case 4: return fz_device_cmyk(doc->ctx); } fz_throw(doc->ctx, FZ_ERROR_GENERIC, "syntaxerror: ICCBased must have 1, 3 or 4 components"); return NULL; /* Stupid MSVC */ }
static void pdf_filter_g(fz_context *ctx, pdf_processor *proc, float g) { float color[1] = { g }; pdf_filter_cs(ctx, proc, "DeviceGray", fz_device_gray(ctx)); pdf_filter_sc_color(ctx, proc, 1, color); }
static void fz_test_color(fz_device *dev, fz_colorspace *colorspace, const float *color) { fz_context *ctx = dev->ctx; struct test *t = dev->user; if (!*t->is_color && colorspace && colorspace != fz_device_gray(ctx)) { if (colorspace == fz_device_rgb(ctx)) { if (is_rgb_color(t->threshold, color[0], color[1], color[2])) { *t->is_color = 1; dev->hints |= FZ_IGNORE_IMAGE; } } else { float rgb[3]; fz_convert_color(ctx, fz_device_rgb(ctx), rgb, colorspace, color); if (is_rgb_color(t->threshold, rgb[0], rgb[1], rgb[2])) { *t->is_color = 1; dev->hints |= FZ_IGNORE_IMAGE; } } } }
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 fz_colorspace * load_icc_based(pdf_document *xref, pdf_obj *dict) { int n; n = pdf_to_int(pdf_dict_gets(dict, "N")); switch (n) { case 1: return fz_device_gray(xref->ctx); case 3: return fz_device_rgb(xref->ctx); case 4: return fz_device_cmyk(xref->ctx); } fz_throw(xref->ctx, "syntaxerror: ICCBased must have 1, 3 or 4 components"); return NULL; /* Stupid MSVC */ }
static fz_colorspace * load_icc_based(pdf_document *doc, pdf_obj *dict) { int n; pdf_obj *obj; fz_context *ctx = doc->ctx; n = pdf_to_int(pdf_dict_gets(dict, "N")); obj = pdf_dict_gets(dict, "Alternate"); if (obj) { fz_colorspace *cs_alt = NULL; fz_try(ctx) { cs_alt = pdf_load_colorspace(doc, obj); if (cs_alt->n != n) { fz_drop_colorspace(ctx, cs_alt); fz_throw(ctx, FZ_ERROR_GENERIC, "ICCBased /Alternate colorspace must have %d components", n); } } fz_catch(ctx) { cs_alt = NULL; } if (cs_alt) return cs_alt; } switch (n) { case 1: return fz_device_gray(ctx); case 3: return fz_device_rgb(ctx); case 4: return fz_device_cmyk(ctx); } fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: ICCBased must have 1, 3 or 4 components"); }
void xps_parse_color(fz_context *ctx, xps_document *doc, char *base_uri, char *string, fz_colorspace **csp, float *samples) { char *p; int i, n; char buf[1024]; char *profile; *csp = fz_device_rgb(ctx); samples[0] = 1; samples[1] = 0; samples[2] = 0; samples[3] = 0; if (string[0] == '#') { if (strlen(string) == 9) { samples[0] = unhex(string[1]) * 16 + unhex(string[2]); samples[1] = unhex(string[3]) * 16 + unhex(string[4]); samples[2] = unhex(string[5]) * 16 + unhex(string[6]); samples[3] = unhex(string[7]) * 16 + unhex(string[8]); } else { samples[0] = 255; samples[1] = unhex(string[1]) * 16 + unhex(string[2]); samples[2] = unhex(string[3]) * 16 + unhex(string[4]); samples[3] = unhex(string[5]) * 16 + unhex(string[6]); } samples[0] /= 255; samples[1] /= 255; samples[2] /= 255; samples[3] /= 255; } else if (string[0] == 's' && string[1] == 'c' && string[2] == '#') { if (count_commas(string) == 2) sscanf(string, "sc#%g,%g,%g", samples + 1, samples + 2, samples + 3); if (count_commas(string) == 3) sscanf(string, "sc#%g,%g,%g,%g", samples, samples + 1, samples + 2, samples + 3); } else if (strstr(string, "ContextColor ") == string) { /* Crack the string for profile name and sample values */ fz_strlcpy(buf, string, sizeof buf); profile = strchr(buf, ' '); if (!profile) { fz_warn(ctx, "cannot find icc profile uri in '%s'", string); return; } *profile++ = 0; p = strchr(profile, ' '); if (!p) { fz_warn(ctx, "cannot find component values in '%s'", profile); return; } *p++ = 0; n = count_commas(p) + 1; if (n > FZ_MAX_COLORS) { fz_warn(ctx, "ignoring %d color components (max %d allowed)", n - FZ_MAX_COLORS, FZ_MAX_COLORS); n = FZ_MAX_COLORS; } i = 0; while (i < n) { samples[i++] = fz_atof(p); p = strchr(p, ','); if (!p) break; p ++; if (*p == ' ') p ++; } while (i < n) { samples[i++] = 0; } /* TODO: load ICC profile */ switch (n) { case 2: *csp = fz_device_gray(ctx); break; case 4: *csp = fz_device_rgb(ctx); break; case 5: *csp = fz_device_cmyk(ctx); break; default: *csp = fz_device_gray(ctx); break; } } }
static void fz_test_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha) { fz_test_device *t = (fz_test_device*)dev; fz_pixmap *pix; unsigned int count, i, k; unsigned char *s; if (*t->is_color || !image->colorspace || image->colorspace == fz_device_gray(ctx)) return; if (image->buffer && image->bpc == 8) { fz_stream *stream = fz_open_compressed_buffer(ctx, image->buffer); count = (unsigned int)image->w * (unsigned int)image->h; if (image->colorspace == fz_device_rgb(ctx)) { int threshold_u8 = t->threshold * 255; for (i = 0; i < count; i++) { int r = fz_read_byte(ctx, stream); int g = fz_read_byte(ctx, stream); int b = fz_read_byte(ctx, stream); if (is_rgb_color_u8(threshold_u8, r, g, b)) { *t->is_color = 1; dev->hints |= FZ_IGNORE_IMAGE; fz_drop_stream(ctx, stream); fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); break; } } } else { fz_color_converter cc; unsigned int n = (unsigned int)image->n; fz_init_cached_color_converter(ctx, &cc, fz_device_rgb(ctx), image->colorspace); for (i = 0; i < count; i++) { float cs[FZ_MAX_COLORS]; float ds[FZ_MAX_COLORS]; for (k = 0; k < n; k++) cs[k] = fz_read_byte(ctx, stream) / 255.0f; cc.convert(ctx, &cc, ds, cs); if (is_rgb_color(t->threshold, ds[0], ds[1], ds[2])) { *t->is_color = 1; dev->hints |= FZ_IGNORE_IMAGE; break; } } fz_fin_cached_color_converter(ctx, &cc); } fz_drop_stream(ctx, stream); return; } pix = fz_new_pixmap_from_image(ctx, image, 0, 0); if (pix == NULL) /* Should never happen really, but... */ return; count = (unsigned int)pix->w * (unsigned int)pix->h; s = pix->samples; if (pix->colorspace == fz_device_rgb(ctx)) { int threshold_u8 = t->threshold * 255; for (i = 0; i < count; i++) { if (s[3] != 0 && is_rgb_color_u8(threshold_u8, s[0], s[1], s[2])) { *t->is_color = 1; dev->hints |= FZ_IGNORE_IMAGE; fz_drop_pixmap(ctx, pix); fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); break; } s += 4; } } else { fz_color_converter cc; unsigned int n = (unsigned int)pix->n-1; fz_init_cached_color_converter(ctx, &cc, fz_device_rgb(ctx), pix->colorspace); for (i = 0; i < count; i++) { float cs[FZ_MAX_COLORS]; float ds[FZ_MAX_COLORS]; for (k = 0; k < n; k++) cs[k] = (*s++) / 255.0f; if (*s++ == 0) continue; cc.convert(ctx, &cc, ds, cs); if (is_rgb_color(t->threshold, ds[0], ds[1], ds[2])) { *t->is_color = 1; dev->hints |= FZ_IGNORE_IMAGE; fz_drop_pixmap(ctx, pix); fz_throw(ctx, FZ_ERROR_ABORT, "Page found as color; stopping interpretation"); break; } } fz_fin_cached_color_converter(ctx, &cc); } fz_drop_pixmap(ctx, pix); }
int bmpmupdf_pdffile_to_bmp(WILLUSBITMAP *bmp,char *filename,int pageno,double dpi, int bpp) { fz_context *ctx; fz_colorspace *colorspace; fz_document *doc; fz_page *page; fz_display_list *list; fz_device *dev; fz_pixmap *pix; double dpp; fz_rect bounds,bounds2; fz_matrix ctm; fz_irect bbox; // fz_glyph_cache *glyphcache; // fz_error error; int np,status; dev=NULL; list=NULL; page=NULL; doc=NULL; status=0; if (pageno<1) return(-99); ctx = fz_new_context(NULL,NULL,FZ_STORE_DEFAULT); if (!ctx) return(-1); fz_try(ctx) { fz_register_document_handlers(ctx); fz_set_aa_level(ctx,8); /* Sumatra version of MuPDF v1.4 -- use locally installed fonts */ pdf_install_load_system_font_funcs(ctx); // fz_accelerate(); // glyphcache=fz_new_glyph_cache(); colorspace=(bpp==8 ? fz_device_gray(ctx) : fz_device_rgb(ctx)); fz_try(ctx) { doc=fz_open_document(ctx,filename); } fz_catch(ctx) { fz_free_context(ctx); return(-1); } /* if (fz_needs_password(doc) && !fz_authenticate_password(doc,password)) return(-2); */ // error=pdf_load_page_tree(xref); // if (error) // { // pdf_free_xref(xref); // return(-2); // } np=fz_count_pages(doc); if (pageno>np) return(-99); fz_try(ctx) { page = fz_load_page(doc,pageno-1); } fz_catch(ctx) { fz_close_document(doc); fz_free_context(ctx); return(-3); } fz_try(ctx) { list=fz_new_display_list(ctx); dev=fz_new_list_device(ctx,list); fz_run_page(doc,page,dev,&fz_identity,NULL); } fz_catch(ctx) { fz_free_device(dev); fz_drop_display_list(ctx,list); fz_free_page(doc,page); fz_close_document(doc); fz_free_context(ctx); return(-4); } fz_free_device(dev); dev=NULL; dpp=dpi/72.; pix=NULL; fz_var(pix); fz_bound_page(doc,page,&bounds); ctm=fz_identity; fz_scale(&ctm,dpp,dpp); // ctm=fz_concat(ctm,fz_rotate(rotation)); bounds2=bounds; fz_transform_rect(&bounds2,&ctm); fz_round_rect(&bbox,&bounds2); // ctm=fz_translate(0,-page->mediabox.y1); // ctm=fz_concat(ctm,fz_scale(dpp,-dpp)); // ctm=fz_concat(ctm,fz_rotate(page->rotate)); // ctm=fz_concat(ctm,fz_rotate(0)); // bbox=fz_round_rect(fz_transform_rect(ctm,page->mediabox)); // pix=fz_new_pixmap_with_rect(colorspace,bbox); fz_try(ctx) { pix=fz_new_pixmap_with_bbox(ctx,colorspace,&bbox); fz_clear_pixmap_with_value(ctx,pix,255); dev=fz_new_draw_device(ctx,pix); if (list) fz_run_display_list(list,dev,&ctm,&bounds2,NULL); else fz_run_page(doc,page,dev,&ctm,NULL); fz_free_device(dev); dev=NULL; status=bmpmupdf_pixmap_to_bmp(bmp,ctx,pix); fz_drop_pixmap(ctx,pix); } fz_catch(ctx) { fz_free_device(dev); fz_drop_pixmap(ctx,pix); fz_drop_display_list(ctx,list); fz_free_page(doc,page); fz_close_document(doc); fz_free_context(ctx); return(-5); } if (list) fz_drop_display_list(ctx,list); fz_free_page(doc,page); // pdf_free_xref(xref); fz_close_document(doc); fz_flush_warnings(ctx); } /* fz_catch before registering handlers */ fz_catch(ctx) /* Error registering */ { status = -10; } fz_free_context(ctx); // fz_free_glyph_cache(glyphcache); // fz_flush_warnings(); if (status<0) return(status-10); return(0); }
static fz_image *render_to_pixmap(fz_context *ctx, HBITMAP hbmp, SizeI size) { int w = size.dx, h = size.dy; int stride = ((w * 3 + 3) / 4) * 4; unsigned char *data = (unsigned char *)fz_malloc(ctx, stride * h); BITMAPINFO bmi = { 0 }; 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; HDC hDC = GetDC(nullptr); int res = GetDIBits(hDC, hbmp, 0, h, data, &bmi, DIB_RGB_COLORS); ReleaseDC(nullptr, hDC); if (!res) { fz_free(ctx, data); fz_throw(ctx, FZ_ERROR_GENERIC, "GetDIBits failed"); } // convert BGR with padding to RGB without padding unsigned char *out = data; bool is_grayscale = true; for (int y = 0; y < h; y++) { const unsigned char *in = data + y * stride; unsigned char green, blue; for (int x = 0; x < w; x++) { is_grayscale = is_grayscale && in[0] == in[1] && in[0] == in[2]; blue = *in++; green = *in++; *out++ = *in++; *out++ = green; *out++ = blue; } } // convert grayscale RGB to proper grayscale if (is_grayscale) { const unsigned char *in = out = data; for (int i = 0; i < w * h; i++) { *out++ = *in++; in += 2; } } fz_compressed_buffer *buf = nullptr; fz_var(buf); fz_try(ctx) { buf = fz_malloc_struct(ctx, fz_compressed_buffer); buf->buffer = fz_new_buffer(ctx, w * h * 4 + 10); buf->params.type = FZ_IMAGE_FLATE; buf->params.u.flate.predictor = 1; z_stream zstm = { 0 }; zstm.next_in = data; zstm.avail_in = out - data; zstm.next_out = buf->buffer->data; zstm.avail_out = buf->buffer->cap; res = deflateInit(&zstm, 9); if (res != Z_OK) fz_throw(ctx, FZ_ERROR_GENERIC, "deflate failure %d", res); res = deflate(&zstm, Z_FINISH); if (res != Z_STREAM_END) fz_throw(ctx, FZ_ERROR_GENERIC, "deflate failure %d", res); buf->buffer->len = zstm.total_out; res = deflateEnd(&zstm); if (res != Z_OK) fz_throw(ctx, FZ_ERROR_GENERIC, "deflate failure %d", res); } fz_always(ctx) { fz_free(ctx, data); } fz_catch(ctx) { fz_free_compressed_buffer(ctx, buf); fz_rethrow(ctx); } fz_colorspace *cs = is_grayscale ? fz_device_gray(ctx) : fz_device_rgb(ctx); return fz_new_image(ctx, w, h, 8, cs, 96, 96, 0, 0, nullptr, nullptr, buf, nullptr); }
static void pdf_dev_color(fz_context *ctx, pdf_device *pdev, fz_colorspace *colorspace, const float *color, int stroke, const fz_color_params *color_params) { int diff = 0; int i; int cspace = 0; float rgb[FZ_MAX_COLORS]; gstate *gs = CURRENT_GSTATE(pdev); if (colorspace == fz_device_gray(ctx)) cspace = 1; else if (colorspace == fz_device_rgb(ctx)) cspace = 3; else if (colorspace == fz_device_cmyk(ctx)) cspace = 4; if (cspace == 0) { /* If it's an unknown colorspace, fallback to rgb */ fz_convert_color(ctx, color_params, NULL, fz_device_rgb(ctx), rgb, colorspace, color); color = rgb; colorspace = fz_device_rgb(ctx); cspace = 3; } if (gs->colorspace[stroke] != colorspace) { gs->colorspace[stroke] = colorspace; diff = 1; } for (i=0; i < cspace; i++) if (gs->color[stroke][i] != color[i]) { gs->color[stroke][i] = color[i]; diff = 1; } if (diff == 0) return; switch (cspace + stroke*8) { case 1: fz_append_printf(ctx, gs->buf, "%g g\n", color[0]); break; case 3: fz_append_printf(ctx, gs->buf, "%g %g %g rg\n", color[0], color[1], color[2]); break; case 4: fz_append_printf(ctx, gs->buf, "%g %g %g %g k\n", color[0], color[1], color[2], color[3]); break; case 1+8: fz_append_printf(ctx, gs->buf, "%g G\n", color[0]); break; case 3+8: fz_append_printf(ctx, gs->buf, "%g %g %g RG\n", color[0], color[1], color[2]); break; case 4+8: fz_append_printf(ctx, gs->buf, "%g %g %g %g K\n", color[0], color[1], color[2], color[3]); break; } }
static void jxr_read_image(fz_context *ctx, unsigned char *data, int size, struct info *info, int only_metadata) { jxr_container_t container; jxr_image_t image = NULL; jxr_image_t alpha = NULL; int rc, i; fz_try(ctx) { container = jxr_create_container(); rc = jxr_read_image_container_memory(container, data, size); if (rc < 0) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot read jxr image container: %s", jxr_error_string(rc)); info->xres = jxrc_width_resolution(container, 0); info->yres = jxrc_height_resolution(container, 0); info->width = jxrc_image_width(container, 0); info->height = jxrc_image_height(container, 0); info->format = jxrc_image_pixelformat(container, 0); for (i = 0; i < nelem(pixelformats); i++) if (pixelformats[i].format == info->format) { info->comps = pixelformats[i].comps; break; } if (i == nelem(pixelformats)) fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported pixel format: %u", info->format); if (info->comps == 1) info->cspace = fz_device_gray(ctx); else if (info->comps == 3) info->cspace = fz_device_rgb(ctx); else if (info->comps >= 4) info->cspace = fz_device_cmyk(ctx); info->stride = info->width * (fz_colorspace_n(ctx, info->cspace) + 1); if (!only_metadata) { unsigned long image_offset; unsigned char image_band; unsigned long alpha_offset; unsigned char alpha_band; info->ctx = ctx; info->samples = fz_malloc(ctx, info->stride * info->height); memset(info->samples, 0xff, info->stride * info->height); image_offset = jxrc_image_offset(container, 0); image_band = jxrc_image_band_presence(container, 0); alpha_offset = jxrc_alpha_offset(container, 0); alpha_band = jxrc_alpha_band_presence(container, 0); image = jxr_create_input(); jxr_set_PROFILE_IDC(image, 111); jxr_set_LEVEL_IDC(image, 255); jxr_set_pixel_format(image, info->format); jxr_set_container_parameters(image, info->format, info->width, info->height, alpha_offset, image_band, alpha_band, 0); jxr_set_user_data(image, info); jxr_set_block_output(image, jxr_decode_block); rc = jxr_read_image_bitstream_memory(image, data + image_offset, size - image_offset); if (rc < 0) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot read jxr image: %s", jxr_error_string(rc)); if (info->format == JXRC_FMT_32bppPBGRA || info->format == JXRC_FMT_64bppPRGBA || info->format == JXRC_FMT_128bppPRGBAFloat) info->has_premul = 1; if (jxr_get_ALPHACHANNEL_FLAG(image)) info->has_alpha = 1; if (alpha_offset > 0) { info->has_alpha = 1; alpha = jxr_create_input(); jxr_set_PROFILE_IDC(alpha, 111); jxr_set_LEVEL_IDC(alpha, 255); jxr_set_pixel_format(alpha, info->format); jxr_set_container_parameters(alpha, info->format, info->width, info->height, alpha_offset, image_band, alpha_band, 1); jxr_set_user_data(alpha, info); jxr_set_block_output(alpha, jxr_decode_block_alpha); rc = jxr_read_image_bitstream_memory(alpha, data + alpha_offset, size - alpha_offset); if (rc < 0) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot read jxr image: %s", jxr_error_string(rc)); } } } fz_always(ctx) { if (alpha) jxr_destroy(alpha); if (image) jxr_destroy(image); jxr_destroy_container(container); } fz_catch(ctx) { fz_rethrow(ctx); } }
static fz_image * pdf_load_image_imp(pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask) { fz_stream *stm = NULL; fz_image *image = NULL; pdf_obj *obj, *res; int w, h, bpc, n; int imagemask; int interpolate; int indexed; fz_image *mask = NULL; /* explicit mask/soft mask image */ int usecolorkey = 0; fz_colorspace *colorspace = NULL; float decode[FZ_MAX_COLORS * 2]; int colorkey[FZ_MAX_COLORS * 2]; int stride; int i; fz_context *ctx = doc->ctx; fz_compressed_buffer *buffer; fz_var(stm); fz_var(mask); fz_var(image); fz_var(colorspace); fz_try(ctx) { /* special case for JPEG2000 images */ if (pdf_is_jpx_image(ctx, dict)) { image = pdf_load_jpx(doc, dict, forcemask); if (forcemask) { fz_pixmap *mask_pixmap; if (image->n != 2) { fz_pixmap *gray; fz_irect bbox; fz_warn(ctx, "soft mask should be grayscale"); gray = fz_new_pixmap_with_bbox(ctx, fz_device_gray(ctx), fz_pixmap_bbox(ctx, image->tile, &bbox)); /* SumatraPDF: ignore invalid JPX softmasks */ fz_clear_pixmap_with_value(ctx, gray, 255); fz_drop_pixmap(ctx, image->tile); image->tile = gray; } mask_pixmap = fz_alpha_from_gray(ctx, image->tile, 1); fz_drop_pixmap(ctx, image->tile); image->tile = mask_pixmap; } break; /* Out of fz_try */ } w = pdf_to_int(pdf_dict_getsa(dict, "Width", "W")); h = pdf_to_int(pdf_dict_getsa(dict, "Height", "H")); bpc = pdf_to_int(pdf_dict_getsa(dict, "BitsPerComponent", "BPC")); if (bpc == 0) bpc = 8; imagemask = pdf_to_bool(pdf_dict_getsa(dict, "ImageMask", "IM")); interpolate = pdf_to_bool(pdf_dict_getsa(dict, "Interpolate", "I")); indexed = 0; usecolorkey = 0; if (imagemask) bpc = 1; if (w <= 0) fz_throw(ctx, FZ_ERROR_GENERIC, "image width is zero (or less)"); if (h <= 0) fz_throw(ctx, FZ_ERROR_GENERIC, "image height is zero (or less)"); if (bpc <= 0) fz_throw(ctx, FZ_ERROR_GENERIC, "image depth is zero (or less)"); if (bpc > 16) fz_throw(ctx, FZ_ERROR_GENERIC, "image depth is too large: %d", bpc); if (w > (1 << 16)) fz_throw(ctx, FZ_ERROR_GENERIC, "image is too wide"); if (h > (1 << 16)) fz_throw(ctx, FZ_ERROR_GENERIC, "image is too high"); obj = pdf_dict_getsa(dict, "ColorSpace", "CS"); if (obj && !imagemask && !forcemask) { /* colorspace resource lookup is only done for inline images */ if (pdf_is_name(obj)) { res = pdf_dict_get(pdf_dict_gets(rdb, "ColorSpace"), obj); if (res) obj = res; } colorspace = pdf_load_colorspace(doc, obj); indexed = fz_colorspace_is_indexed(colorspace); n = colorspace->n; } else { n = 1; } obj = pdf_dict_getsa(dict, "Decode", "D"); if (obj) { for (i = 0; i < n * 2; i++) decode[i] = pdf_to_real(pdf_array_get(obj, i)); } else { float maxval = indexed ? (1 << bpc) - 1 : 1; for (i = 0; i < n * 2; i++) decode[i] = i & 1 ? maxval : 0; } obj = pdf_dict_getsa(dict, "SMask", "Mask"); if (pdf_is_dict(obj)) { /* Not allowed for inline images or soft masks */ if (cstm) fz_warn(ctx, "Ignoring invalid inline image soft mask"); else if (forcemask) fz_warn(ctx, "Ignoring recursive image soft mask"); else { mask = pdf_load_image_imp(doc, rdb, obj, NULL, 1); obj = pdf_dict_gets(obj, "Matte"); if (pdf_is_array(obj)) { usecolorkey = 1; for (i = 0; i < n; i++) colorkey[i] = pdf_to_real(pdf_array_get(obj, i)) * 255; } } } else if (pdf_is_array(obj)) { usecolorkey = 1; for (i = 0; i < n * 2; i++) { if (!pdf_is_int(pdf_array_get(obj, i))) { fz_warn(ctx, "invalid value in color key mask"); usecolorkey = 0; } colorkey[i] = pdf_to_int(pdf_array_get(obj, i)); } } /* Do we load from a ref, or do we load an inline stream? */ if (cstm == NULL) { /* Just load the compressed image data now and we can * decode it on demand. */ int num = pdf_to_num(dict); int gen = pdf_to_gen(dict); buffer = pdf_load_compressed_stream(doc, num, gen); image = fz_new_image(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, usecolorkey ? colorkey : NULL, buffer, mask); } else { /* Inline stream */ stride = (w * n * bpc + 7) / 8; image = fz_new_image(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, usecolorkey ? colorkey : NULL, NULL, mask); pdf_load_compressed_inline_image(doc, dict, stride * h, cstm, indexed, image); } } fz_catch(ctx) { fz_drop_colorspace(ctx, colorspace); fz_drop_image(ctx, mask); fz_drop_image(ctx, image); fz_rethrow(ctx); } return image; }
static fz_pixmap * pam_binary_read_image(fz_context *ctx, struct info *pnm, const unsigned char *p, const unsigned char *e, int onlymeta, const unsigned char **out) { fz_pixmap *img = NULL; int bitmap = 0; int minval = 1; int maxval = 65535; fz_var(img); p = pam_binary_read_header(ctx, pnm, p, e); if (pnm->tupletype == PAM_UNKNOWN) switch (pnm->depth) { case 1: pnm->tupletype = pnm->maxval == 1 ? PAM_BW : PAM_GRAY; break; case 2: pnm->tupletype = pnm->maxval == 1 ? PAM_BWA : PAM_GRAYA; break; case 3: pnm->tupletype = PAM_RGB; break; case 4: pnm->tupletype = PAM_CMYK; break; case 5: pnm->tupletype = PAM_CMYKA; break; default: fz_throw(ctx, FZ_ERROR_GENERIC, "cannot guess tuple type based on depth in pnm image"); } if (pnm->tupletype == PAM_BW && pnm->maxval > 1) pnm->tupletype = PAM_GRAY; else if (pnm->tupletype == PAM_GRAY && pnm->maxval == 1) pnm->tupletype = PAM_BW; else if (pnm->tupletype == PAM_BWA && pnm->maxval > 1) pnm->tupletype = PAM_GRAYA; else if (pnm->tupletype == PAM_GRAYA && pnm->maxval == 1) pnm->tupletype = PAM_BWA; switch (pnm->tupletype) { case PAM_BWA: pnm->alpha = 1; /* fallthrough */ case PAM_BW: pnm->cs = fz_device_gray(ctx); maxval = 1; bitmap = 1; break; case PAM_GRAYA: pnm->alpha = 1; /* fallthrough */ case PAM_GRAY: pnm->cs = fz_device_gray(ctx); minval = 2; break; case PAM_RGBA: pnm->alpha = 1; /* fallthrough */ case PAM_RGB: pnm->cs = fz_device_rgb(ctx); break; case PAM_CMYKA: pnm->alpha = 1; /* fallthrough */ case PAM_CMYK: pnm->cs = fz_device_cmyk(ctx); break; default: fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported tuple type"); } if (pnm->depth != fz_colorspace_n(ctx, pnm->cs) + pnm->alpha) fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of tuple type range"); if (pnm->maxval < minval || pnm->maxval > maxval) fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range"); pnm->bitdepth = bitdepth_from_maxval(pnm->maxval); if (pnm->height <= 0) fz_throw(ctx, FZ_ERROR_GENERIC, "image height must be > 0"); if (pnm->width <= 0) fz_throw(ctx, FZ_ERROR_GENERIC, "image width must be > 0"); if ((unsigned int)pnm->height > UINT_MAX / pnm->width / fz_colorspace_n(ctx, pnm->cs) / (pnm->bitdepth / 8 + 1)) fz_throw(ctx, FZ_ERROR_GENERIC, "image too large"); if (onlymeta) { int packed; int w, h, n; w = pnm->width; h = pnm->height; n = fz_colorspace_n(ctx, pnm->cs) + pnm->alpha; /* some encoders incorrectly pack bits into bytes and invert the image */ packed = 0; if (pnm->maxval == 1) { const unsigned char *e_packed = p + w * h * n / 8; if (e_packed < e - 1 && e_packed[0] == 'P' && e_packed[1] >= '0' && e_packed[1] <= '7') e = e_packed; if (e - p < w * h * n) packed = 1; } if (packed && e - p < w * h * n / 8) fz_throw(ctx, FZ_ERROR_GENERIC, "truncated packed image"); if (!packed && e - p < w * h * n * (pnm->maxval < 256 ? 1 : 2)) fz_throw(ctx, FZ_ERROR_GENERIC, "truncated image"); if (pnm->maxval == 255) p += n * w * h; else if (bitmap && packed) p += ((w + 7) / 8) * h; else if (bitmap) p += n * w * h; else if (pnm->maxval < 255) p += n * w * h; else p += 2 * n * w * h; } if (!onlymeta) { unsigned char *dp; int x, y, k, packed; int w, h, n; img = fz_new_pixmap(ctx, pnm->cs, pnm->width, pnm->height, NULL, pnm->alpha); fz_try(ctx) { dp = img->samples; w = img->w; h = img->h; n = img->n; /* some encoders incorrectly pack bits into bytes and invert the image */ packed = 0; if (pnm->maxval == 1) { const unsigned char *e_packed = p + w * h * n / 8; if (e_packed < e - 1 && e_packed[0] == 'P' && e_packed[1] >= '0' && e_packed[1] <= '7') e = e_packed; if (e - p < w * h * n) packed = 1; } if (packed && e - p < w * h * n / 8) fz_throw(ctx, FZ_ERROR_GENERIC, "truncated packed image"); if (!packed && e - p < w * h * n * (pnm->maxval < 256 ? 1 : 2)) fz_throw(ctx, FZ_ERROR_GENERIC, "truncated image"); if (pnm->maxval == 255) memcpy(dp, p, w * h * n); else if (bitmap && packed) { for (y = 0; y < h; y++) for (x = 0; x < w; x++) { for (k = 0; k < n; k++) { *dp++ = (*p & (1 << (7 - (x & 0x7)))) ? 0x00 : 0xff; if ((x & 0x7) == 7) p++; } if (w & 0x7) p++; } } else if (bitmap) { for (y = 0; y < h; y++) for (x = 0; x < w; x++) for (k = 0; k < n; k++) *dp++ = *p++ ? 0xff : 0x00; } else if (pnm->maxval < 255) { for (y = 0; y < h; y++) for (x = 0; x < w; x++) for (k = 0; k < n; k++) *dp++ = map_color(ctx, *p++, pnm->maxval, 255); } else { for (y = 0; y < h; y++) for (x = 0; x < w; x++) for (k = 0; k < n; k++) { *dp++ = map_color(ctx, (p[0] << 8) | p[1], pnm->maxval, 255); p += 2; } } if (pnm->alpha) fz_premultiply_pixmap(ctx, img); } fz_catch(ctx) { fz_drop_pixmap(ctx, img); fz_rethrow(ctx); } }
static void pdf_dev_color(fz_context *ctx, pdf_device *pdev, fz_colorspace *colorspace, const float *color, int stroke) { int diff = 0; int i; int cspace = 0; float rgb[FZ_MAX_COLORS]; gstate *gs = CURRENT_GSTATE(pdev); if (colorspace == fz_device_gray(ctx)) cspace = 1; else if (colorspace == fz_device_rgb(ctx)) cspace = 3; else if (colorspace == fz_device_cmyk(ctx)) cspace = 4; if (cspace == 0) { /* If it's an unknown colorspace, fallback to rgb */ colorspace->to_rgb(ctx, colorspace, color, rgb); color = rgb; colorspace = fz_device_rgb(ctx); } if (gs->colorspace[stroke] != colorspace) { gs->colorspace[stroke] = colorspace; diff = 1; } for (i=0; i < colorspace->n; i++) if (gs->color[stroke][i] != color[i]) { gs->color[stroke][i] = color[i]; diff = 1; } if (diff == 0) return; switch (cspace + stroke*8) { case 1: fz_buffer_printf(ctx, gs->buf, "%f g\n", color[0]); break; case 3: fz_buffer_printf(ctx, gs->buf, "%f %f %f rg\n", color[0], color[1], color[2]); break; case 4: fz_buffer_printf(ctx, gs->buf, "%f %f %f %f k\n", color[0], color[1], color[2], color[3]); break; case 1+8: fz_buffer_printf(ctx, gs->buf, "%f G\n", color[0]); break; case 3+8: fz_buffer_printf(ctx, gs->buf, "%f %f %f RG\n", color[0], color[1], color[2]); break; case 4+8: fz_buffer_printf(ctx, gs->buf, "%f %f %f %f K\n", color[0], color[1], color[2], color[3]); break; } }
void fz_load_jpeg_info(fz_context *ctx, unsigned char *rbuf, int rlen, int *xp, int *yp, int *xresp, int *yresp, fz_colorspace **cspacep) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr err; struct jpeg_source_mgr src; fz_try(ctx) { cinfo.client_data = ctx; cinfo.err = jpeg_std_error(&err); err.error_exit = error_exit; jpeg_create_decompress(&cinfo); cinfo.src = &src; src.init_source = init_source; src.fill_input_buffer = fill_input_buffer; src.skip_input_data = skip_input_data; src.resync_to_restart = jpeg_resync_to_restart; src.term_source = term_source; src.next_input_byte = rbuf; src.bytes_in_buffer = rlen; jpeg_read_header(&cinfo, 1); if (cinfo.num_components == 1) *cspacep = fz_device_gray(ctx); else if (cinfo.num_components == 3) *cspacep = fz_device_rgb(ctx); else if (cinfo.num_components == 4) *cspacep = fz_device_cmyk(ctx); else fz_throw(ctx, "bad number of components in jpeg: %d", cinfo.num_components); *xp = cinfo.image_width; *yp = cinfo.image_height; if (cinfo.density_unit == 1) { *xresp = cinfo.X_density; *yresp = cinfo.Y_density; } else if (cinfo.density_unit == 2) { *xresp = cinfo.X_density * 254 / 100; *yresp = cinfo.Y_density * 254 / 100; } else { *xresp = 0; *yresp = 0; } if (*xresp <= 0) *xresp = 72; if (*yresp <= 0) *yresp = 72; } fz_always(ctx) { jpeg_destroy_decompress(&cinfo); } fz_catch(ctx) { fz_rethrow(ctx); } }
void fz_load_jpeg_info(fz_context *ctx, unsigned char *rbuf, int rlen, int *xp, int *yp, int *xresp, int *yresp, fz_colorspace **cspacep) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr err; struct jpeg_source_mgr src; fz_try(ctx) { cinfo.client_data = ctx; cinfo.err = jpeg_std_error(&err); err.error_exit = error_exit; fz_jpg_mem_init(ctx, &cinfo); jpeg_create_decompress(&cinfo); cinfo.src = &src; src.init_source = init_source; src.fill_input_buffer = fill_input_buffer; src.skip_input_data = skip_input_data; src.resync_to_restart = jpeg_resync_to_restart; src.term_source = term_source; src.next_input_byte = rbuf; src.bytes_in_buffer = rlen; jpeg_save_markers(&cinfo, JPEG_APP0+1, 0xffff); jpeg_save_markers(&cinfo, JPEG_APP0+13, 0xffff); jpeg_read_header(&cinfo, 1); if (cinfo.num_components == 1) *cspacep = fz_device_gray(ctx); else if (cinfo.num_components == 3) *cspacep = fz_device_rgb(ctx); else if (cinfo.num_components == 4) *cspacep = fz_device_cmyk(ctx); else fz_throw(ctx, FZ_ERROR_GENERIC, "bad number of components in jpeg: %d", cinfo.num_components); *xp = cinfo.image_width; *yp = cinfo.image_height; if (extract_exif_resolution(cinfo.marker_list, xresp, yresp)) /* XPS prefers EXIF resolution to JFIF density */; else if (extract_app13_resolution(cinfo.marker_list, xresp, yresp)) /* XPS prefers APP13 resolution to JFIF density */; else if (cinfo.density_unit == 1) { *xresp = cinfo.X_density; *yresp = cinfo.Y_density; } else if (cinfo.density_unit == 2) { *xresp = cinfo.X_density * 254 / 100; *yresp = cinfo.Y_density * 254 / 100; } else { *xresp = 0; *yresp = 0; } if (*xresp <= 0) *xresp = 96; if (*yresp <= 0) *yresp = 96; } fz_always(ctx) { jpeg_destroy_decompress(&cinfo); fz_jpg_mem_term(&cinfo); } fz_catch(ctx) { fz_rethrow(ctx); } }
static void filter_flush(fz_context *ctx, pdf_filter_processor *p, int flush) { filter_gstate *gstate = gstate_to_update(ctx, p); int i; if (gstate->pushed == 0) { gstate->pushed = 1; if (p->chain->op_q) p->chain->op_q(ctx, p->chain); } if (flush & FLUSH_CTM) { if (gstate->ctm.a != 1 || gstate->ctm.b != 0 || gstate->ctm.c != 0 || gstate->ctm.d != 1 || gstate->ctm.e != 0 || gstate->ctm.f != 0) { fz_matrix current = gstate->current_ctm; if (p->chain->op_cm) p->chain->op_cm(ctx, p->chain, gstate->ctm.a, gstate->ctm.b, gstate->ctm.c, gstate->ctm.d, gstate->ctm.e, gstate->ctm.f); fz_concat(&gstate->current_ctm, ¤t, &gstate->ctm); gstate->ctm.a = 1; gstate->ctm.b = 0; gstate->ctm.c = 0; gstate->ctm.d = 1; gstate->ctm.e = 0; gstate->ctm.f = 0; } } if (flush & FLUSH_COLOR_F) { if (gstate->cs.cs == fz_device_gray(ctx) && !gstate->sc.pat && !gstate->sc.shd && gstate->sc.n == 1) { if (p->chain->op_g) p->chain->op_g(ctx, p->chain, gstate->sc.c[0]); goto done_sc; } if (gstate->cs.cs == fz_device_rgb(ctx) && !gstate->sc.pat && !gstate->sc.shd && gstate->sc.n == 3) { if (p->chain->op_rg) p->chain->op_rg(ctx, p->chain, gstate->sc.c[0], gstate->sc.c[1], gstate->sc.c[2]); goto done_sc; } if (gstate->cs.cs == fz_device_cmyk(ctx) && !gstate->sc.pat && !gstate->sc.shd && gstate->sc.n == 4) { if (p->chain->op_k) p->chain->op_k(ctx, p->chain, gstate->sc.c[0], gstate->sc.c[1], gstate->sc.c[2], gstate->sc.c[3]); goto done_sc; } if (strcmp(gstate->cs.name, gstate->current_cs.name)) { if (p->chain->op_cs) p->chain->op_cs(ctx, p->chain, gstate->cs.name, gstate->cs.cs); } /* pattern or shading */ if (gstate->sc.name[0]) { int emit = 0; if (strcmp(gstate->sc.name, gstate->current_sc.name)) emit = 1; if (gstate->sc.n != gstate->current_sc.n) emit = 1; else for (i = 0; i < gstate->sc.n; ++i) if (gstate->sc.c[i] != gstate->current_sc.c[i]) emit = 1; if (emit) { if (gstate->sc.pat) if (p->chain->op_sc_pattern) p->chain->op_sc_pattern(ctx, p->chain, gstate->sc.name, gstate->sc.pat, gstate->sc.n, gstate->sc.c); if (gstate->sc.shd) if (p->chain->op_sc_shade) p->chain->op_sc_shade(ctx, p->chain, gstate->sc.name, gstate->sc.shd); } } /* plain color */ else { int emit = 0; if (gstate->sc.n != gstate->current_sc.n) emit = 1; else for (i = 0; i < gstate->sc.n; ++i) if (gstate->sc.c[i] != gstate->current_sc.c[i]) emit = 1; if (emit) { if (p->chain->op_sc_color) p->chain->op_sc_color(ctx, p->chain, gstate->sc.n, gstate->sc.c); } } done_sc: gstate->current_cs = gstate->cs; gstate->current_sc = gstate->sc; } if (flush & FLUSH_COLOR_S) { if (gstate->CS.cs == fz_device_gray(ctx) && !gstate->SC.pat && !gstate->SC.shd && gstate->SC.n == 1) { if (p->chain->op_G) p->chain->op_G(ctx, p->chain, gstate->SC.c[0]); goto done_SC; } if (gstate->CS.cs == fz_device_rgb(ctx) && !gstate->SC.pat && !gstate->SC.shd && gstate->SC.n == 3) { if (p->chain->op_RG) p->chain->op_RG(ctx, p->chain, gstate->SC.c[0], gstate->SC.c[1], gstate->SC.c[2]); goto done_SC; } if (gstate->CS.cs == fz_device_cmyk(ctx) && !gstate->SC.pat && !gstate->SC.shd && gstate->SC.n == 4) { if (p->chain->op_K) p->chain->op_K(ctx, p->chain, gstate->SC.c[0], gstate->SC.c[1], gstate->SC.c[2], gstate->SC.c[3]); goto done_SC; } if (strcmp(gstate->CS.name, gstate->current_CS.name)) { if (p->chain->op_CS) p->chain->op_CS(ctx, p->chain, gstate->CS.name, gstate->CS.cs); } /* pattern or shading */ if (gstate->SC.name[0]) { int emit = 0; if (strcmp(gstate->SC.name, gstate->current_SC.name)) emit = 1; if (gstate->SC.n != gstate->current_SC.n) emit = 1; else for (i = 0; i < gstate->SC.n; ++i) if (gstate->SC.c[i] != gstate->current_SC.c[i]) emit = 1; if (emit) { if (gstate->SC.pat) if (p->chain->op_SC_pattern) p->chain->op_SC_pattern(ctx, p->chain, gstate->SC.name, gstate->SC.pat, gstate->SC.n, gstate->SC.c); if (gstate->SC.shd) if (p->chain->op_SC_shade) p->chain->op_SC_shade(ctx, p->chain, gstate->SC.name, gstate->SC.shd); } } /* plain color */ else { int emit = 0; if (gstate->SC.n != gstate->current_SC.n) emit = 1; else for (i = 0; i < gstate->SC.n; ++i) if (gstate->SC.c[i] != gstate->current_SC.c[i]) emit = 1; if (emit) { if (p->chain->op_SC_color) p->chain->op_SC_color(ctx, p->chain, gstate->SC.n, gstate->SC.c); } } done_SC: gstate->current_CS = gstate->CS; gstate->current_SC = gstate->SC; } if (flush & FLUSH_STROKE) { if (gstate->stroke.linecap != gstate->current_stroke.linecap) { if (p->chain->op_J) p->chain->op_J(ctx, p->chain, gstate->stroke.linecap); } if (gstate->stroke.linejoin != gstate->current_stroke.linejoin) { if (p->chain->op_j) p->chain->op_j(ctx, p->chain, gstate->stroke.linejoin); } if (gstate->stroke.linewidth != gstate->current_stroke.linewidth) { if (p->chain->op_w) p->chain->op_w(ctx, p->chain, gstate->stroke.linewidth); } if (gstate->stroke.miterlimit != gstate->current_stroke.miterlimit) { if (p->chain->op_M) p->chain->op_M(ctx, p->chain, gstate->stroke.linewidth); } gstate->current_stroke = gstate->stroke; } }
static void pdf_out_BI(fz_context *ctx, pdf_processor *proc, fz_image *img) { fz_output *out = ((pdf_output_processor*)proc)->out; int ahx = ((pdf_output_processor*)proc)->ahxencode; fz_compressed_buffer *cbuf; fz_buffer *buf; int i; if (img == NULL) return; cbuf = fz_compressed_image_buffer(ctx, img); if (cbuf == NULL) return; buf = cbuf->buffer; if (buf == NULL) return; fz_printf(ctx, out, "BI\n"); fz_printf(ctx, out, "/W %d\n", img->w); fz_printf(ctx, out, "/H %d\n", img->h); fz_printf(ctx, out, "/BPC %d\n", img->bpc); if (img->imagemask) fz_printf(ctx, out, "/IM true\n"); else if (img->colorspace == fz_device_gray(ctx)) fz_printf(ctx, out, "/CS/G\n"); else if (img->colorspace == fz_device_rgb(ctx)) fz_printf(ctx, out, "/CS/RGB\n"); else if (img->colorspace == fz_device_cmyk(ctx)) fz_printf(ctx, out, "/CS/CMYK\n"); else if (fz_colorspace_is_indexed(ctx, img->colorspace)) fz_printf(ctx, out, "/CS/I\n"); if (img->interpolate) fz_printf(ctx, out, "/I true\n"); fz_printf(ctx, out, "/D["); for (i = 0; i < img->n * 2; ++i) { if (i > 0) fz_putc(ctx, out, ' '); fz_printf(ctx, out, "%g", img->decode[i]); } fz_printf(ctx, out, "]\n"); switch (cbuf->params.type) { default: fz_throw(ctx, FZ_ERROR_GENERIC, "unknown compressed buffer type"); break; case FZ_IMAGE_JPEG: fz_printf(ctx, out, ahx ? "/F[/AHx/DCT]\n" : "/F/DCT\n"); if (cbuf->params.u.jpeg.color_transform != -1) fz_printf(ctx, out, "/DP<</ColorTransform %d>>\n", cbuf->params.u.jpeg.color_transform); break; case FZ_IMAGE_FAX: fz_printf(ctx, out, ahx ? "/F[/AHx/CCF]\n/DP[null<<\n" : "/F/CCF\n/DP<<\n"); fz_printf(ctx, out, "/K %d\n", cbuf->params.u.fax.k); if (cbuf->params.u.fax.columns != 1728) fz_printf(ctx, out, "/Columns %d\n", cbuf->params.u.fax.columns); if (cbuf->params.u.fax.rows > 0) fz_printf(ctx, out, "/Rows %d\n", cbuf->params.u.fax.rows); if (cbuf->params.u.fax.end_of_line) fz_printf(ctx, out, "/EndOfLine true\n"); if (cbuf->params.u.fax.encoded_byte_align) fz_printf(ctx, out, "/EncodedByteAlign true\n"); if (!cbuf->params.u.fax.end_of_block) fz_printf(ctx, out, "/EndOfBlock false\n"); if (cbuf->params.u.fax.black_is_1) fz_printf(ctx, out, "/BlackIs1 true\n"); if (cbuf->params.u.fax.damaged_rows_before_error > 0) fz_printf(ctx, out, "/DamagedRowsBeforeError %d\n", cbuf->params.u.fax.damaged_rows_before_error); fz_printf(ctx, out, ahx ? ">>]\n" : ">>\n"); break; case FZ_IMAGE_RAW: if (ahx) fz_printf(ctx, out, "/F/AHx\n"); break; case FZ_IMAGE_RLD: fz_printf(ctx, out, ahx ? "/F[/AHx/RL]\n" : "/F/RL\n"); break; case FZ_IMAGE_FLATE: fz_printf(ctx, out, ahx ? "/F[/AHx/Fl]\n" : "/F/Fl\n"); if (cbuf->params.u.flate.predictor > 1) { fz_printf(ctx, out, ahx ? "/DP[null<<\n" : "/DP<<\n"); fz_printf(ctx, out, "/Predictor %d\n", cbuf->params.u.flate.predictor); if (cbuf->params.u.flate.columns != 1) fz_printf(ctx, out, "/Columns %d\n", cbuf->params.u.flate.columns); if (cbuf->params.u.flate.colors != 1) fz_printf(ctx, out, "/Colors %d\n", cbuf->params.u.flate.colors); if (cbuf->params.u.flate.bpc != 8) fz_printf(ctx, out, "/BitsPerComponent %d\n", cbuf->params.u.flate.bpc); fz_printf(ctx, out, ahx ? ">>]\n" : ">>\n"); } break; case FZ_IMAGE_LZW: fz_printf(ctx, out, ahx ? "/F[/AHx/LZW]\n" : "/F/LZW\n"); if (cbuf->params.u.lzw.predictor > 1) { fz_printf(ctx, out, ahx ? "/DP[<<null\n" : "/DP<<\n"); fz_printf(ctx, out, "/Predictor %d\n", cbuf->params.u.lzw.predictor); if (cbuf->params.u.lzw.columns != 1) fz_printf(ctx, out, "/Columns %d\n", cbuf->params.u.lzw.columns); if (cbuf->params.u.lzw.colors != 1) fz_printf(ctx, out, "/Colors %d\n", cbuf->params.u.lzw.colors); if (cbuf->params.u.lzw.bpc != 8) fz_printf(ctx, out, "/BitsPerComponent %d\n", cbuf->params.u.lzw.bpc); if (cbuf->params.u.lzw.early_change != 1) fz_printf(ctx, out, "/EarlyChange %d\n", cbuf->params.u.lzw.early_change); fz_printf(ctx, out, ahx ? ">>]\n" : ">>\n"); } break; } fz_printf(ctx, out, "ID\n"); if (ahx) { size_t z; for (z = 0; z < buf->len; ++z) { int c = buf->data[z]; fz_putc(ctx, out, "0123456789abcdef"[(c >> 4) & 0xf]); fz_putc(ctx, out, "0123456789abcdef"[c & 0xf]); if ((z & 31) == 31) fz_putc(ctx, out, '\n'); } fz_putc(ctx, out, '>'); } else {
static fz_pixmap * pam_binary_read_image(fz_context *ctx, struct info *pnm, unsigned char *p, unsigned char *e, int onlymeta) { fz_pixmap *img = NULL; int bitmap = 0; p = pam_binary_read_header(ctx, pnm, p, e); if (pnm->tupletype == NULL) switch (pnm->depth) { case 1: pnm->tupletype = fz_strdup(ctx, "BLACKANDWHITE"); break; case 2: pnm->tupletype = fz_strdup(ctx, "GRAYSCALE_ALPHA"); break; case 3: pnm->tupletype = fz_strdup(ctx, "RGB"); break; case 4: pnm->tupletype = fz_strdup(ctx, "CMYK"); break; case 5: pnm->tupletype = fz_strdup(ctx, "CMYK_ALPHA"); break; default: fz_throw(ctx, FZ_ERROR_GENERIC, "cannot guess tupletype based on depth in pnm image"); } if (!strcmp(pnm->tupletype, "BLACKANDWHITE")) { if (pnm->depth != 1) fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for b/w pnm image"); if (pnm->maxval == 1) bitmap = 1; else if (pnm->maxval < 2 || pnm->maxval > 65535) fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for grayscale pnm image"); pnm->cs = fz_device_gray(ctx); } else if (!strcmp(pnm->tupletype, "GRAYSCALE")) { if (pnm->maxval < 2 || pnm->maxval > 65535) fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for grayscale pnm image"); if (pnm->depth != 1) fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for grayscale pnm image"); pnm->cs = fz_device_gray(ctx); } else if (!strcmp(pnm->tupletype, "GRAYSCALE_ALPHA")) { if (pnm->maxval < 2 || pnm->maxval > 65535) fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for grayscale pnm image with alpha"); if (pnm->depth != 2) fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for grayscale pnm image with alpha"); pnm->cs = fz_device_gray(ctx); pnm->alpha = 1; } else if (!strcmp(pnm->tupletype, "RGB")) { if (pnm->maxval < 1 || pnm->maxval > 65535) fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for rgb pnm image"); if (pnm->depth != 3) fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for rgb pnm image"); pnm->cs = fz_device_rgb(ctx); } else if (!strcmp(pnm->tupletype, "RGB_ALPHA")) { if (pnm->maxval < 1 || pnm->maxval > 65535) fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for rgb pnm image with alpha"); if (pnm->depth != 4) fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for rgb pnm image with alpha"); pnm->cs = fz_device_rgb(ctx); pnm->alpha = 1; } else if (!strcmp(pnm->tupletype, "CMYK")) { if (pnm->maxval < 1 || pnm->maxval > 65535) fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for cmyk pnm image"); if (pnm->depth != 4) fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for cmyk pnm image"); pnm->cs = fz_device_cmyk(ctx); } else if (!strcmp(pnm->tupletype, "CMYK_ALPHA")) { if (pnm->maxval < 1 || pnm->maxval > 65535) fz_throw(ctx, FZ_ERROR_GENERIC, "maxval out of range for cmyk pnm image with alpha"); if (pnm->depth != 5) fz_throw(ctx, FZ_ERROR_GENERIC, "depth out of range for cmyk pnm image with alpha"); pnm->cs = fz_device_cmyk(ctx); pnm->alpha = 1; } else { fz_free(ctx, pnm->tupletype); fz_throw(ctx, FZ_ERROR_GENERIC, "unsupported tupletype"); } fz_free(ctx, pnm->tupletype); if (!onlymeta) { unsigned char *dp; int x, y, k; img = fz_new_pixmap(ctx, pnm->cs, pnm->width, pnm->height, pnm->alpha); dp = img->samples; if (bitmap) { if (e - p < pnm->height * pnm->width * img->n) fz_throw(ctx, FZ_ERROR_GENERIC, "truncated image"); for (y = 0; y < pnm->height; y++) for (x = 0; x < pnm->width; x++) for (k = 0; k < img->colorspace->n; k++) { if (*p) *dp = 0x00; else *dp = 0xff; dp++; p++; } } else { if (pnm->maxval == 255) { if (e - p < pnm->height * pnm->width * img->n) fz_throw(ctx, FZ_ERROR_GENERIC, "truncated image"); for (y = 0; y < pnm->height; y++) for (x = 0; x < pnm->width; x++) for (k = 0; k < img->n; k++) *dp++ = *p++; } else if (pnm->maxval < 256) { if (e - p < pnm->height * pnm->width * img->n) fz_throw(ctx, FZ_ERROR_GENERIC, "truncated image"); for (y = 0; y < pnm->height; y++) for (x = 0; x < pnm->width; x++) for (k = 0; k < img->n; k++) *dp++ = map_color(ctx, *p++, pnm->maxval, 255); } else { if (e - p < pnm->height * pnm->width * img->n * 2) fz_throw(ctx, FZ_ERROR_GENERIC, "truncated image"); for (y = 0; y < pnm->height; y++) for (x = 0; x < pnm->width; x++) for (k = 0; k < img->n; k++) { *dp++ = map_color(ctx, (p[0] << 8) | p[1], pnm->maxval, 255); p += 2; } } } } return img; }
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; }