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 fz_colorspace * load_indexed(pdf_document *doc, pdf_obj *array) { fz_context *ctx = doc->ctx; pdf_obj *baseobj = pdf_array_get(array, 1); pdf_obj *highobj = pdf_array_get(array, 2); pdf_obj *lookupobj = pdf_array_get(array, 3); fz_colorspace *base = NULL; fz_colorspace *cs; int i, n, high; unsigned char *lookup = NULL; fz_var(base); fz_var(lookup); fz_try(ctx) { base = pdf_load_colorspace(doc, baseobj); high = pdf_to_int(highobj); high = fz_clampi(high, 0, 255); n = base->n * (high + 1); lookup = fz_malloc_array(ctx, 1, n); if (pdf_is_string(lookupobj) && pdf_to_str_len(lookupobj) >= n) { unsigned char *buf = (unsigned char *) pdf_to_str_buf(lookupobj); for (i = 0; i < n; i++) lookup[i] = buf[i]; } else if (pdf_is_indirect(lookupobj)) { fz_stream *file = NULL; fz_var(file); fz_try(ctx) { file = pdf_open_stream(doc, pdf_to_num(lookupobj), pdf_to_gen(lookupobj)); i = fz_read(file, lookup, n); if (i < n) memset(lookup+i, 0, n-i); } fz_always(ctx) { fz_close(file); } fz_catch(ctx) { fz_rethrow_message(ctx, "cannot open colorspace lookup table (%d 0 R)", pdf_to_num(lookupobj)); } } else { fz_rethrow_message(ctx, "cannot parse colorspace lookup table"); } cs = fz_new_indexed_colorspace(ctx, base, high, lookup); }
static fz_colorspace * load_separation(pdf_document *xref, pdf_obj *array) { fz_colorspace *cs; struct separation *sep = NULL; fz_context *ctx = xref->ctx; pdf_obj *nameobj = pdf_array_get(array, 1); pdf_obj *baseobj = pdf_array_get(array, 2); pdf_obj *tintobj = pdf_array_get(array, 3); fz_colorspace *base; pdf_function *tint = NULL; int n; fz_var(tint); fz_var(sep); if (pdf_is_array(nameobj)) n = pdf_array_len(nameobj); else n = 1; if (n > FZ_MAX_COLORS) fz_throw(ctx, "too many components in colorspace"); base = pdf_load_colorspace(xref, baseobj); /* RJW: "cannot load base colorspace (%d %d R)", pdf_to_num(baseobj), pdf_to_gen(baseobj) */ fz_try(ctx) { tint = pdf_load_function(xref, tintobj); /* RJW: fz_drop_colorspace(ctx, base); * "cannot load tint function (%d %d R)", pdf_to_num(tintobj), pdf_to_gen(tintobj) */ sep = fz_malloc_struct(ctx, struct separation); sep->base = base; sep->tint = tint; cs = fz_new_colorspace(ctx, n == 1 ? "Separation" : "DeviceN", n); cs->to_rgb = separation_to_rgb; cs->free_data = free_separation; cs->data = sep; cs->size += sizeof(struct separation) + (base ? base->size : 0) + pdf_function_size(tint); } fz_catch(ctx) { fz_drop_colorspace(ctx, base); pdf_drop_function(ctx, tint); fz_free(ctx, sep); fz_rethrow(ctx); } return cs; }
static fz_error pdf_load_jpx_image(fz_pixmap **imgp, pdf_xref *xref, fz_obj *dict) { fz_error error; fz_buffer *buf; fz_colorspace *colorspace; fz_pixmap *img; fz_obj *obj; colorspace = NULL; error = pdf_load_stream(&buf, xref, fz_to_num(dict), fz_to_gen(dict)); if (error) return fz_rethrow(error, "cannot load jpx image data"); obj = fz_dict_gets(dict, "ColorSpace"); if (obj) { error = pdf_load_colorspace(&colorspace, xref, obj); if (error) fz_catch(error, "cannot load image colorspace"); } error = fz_load_jpx_image(&img, buf->data, buf->len, colorspace); if (error) { if (colorspace) fz_drop_colorspace(colorspace); fz_drop_buffer(buf); return fz_rethrow(error, "cannot load jpx image"); } if (colorspace) fz_drop_colorspace(colorspace); fz_drop_buffer(buf); obj = fz_dict_getsa(dict, "SMask", "Mask"); if (fz_is_dict(obj)) { error = pdf_load_image_imp(&img->mask, xref, NULL, obj, NULL, 1); if (error) { fz_drop_pixmap(img); return fz_rethrow(error, "cannot load image mask/softmask"); } } *imgp = img; return fz_okay; }
static fz_error load_separation(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) { fz_error error; fz_colorspace *cs; struct separation *sep; fz_obj *nameobj = fz_array_get(array, 1); fz_obj *baseobj = fz_array_get(array, 2); fz_obj *tintobj = fz_array_get(array, 3); fz_colorspace *base; pdf_function *tint; int n; if (fz_is_array(nameobj)) n = fz_array_len(nameobj); else n = 1; if (n > FZ_MAX_COLORS) return fz_throw("too many components in colorspace"); error = pdf_load_colorspace(&base, xref, baseobj); if (error) return fz_rethrow(error, "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj)); error = pdf_load_function(&tint, xref, tintobj); if (error) { fz_drop_colorspace(base); return fz_rethrow(error, "cannot load tint function (%d %d R)", fz_to_num(tintobj), fz_to_gen(tintobj)); } sep = fz_malloc(sizeof(struct separation)); sep->base = base; sep->tint = tint; cs = fz_new_colorspace(n == 1 ? "Separation" : "DeviceN", n); cs->to_rgb = separation_to_rgb; cs->free_data = free_separation; cs->data = sep; *csp = cs; return fz_okay; }
fz_colorspace * pdf_xobject_colorspace(fz_context *ctx, pdf_obj *xobj) { pdf_obj *group = pdf_dict_get(ctx, xobj, PDF_NAME(Group)); if (group) { pdf_obj *cs = pdf_dict_get(ctx, group, PDF_NAME(CS)); if (cs) { fz_colorspace *colorspace = NULL; fz_try(ctx) colorspace = pdf_load_colorspace(ctx, cs); fz_catch(ctx) fz_warn(ctx, "cannot load xobject colorspace"); return colorspace; } } return NULL; }
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"); }
static void pdf_run_page_contents_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_device *dev, const fz_matrix *ctm, const char *usage, fz_cookie *cookie) { fz_matrix local_ctm, page_ctm; pdf_obj *resources; pdf_obj *contents; fz_rect mediabox; pdf_processor *proc = NULL; fz_default_colorspaces *default_cs; fz_var(proc); default_cs = pdf_load_default_colorspaces(ctx, doc, page); if (default_cs) fz_set_default_colorspaces(ctx, dev, default_cs); fz_try(ctx) { pdf_page_transform(ctx, page, &mediabox, &page_ctm); fz_concat(&local_ctm, &page_ctm, ctm); resources = pdf_page_resources(ctx, page); contents = pdf_page_contents(ctx, page); if (page->transparency) { fz_colorspace *colorspace = NULL; pdf_obj *group = pdf_page_group(ctx, page); if (group) { pdf_obj *cs = pdf_dict_get(ctx, group, PDF_NAME_CS); if (cs) { fz_try(ctx) colorspace = pdf_load_colorspace(ctx, cs); fz_catch(ctx) colorspace = NULL; } } else colorspace = fz_keep_colorspace(ctx, fz_default_output_intent(ctx, default_cs)); fz_begin_group(ctx, dev, fz_transform_rect(&mediabox, &local_ctm), colorspace, 1, 0, 0, 1); fz_drop_colorspace(ctx, colorspace); } proc = pdf_new_run_processor(ctx, dev, &local_ctm, usage, NULL, 0); pdf_process_contents(ctx, proc, doc, resources, contents, cookie); pdf_close_processor(ctx, proc); } fz_always(ctx) { fz_drop_default_colorspaces(ctx, default_cs); pdf_drop_processor(ctx, proc); } fz_catch(ctx) fz_rethrow(ctx); if (page->transparency) fz_end_group(ctx, dev); }
static fz_error pdf_load_shading_dict(fz_shade **shadep, pdf_xref *xref, fz_obj *dict, fz_matrix transform) { fz_error error; fz_shade *shade; pdf_function *func[FZ_MAX_COLORS] = { NULL }; fz_stream *stream = NULL; fz_obj *obj; int funcs; int type; int i; shade = fz_malloc(sizeof(fz_shade)); shade->refs = 1; shade->type = FZ_MESH; shade->use_background = 0; shade->use_function = 0; shade->matrix = transform; shade->bbox = fz_infinite_rect; shade->extend[0] = 0; shade->extend[1] = 0; shade->mesh_len = 0; shade->mesh_cap = 0; shade->mesh = NULL; shade->colorspace = NULL; funcs = 0; obj = fz_dict_gets(dict, "ShadingType"); type = fz_to_int(obj); obj = fz_dict_gets(dict, "ColorSpace"); if (!obj) { fz_drop_shade(shade); return fz_throw("shading colorspace is missing"); } error = pdf_load_colorspace(&shade->colorspace, xref, obj); if (error) { fz_drop_shade(shade); return fz_rethrow(error, "cannot load colorspace (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); } obj = fz_dict_gets(dict, "Background"); if (obj) { shade->use_background = 1; for (i = 0; i < shade->colorspace->n; i++) shade->background[i] = fz_to_real(fz_array_get(obj, i)); } obj = fz_dict_gets(dict, "BBox"); if (fz_is_array(obj)) { shade->bbox = pdf_to_rect(obj); } obj = fz_dict_gets(dict, "Function"); if (fz_is_dict(obj)) { funcs = 1; error = pdf_load_function(&func[0], xref, obj); if (error) { error = fz_rethrow(error, "cannot load shading function (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); goto cleanup; } } else if (fz_is_array(obj)) { funcs = fz_array_len(obj); if (funcs != 1 && funcs != shade->colorspace->n) { error = fz_throw("incorrect number of shading functions"); goto cleanup; } for (i = 0; i < funcs; i++) { error = pdf_load_function(&func[i], xref, fz_array_get(obj, i)); if (error) { error = fz_rethrow(error, "cannot load shading function (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); goto cleanup; } } } if (type >= 4 && type <= 7) { error = pdf_open_stream(&stream, xref, fz_to_num(dict), fz_to_gen(dict)); if (error) { error = fz_rethrow(error, "cannot open shading stream (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); goto cleanup; } } switch (type) { case 1: pdf_load_function_based_shading(shade, xref, dict, func[0]); break; case 2: pdf_load_axial_shading(shade, xref, dict, funcs, func); break; case 3: pdf_load_radial_shading(shade, xref, dict, funcs, func); break; case 4: pdf_load_type4_shade(shade, xref, dict, funcs, func, stream); break; case 5: pdf_load_type5_shade(shade, xref, dict, funcs, func, stream); break; case 6: pdf_load_type6_shade(shade, xref, dict, funcs, func, stream); break; case 7: pdf_load_type7_shade(shade, xref, dict, funcs, func, stream); break; default: error = fz_throw("unknown shading type: %d", type); goto cleanup; } if (stream) fz_close(stream); for (i = 0; i < funcs; i++) if (func[i]) pdf_drop_function(func[i]); *shadep = shade; return fz_okay; cleanup: if (stream) fz_close(stream); for (i = 0; i < funcs; i++) if (func[i]) pdf_drop_function(func[i]); fz_drop_shade(shade); return fz_rethrow(error, "cannot load shading type %d (%d %d R)", type, fz_to_num(dict), fz_to_gen(dict)); }
static fz_shade * pdf_load_shading_dict(pdf_document *xref, pdf_obj *dict, fz_matrix transform) { fz_shade *shade = NULL; pdf_function *func[FZ_MAX_COLORS] = { NULL }; pdf_obj *obj; int funcs = 0; int type = 0; int i, in, out; fz_context *ctx = xref->ctx; fz_var(shade); fz_var(func); fz_var(funcs); fz_var(type); fz_try(ctx) { shade = fz_malloc_struct(ctx, fz_shade); FZ_INIT_STORABLE(shade, 1, fz_free_shade_imp); shade->type = FZ_MESH_TYPE4; shade->use_background = 0; shade->use_function = 0; shade->matrix = transform; shade->bbox = fz_infinite_rect; shade->colorspace = NULL; funcs = 0; obj = pdf_dict_gets(dict, "ShadingType"); type = pdf_to_int(obj); obj = pdf_dict_gets(dict, "ColorSpace"); if (!obj) fz_throw(ctx, "shading colorspace is missing"); shade->colorspace = pdf_load_colorspace(xref, obj); obj = pdf_dict_gets(dict, "Background"); if (obj) { shade->use_background = 1; for (i = 0; i < shade->colorspace->n; i++) shade->background[i] = pdf_to_real(pdf_array_get(obj, i)); } obj = pdf_dict_gets(dict, "BBox"); if (pdf_is_array(obj)) { shade->bbox = pdf_to_rect(ctx, obj); } obj = pdf_dict_gets(dict, "Function"); if (pdf_is_dict(obj)) { funcs = 1; if (type == 1) in = 2; else in = 1; out = shade->colorspace->n; func[0] = pdf_load_function(xref, obj, in, out); if (!func[0]) fz_throw(ctx, "cannot load shading function (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); } else if (pdf_is_array(obj)) { funcs = pdf_array_len(obj); if (funcs != 1 && funcs != shade->colorspace->n) { funcs = 0; fz_throw(ctx, "incorrect number of shading functions"); } if (funcs > FZ_MAX_COLORS) { funcs = 0; fz_throw(ctx, "too many shading functions"); } if (type == 1) in = 2; else in = 1; out = 1; for (i = 0; i < funcs; i++) { func[i] = pdf_load_function(xref, pdf_array_get(obj, i), in, out); if (!func[i]) fz_throw(ctx, "cannot load shading function (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); } } else if (type < 4) { /* Functions are compulsory for types 1,2,3 */ fz_throw(ctx, "cannot load shading function (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); } shade->type = type; switch (type) { case 1: pdf_load_function_based_shading(shade, xref, dict, func[0]); break; case 2: pdf_load_linear_shading(shade, xref, dict, funcs, func); break; case 3: pdf_load_radial_shading(shade, xref, dict, funcs, func); break; case 4: pdf_load_type4_shade(shade, xref, dict, funcs, func); break; case 5: pdf_load_type5_shade(shade, xref, dict, funcs, func); break; case 6: pdf_load_type6_shade(shade, xref, dict, funcs, func); break; case 7: pdf_load_type7_shade(shade, xref, dict, funcs, func); break; default: fz_throw(ctx, "unknown shading type: %d", type); } for (i = 0; i < funcs; i++) if (func[i]) pdf_drop_function(ctx, func[i]); } fz_catch(ctx) { for (i = 0; i < funcs; i++) if (func[i]) pdf_drop_function(ctx, func[i]); fz_drop_shade(ctx, shade); fz_throw(ctx, "cannot load shading type %d (%d %d R)", type, pdf_to_num(dict), pdf_to_gen(dict)); } return shade; }
static fz_error pdf_load_colorspace_imp(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj) { if (fz_is_name(obj)) { if (!strcmp(fz_to_name(obj), "Pattern")) *csp = fz_device_gray; else if (!strcmp(fz_to_name(obj), "G")) *csp = fz_device_gray; else if (!strcmp(fz_to_name(obj), "RGB")) *csp = fz_device_rgb; else if (!strcmp(fz_to_name(obj), "CMYK")) *csp = fz_device_cmyk; else if (!strcmp(fz_to_name(obj), "DeviceGray")) *csp = fz_device_gray; else if (!strcmp(fz_to_name(obj), "DeviceRGB")) *csp = fz_device_rgb; else if (!strcmp(fz_to_name(obj), "DeviceCMYK")) *csp = fz_device_cmyk; else return fz_throw("unknown colorspace: %s", fz_to_name(obj)); return fz_okay; } else if (fz_is_array(obj)) { fz_obj *name = fz_array_get(obj, 0); if (fz_is_name(name)) { /* load base colorspace instead */ if (!strcmp(fz_to_name(name), "Pattern")) { fz_error error; obj = fz_array_get(obj, 1); if (!obj) { *csp = fz_device_gray; return fz_okay; } error = pdf_load_colorspace(csp, xref, obj); if (error) return fz_rethrow(error, "cannot load pattern (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); } else if (!strcmp(fz_to_name(name), "G")) *csp = fz_device_gray; else if (!strcmp(fz_to_name(name), "RGB")) *csp = fz_device_rgb; else if (!strcmp(fz_to_name(name), "CMYK")) *csp = fz_device_cmyk; else if (!strcmp(fz_to_name(name), "DeviceGray")) *csp = fz_device_gray; else if (!strcmp(fz_to_name(name), "DeviceRGB")) *csp = fz_device_rgb; else if (!strcmp(fz_to_name(name), "DeviceCMYK")) *csp = fz_device_cmyk; else if (!strcmp(fz_to_name(name), "CalGray")) *csp = fz_device_gray; else if (!strcmp(fz_to_name(name), "CalRGB")) *csp = fz_device_rgb; else if (!strcmp(fz_to_name(name), "CalCMYK")) *csp = fz_device_cmyk; else if (!strcmp(fz_to_name(name), "Lab")) *csp = fz_device_lab; else if (!strcmp(fz_to_name(name), "ICCBased")) return load_icc_based(csp, xref, fz_array_get(obj, 1)); else if (!strcmp(fz_to_name(name), "Indexed")) return load_indexed(csp, xref, obj); else if (!strcmp(fz_to_name(name), "I")) return load_indexed(csp, xref, obj); else if (!strcmp(fz_to_name(name), "Separation")) return load_separation(csp, xref, obj); else if (!strcmp(fz_to_name(name), "DeviceN")) return load_separation(csp, xref, obj); else return fz_throw("syntaxerror: unknown colorspace %s", fz_to_name(name)); return fz_okay; } } return fz_throw("syntaxerror: could not parse color space (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); }
static fz_error pdf_load_image_imp(fz_pixmap **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cstm, int forcemask) { fz_stream *stm; fz_pixmap *tile; fz_obj *obj, *res; fz_error error; int w, h, bpc, n; int imagemask; int interpolate; int indexed; fz_colorspace *colorspace; fz_pixmap *mask; /* explicit mask/softmask image */ int usecolorkey; int colorkey[FZ_MAX_COLORS * 2]; float decode[FZ_MAX_COLORS * 2]; int stride; unsigned char *samples; int i, len; /* special case for JPEG2000 images */ if (pdf_is_jpx_image(dict)) { tile = NULL; error = pdf_load_jpx_image(&tile, xref, dict); if (error) return fz_rethrow(error, "cannot load jpx image"); if (forcemask) { if (tile->n != 2) { fz_drop_pixmap(tile); return fz_throw("softmask must be grayscale"); } mask = fz_alpha_from_gray(tile, 1); fz_drop_pixmap(tile); *imgp = mask; return fz_okay; } *imgp = tile; return fz_okay; } w = fz_to_int(fz_dict_getsa(dict, "Width", "W")); h = fz_to_int(fz_dict_getsa(dict, "Height", "H")); bpc = fz_to_int(fz_dict_getsa(dict, "BitsPerComponent", "BPC")); imagemask = fz_to_bool(fz_dict_getsa(dict, "ImageMask", "IM")); interpolate = fz_to_bool(fz_dict_getsa(dict, "Interpolate", "I")); indexed = 0; usecolorkey = 0; colorspace = NULL; mask = NULL; if (imagemask) bpc = 1; if (w == 0) return fz_throw("image width is zero"); if (h == 0) return fz_throw("image height is zero"); if (bpc == 0) return fz_throw("image depth is zero"); if (w > (1 << 16)) return fz_throw("image is too wide"); if (h > (1 << 16)) return fz_throw("image is too high"); obj = fz_dict_getsa(dict, "ColorSpace", "CS"); if (obj && !imagemask && !forcemask) { /* colorspace resource lookup is only done for inline images */ if (fz_is_name(obj)) { res = fz_dict_get(fz_dict_gets(rdb, "ColorSpace"), obj); if (res) obj = res; } error = pdf_load_colorspace(&colorspace, xref, obj); if (error) return fz_rethrow(error, "cannot load image colorspace"); if (!strcmp(colorspace->name, "Indexed")) indexed = 1; n = colorspace->n; } else { n = 1; } obj = fz_dict_getsa(dict, "Decode", "D"); if (obj) { for (i = 0; i < n * 2; i++) decode[i] = fz_to_real(fz_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 = fz_dict_getsa(dict, "SMask", "Mask"); if (fz_is_dict(obj)) { /* Not allowed for inline images */ if (!cstm) { error = pdf_load_image_imp(&mask, xref, rdb, obj, NULL, 1); if (error) { if (colorspace) fz_drop_colorspace(colorspace); return fz_rethrow(error, "cannot load image mask/softmask"); } } } else if (fz_is_array(obj)) { usecolorkey = 1; for (i = 0; i < n * 2; i++) colorkey[i] = fz_to_int(fz_array_get(obj, i)); } /* Allocate now, to fail early if we run out of memory */ tile = fz_new_pixmap_with_limit(colorspace, w, h); if (!tile) { if (colorspace) fz_drop_colorspace(colorspace); if (mask) fz_drop_pixmap(mask); return fz_throw("out of memory"); } if (colorspace) fz_drop_colorspace(colorspace); tile->mask = mask; tile->interpolate = interpolate; stride = (w * n * bpc + 7) / 8; if (cstm) { stm = pdf_open_inline_stream(cstm, xref, dict, stride * h); } else { error = pdf_open_stream(&stm, xref, fz_to_num(dict), fz_to_gen(dict)); if (error) { fz_drop_pixmap(tile); return fz_rethrow(error, "cannot open image data stream (%d 0 R)", fz_to_num(dict)); } } samples = fz_calloc(h, stride); len = fz_read(stm, samples, h * stride); if (len < 0) { fz_close(stm); fz_free(samples); fz_drop_pixmap(tile); return fz_rethrow(len, "cannot read image data"); } /* Make sure we read the EOF marker (for inline images only) */ if (cstm) { unsigned char tbuf[512]; int tlen = fz_read(stm, tbuf, sizeof tbuf); if (tlen < 0) fz_catch(tlen, "ignoring error at end of image"); if (tlen > 0) fz_warn("ignoring garbage at end of image"); } fz_close(stm); /* Pad truncated images */ if (len < stride * h) { fz_warn("padding truncated image (%d 0 R)", fz_to_num(dict)); memset(samples + len, 0, stride * h - len); } /* Invert 1-bit image masks */ if (imagemask) { /* 0=opaque and 1=transparent so we need to invert */ unsigned char *p = samples; len = h * stride; for (i = 0; i < len; i++) p[i] = ~p[i]; } fz_unpack_tile(tile, samples, n, bpc, stride, indexed); fz_free(samples); if (usecolorkey) pdf_mask_color_key(tile, n, colorkey); if (indexed) { fz_pixmap *conv; fz_decode_indexed_tile(tile, decode, (1 << bpc) - 1); conv = pdf_expand_indexed_pixmap(tile); fz_drop_pixmap(tile); tile = conv; } else { fz_decode_tile(tile, decode); } *imgp = tile; return fz_okay; }
static fz_image * pdf_load_image_imp(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask) { 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 use_colorkey = 0; fz_colorspace *colorspace = NULL; float decode[FZ_MAX_COLORS * 2]; int colorkey[FZ_MAX_COLORS * 2]; int stride; int i; fz_compressed_buffer *buffer; /* special case for JPEG2000 images */ if (pdf_is_jpx_image(ctx, dict)) return pdf_load_jpx_imp(ctx, doc, rdb, dict, cstm, forcemask); w = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Width), PDF_NAME(W))); h = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Height), PDF_NAME(H))); bpc = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(BitsPerComponent), PDF_NAME(BPC))); if (bpc == 0) bpc = 8; imagemask = pdf_to_bool(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(ImageMask), PDF_NAME(IM))); interpolate = pdf_to_bool(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Interpolate), PDF_NAME(I))); indexed = 0; use_colorkey = 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"); fz_var(mask); fz_var(image); fz_var(colorspace); fz_try(ctx) { obj = pdf_dict_geta(ctx, dict, PDF_NAME(ColorSpace), PDF_NAME(CS)); if (obj && !imagemask && !forcemask) { /* colorspace resource lookup is only done for inline images */ if (pdf_is_name(ctx, obj)) { res = pdf_dict_get(ctx, pdf_dict_get(ctx, rdb, PDF_NAME(ColorSpace)), obj); if (res) obj = res; } colorspace = pdf_load_colorspace(ctx, obj); indexed = fz_colorspace_is_indexed(ctx, colorspace); n = fz_colorspace_n(ctx, colorspace); } else { n = 1; } obj = pdf_dict_geta(ctx, dict, PDF_NAME(Decode), PDF_NAME(D)); if (obj) { for (i = 0; i < n * 2; i++) decode[i] = pdf_array_get_real(ctx, obj, i); } else if (fz_colorspace_is_lab(ctx, colorspace) || fz_colorspace_is_lab_icc(ctx, colorspace)) { decode[0] = 0; decode[1] = 100; decode[2] = -128; decode[3] = 127; decode[4] = -128; decode[5] = 127; } else { float maxval = indexed ? (1 << bpc) - 1 : 1; for (i = 0; i < n * 2; i++) decode[i] = i & 1 ? maxval : 0; } obj = pdf_dict_geta(ctx, dict, PDF_NAME(SMask), PDF_NAME(Mask)); if (pdf_is_dict(ctx, 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(ctx, doc, rdb, obj, NULL, 1); obj = pdf_dict_get(ctx, obj, PDF_NAME(Matte)); if (pdf_is_array(ctx, obj)) { use_colorkey = 1; for (i = 0; i < n; i++) colorkey[i] = pdf_array_get_real(ctx, obj, i) * 255; } } } else if (pdf_is_array(ctx, obj)) { use_colorkey = 1; for (i = 0; i < n * 2; i++) { if (!pdf_is_int(ctx, pdf_array_get(ctx, obj, i))) { fz_warn(ctx, "invalid value in color key mask"); use_colorkey = 0; } colorkey[i] = pdf_array_get_int(ctx, 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. */ buffer = pdf_load_compressed_stream(ctx, doc, pdf_to_num(ctx, dict)); image = fz_new_image_from_compressed_buffer(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, use_colorkey ? colorkey : NULL, buffer, mask); image->invert_cmyk_jpeg = 0; } else { /* Inline stream */ stride = (w * n * bpc + 7) / 8; image = fz_new_image_from_compressed_buffer(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, use_colorkey ? colorkey : NULL, NULL, mask); image->invert_cmyk_jpeg = 0; pdf_load_compressed_inline_image(ctx, doc, dict, stride * h, cstm, indexed, (fz_compressed_image *)image); } } fz_always(ctx) { fz_drop_colorspace(ctx, colorspace); fz_drop_image(ctx, mask); } fz_catch(ctx) { fz_drop_image(ctx, image); fz_rethrow(ctx); } return image; }
static pdf_image * pdf_load_image_imp(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask) { fz_stream *stm = NULL; pdf_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; int i; fz_context *ctx = xref->ctx; fz_var(stm); fz_var(mask); image = fz_malloc_struct(ctx, pdf_image); fz_try(ctx) { /* special case for JPEG2000 images */ if (pdf_is_jpx_image(ctx, dict)) { pdf_load_jpx(xref, dict, image, forcemask); if (forcemask) { fz_pixmap *mask_pixmap; if (image->n != 2) fz_throw(ctx, "soft mask must be grayscale"); 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; mask = NULL; if (imagemask) bpc = 1; if (w <= 0) fz_throw(ctx, "image width is zero (or less)"); if (h <= 0) fz_throw(ctx, "image height is zero (or less)"); if (bpc <= 0) fz_throw(ctx, "image depth is zero (or less)"); if (bpc > 16) fz_throw(ctx, "image depth is too large: %d", bpc); if (w > (1 << 16)) fz_throw(ctx, "image is too wide"); if (h > (1 << 16)) fz_throw(ctx, "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; } image->base.colorspace = pdf_load_colorspace(xref, obj); if (!strcmp(image->base.colorspace->name, "Indexed")) indexed = 1; n = image->base.colorspace->n; } else { n = 1; } obj = pdf_dict_getsa(dict, "Decode", "D"); if (obj) { for (i = 0; i < n * 2; i++) image->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++) image->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 = (fz_image *)pdf_load_image_imp(xref, rdb, obj, NULL, 1); } 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; } image->colorkey[i] = pdf_to_int(pdf_array_get(obj, i)); } } /* Now, do we load a ref, or do we load the actual thing? */ FZ_INIT_STORABLE(&image->base, 1, pdf_free_image); image->base.get_pixmap = pdf_image_get_pixmap; image->base.w = w; image->base.h = h; image->base.bpc = bpc; image->n = n; image->interpolate = interpolate; image->imagemask = imagemask; image->usecolorkey = usecolorkey; image->base.mask = mask; if (!cstm) { /* 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); image->buffer = pdf_load_compressed_stream(xref, num, gen); break; /* Out of fz_try */ } /* We need to decompress the image now */ if (cstm) { int stride = (w * image->n * image->base.bpc + 7) / 8; stm = pdf_open_inline_stream(xref, dict, stride * h, cstm, NULL); } else { stm = pdf_open_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); } image->tile = decomp_image_from_stream(ctx, stm, image, cstm != NULL, indexed, 0, 0, 0); } fz_catch(ctx) { pdf_free_image(ctx, (fz_storable *) image); fz_rethrow(ctx); } return image; }
static fz_shade * pdf_load_shading_dict(fz_context *ctx, pdf_document *doc, pdf_obj *dict, const fz_matrix *transform) { fz_shade *shade = NULL; pdf_function *func[FZ_MAX_COLORS] = { NULL }; pdf_obj *obj; int funcs = 0; int type = 0; int i, in, out, n; fz_var(shade); fz_var(func); fz_var(funcs); fz_var(type); fz_try(ctx) { shade = fz_malloc_struct(ctx, fz_shade); FZ_INIT_STORABLE(shade, 1, fz_drop_shade_imp); shade->type = FZ_MESH_TYPE4; shade->use_background = 0; shade->use_function = 0; shade->matrix = *transform; shade->bbox = fz_infinite_rect; shade->colorspace = NULL; funcs = 0; obj = pdf_dict_get(ctx, dict, PDF_NAME(ShadingType)); type = pdf_to_int(ctx, obj); obj = pdf_dict_get(ctx, dict, PDF_NAME(ColorSpace)); if (!obj) fz_throw(ctx, FZ_ERROR_SYNTAX, "shading colorspace is missing"); shade->colorspace = pdf_load_colorspace(ctx, obj); n = fz_colorspace_n(ctx, shade->colorspace); obj = pdf_dict_get(ctx, dict, PDF_NAME(Background)); if (obj) { shade->use_background = 1; for (i = 0; i < n; i++) shade->background[i] = pdf_array_get_real(ctx, obj, i); } obj = pdf_dict_get(ctx, dict, PDF_NAME(BBox)); if (pdf_is_array(ctx, obj)) pdf_to_rect(ctx, obj, &shade->bbox); obj = pdf_dict_get(ctx, dict, PDF_NAME(Function)); if (pdf_is_dict(ctx, obj)) { funcs = 1; if (type == 1) in = 2; else in = 1; out = n; func[0] = pdf_load_function(ctx, obj, in, out); if (!func[0]) fz_throw(ctx, FZ_ERROR_SYNTAX, "cannot load shading function (%d 0 R)", pdf_to_num(ctx, obj)); } else if (pdf_is_array(ctx, obj)) { funcs = pdf_array_len(ctx, obj); if (funcs != 1 && funcs != n) { funcs = 0; fz_throw(ctx, FZ_ERROR_SYNTAX, "incorrect number of shading functions"); } if (funcs > FZ_MAX_COLORS) { funcs = 0; fz_throw(ctx, FZ_ERROR_SYNTAX, "too many shading functions"); } if (type == 1) in = 2; else in = 1; out = 1; for (i = 0; i < funcs; i++) { func[i] = pdf_load_function(ctx, pdf_array_get(ctx, obj, i), in, out); if (!func[i]) fz_throw(ctx, FZ_ERROR_SYNTAX, "cannot load shading function (%d 0 R)", pdf_to_num(ctx, obj)); } } else if (type < 4) { /* Functions are compulsory for types 1,2,3 */ fz_throw(ctx, FZ_ERROR_SYNTAX, "cannot load shading function (%d 0 R)", pdf_to_num(ctx, obj)); } shade->type = type; switch (type) { case 1: pdf_load_function_based_shading(ctx, doc, shade, dict, func[0]); break; case 2: pdf_load_linear_shading(ctx, doc, shade, dict, funcs, func); break; case 3: pdf_load_radial_shading(ctx, doc, shade, dict, funcs, func); break; case 4: pdf_load_type4_shade(ctx, doc, shade, dict, funcs, func); break; case 5: pdf_load_type5_shade(ctx, doc, shade, dict, funcs, func); break; case 6: pdf_load_type6_shade(ctx, doc, shade, dict, funcs, func); break; case 7: pdf_load_type7_shade(ctx, doc, shade, dict, funcs, func); break; default: fz_throw(ctx, FZ_ERROR_SYNTAX, "unknown shading type: %d", type); } } fz_always(ctx) { for (i = 0; i < funcs; i++) pdf_drop_function(ctx, func[i]); } fz_catch(ctx) { fz_drop_shade(ctx, shade); fz_rethrow(ctx); } return shade; }
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)); // fz_convert_pixmap(ctx, gray, image->tile); // 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_image * pdf_load_jpx(pdf_document *doc, pdf_obj *dict, int forcemask) { fz_buffer *buf = NULL; fz_colorspace *colorspace = NULL; fz_pixmap *img = NULL; pdf_obj *obj; fz_context *ctx = doc->ctx; int indexed = 0; fz_image *mask = NULL; fz_var(img); fz_var(buf); fz_var(colorspace); fz_var(mask); buf = pdf_load_stream(doc, pdf_to_num(dict), pdf_to_gen(dict)); /* FIXME: We can't handle decode arrays for indexed images currently */ fz_try(ctx) { obj = pdf_dict_gets(dict, "ColorSpace"); if (obj) { colorspace = pdf_load_colorspace(doc, obj); indexed = fz_colorspace_is_indexed(colorspace); } img = fz_load_jpx(ctx, buf->data, buf->len, colorspace, indexed); obj = pdf_dict_getsa(dict, "SMask", "Mask"); if (pdf_is_dict(obj)) { if (forcemask) fz_warn(ctx, "Ignoring recursive JPX soft mask"); else mask = pdf_load_image_imp(doc, NULL, obj, NULL, 1); } obj = pdf_dict_getsa(dict, "Decode", "D"); if (obj && !indexed) { float decode[FZ_MAX_COLORS * 2]; int i; for (i = 0; i < img->n * 2; i++) decode[i] = pdf_to_real(pdf_array_get(obj, i)); fz_decode_tile(img, decode); } } fz_always(ctx) { fz_drop_colorspace(ctx, colorspace); fz_drop_buffer(ctx, buf); } fz_catch(ctx) { fz_drop_pixmap(ctx, img); fz_rethrow(ctx); } return fz_new_image_from_pixmap(ctx, img, mask); }
static fz_colorspace * load_indexed(pdf_document *xref, pdf_obj *array) { struct indexed *idx = NULL; fz_context *ctx = xref->ctx; pdf_obj *baseobj = pdf_array_get(array, 1); pdf_obj *highobj = pdf_array_get(array, 2); pdf_obj *lookup = pdf_array_get(array, 3); fz_colorspace *base = NULL; fz_colorspace *cs = NULL; int i, n; fz_var(idx); fz_var(base); fz_var(cs); fz_try(ctx) { base = pdf_load_colorspace(xref, baseobj); /* "cannot load base colorspace (%d %d R)", pdf_to_num(baseobj), pdf_to_gen(baseobj) */ idx = fz_malloc_struct(ctx, struct indexed); idx->lookup = NULL; idx->base = base; idx->high = pdf_to_int(highobj); idx->high = CLAMP(idx->high, 0, 255); n = base->n * (idx->high + 1); idx->lookup = fz_malloc_array(ctx, 1, n); cs = fz_new_colorspace(ctx, "Indexed", 1); cs->to_rgb = indexed_to_rgb; cs->free_data = free_indexed; cs->data = idx; cs->size += sizeof(*idx) + n + (base ? base->size : 0); if (pdf_is_string(lookup) && pdf_to_str_len(lookup) == n) { unsigned char *buf = (unsigned char *) pdf_to_str_buf(lookup); for (i = 0; i < n; i++) idx->lookup[i] = buf[i]; } else if (pdf_is_indirect(lookup)) { fz_stream *file = NULL; fz_try(ctx) { file = pdf_open_stream(xref, pdf_to_num(lookup), pdf_to_gen(lookup)); } fz_catch(ctx) { fz_throw(ctx, "cannot open colorspace lookup table (%d 0 R)", pdf_to_num(lookup)); } i = fz_read(file, idx->lookup, n); if (i < 0) { fz_close(file); fz_throw(ctx, "cannot read colorspace lookup table (%d 0 R)", pdf_to_num(lookup)); } fz_close(file); } else { fz_throw(ctx, "cannot parse colorspace lookup table"); } }
static fz_error load_indexed(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) { fz_error error; fz_colorspace *cs; struct indexed *idx; fz_obj *baseobj = fz_array_get(array, 1); fz_obj *highobj = fz_array_get(array, 2); fz_obj *lookup = fz_array_get(array, 3); fz_colorspace *base; int i, n; error = pdf_load_colorspace(&base, xref, baseobj); if (error) return fz_rethrow(error, "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj)); idx = fz_malloc(sizeof(struct indexed)); idx->base = base; idx->high = fz_to_int(highobj); idx->high = CLAMP(idx->high, 0, 255); n = base->n * (idx->high + 1); idx->lookup = fz_malloc(n); memset(idx->lookup, 0, n); cs = fz_new_colorspace("Indexed", 1); cs->to_rgb = indexed_to_rgb; cs->free_data = free_indexed; cs->data = idx; if (fz_is_string(lookup) && fz_to_str_len(lookup) == n) { unsigned char *buf = (unsigned char *) fz_to_str_buf(lookup); for (i = 0; i < n; i++) idx->lookup[i] = buf[i]; } else if (fz_is_indirect(lookup)) { fz_stream *file; error = pdf_open_stream(&file, xref, fz_to_num(lookup), fz_to_gen(lookup)); if (error) { fz_drop_colorspace(cs); return fz_rethrow(error, "cannot open colorspace lookup table (%d 0 R)", fz_to_num(lookup)); } i = fz_read(file, idx->lookup, n); if (i < 0) { fz_drop_colorspace(cs); return fz_throw("cannot read colorspace lookup table (%d 0 R)", fz_to_num(lookup)); } fz_close(file); } else { fz_drop_colorspace(cs); return fz_throw("cannot parse colorspace lookup table"); } *csp = cs; return fz_okay; }
pdf_xobject * pdf_load_xobject(pdf_document *xref, pdf_obj *dict) { pdf_xobject *form; pdf_obj *obj; fz_context *ctx = xref->ctx; if ((form = pdf_find_item(ctx, pdf_free_xobject_imp, dict))) { return form; } form = fz_malloc_struct(ctx, pdf_xobject); FZ_INIT_STORABLE(form, 1, pdf_free_xobject_imp); form->resources = NULL; form->contents = NULL; form->colorspace = NULL; form->me = NULL; /* Store item immediately, to avoid possible recursion if objects refer back to this one */ pdf_store_item(ctx, dict, form, pdf_xobject_size(form)); obj = pdf_dict_gets(dict, "BBox"); form->bbox = pdf_to_rect(ctx, obj); obj = pdf_dict_gets(dict, "Matrix"); if (obj) form->matrix = pdf_to_matrix(ctx, obj); else form->matrix = fz_identity; form->isolated = 0; form->knockout = 0; form->transparency = 0; obj = pdf_dict_gets(dict, "Group"); if (obj) { pdf_obj *attrs = obj; form->isolated = pdf_to_bool(pdf_dict_gets(attrs, "I")); form->knockout = pdf_to_bool(pdf_dict_gets(attrs, "K")); obj = pdf_dict_gets(attrs, "S"); if (pdf_is_name(obj) && !strcmp(pdf_to_name(obj), "Transparency")) form->transparency = 1; obj = pdf_dict_gets(attrs, "CS"); if (obj) { form->colorspace = pdf_load_colorspace(xref, obj); if (!form->colorspace) fz_throw(ctx, "cannot load xobject colorspace"); } } form->resources = pdf_dict_gets(dict, "Resources"); if (form->resources) pdf_keep_obj(form->resources); fz_try(ctx) { form->contents = pdf_load_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); } fz_catch(ctx) { pdf_remove_item(ctx, pdf_free_xobject_imp, dict); pdf_drop_xobject(ctx, form); fz_throw(ctx, "cannot load xobject content stream (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } form->me = pdf_keep_obj(dict); return form; }
static fz_image * pdf_load_image_imp(pdf_document *xref, 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 i; fz_context *ctx = xref->ctx; 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(xref, dict, forcemask); if (forcemask) { fz_pixmap *mask_pixmap; if (image->n != 2) { /* SumatraPDF: ignore invalid JPX softmasks */ fz_warn(ctx, "soft mask must be grayscale"); mask_pixmap = fz_new_pixmap(ctx, NULL, image->tile->w, image->tile->h); fz_clear_pixmap_with_value(ctx, mask_pixmap, 255); } else 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; mask = NULL; if (imagemask) bpc = 1; if (w <= 0) fz_throw(ctx, "image width is zero (or less)"); if (h <= 0) fz_throw(ctx, "image height is zero (or less)"); if (bpc <= 0) fz_throw(ctx, "image depth is zero (or less)"); if (bpc > 16) fz_throw(ctx, "image depth is too large: %d", bpc); if (w > (1 << 16)) fz_throw(ctx, "image is too wide"); if (h > (1 << 16)) fz_throw(ctx, "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(xref, obj); if (!strcmp(colorspace->name, "Indexed")) indexed = 1; 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(xref, rdb, obj, NULL, 1); } 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)); } } /* Now, do we load a ref, or do we load the actual thing? */ if (!cstm) { /* 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); fz_compressed_buffer *buffer = pdf_load_compressed_stream(xref, num, gen); image = fz_new_image(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, usecolorkey ? colorkey : NULL, buffer, mask); break; /* Out of fz_try */ } /* We need to decompress the image now */ if (cstm) { int stride = (w * n * bpc + 7) / 8; stm = pdf_open_inline_stream(xref, dict, stride * h, cstm, NULL); } else { stm = pdf_open_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); } image = fz_new_image(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, usecolorkey ? colorkey : NULL, NULL, mask); image->tile = fz_decomp_image_from_stream(ctx, stm, image, cstm != NULL, indexed, 0, 0); } fz_catch(ctx) { /* SumatraPDF: fix memory leak */ if (!image) fz_drop_colorspace(ctx, colorspace); else fz_drop_image(ctx, image); fz_rethrow(ctx); } /* cf. http://bugs.ghostscript.com/show_bug.cgi?id=693517 */ fz_try(ctx) { obj = pdf_dict_getp(dict, "SMask/Matte"); if (pdf_is_array(obj) && image->mask) { assert(!image->usecolorkey); image->usecolorkey = 2; for (i = 0; i < n; i++) image->colorkey[i] = pdf_to_int(pdf_array_get(obj, i)); } } fz_catch(ctx) { fz_drop_image(ctx, image); fz_rethrow(ctx); } return image; }
static void pdf_load_jpx(pdf_document *xref, pdf_obj *dict, pdf_image *image, int forcemask) { fz_buffer *buf = NULL; fz_colorspace *colorspace = NULL; fz_pixmap *img = NULL; pdf_obj *obj; fz_context *ctx = xref->ctx; int indexed = 0; fz_var(img); fz_var(buf); fz_var(colorspace); buf = pdf_load_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); /* FIXME: We can't handle decode arrays for indexed images currently */ fz_try(ctx) { obj = pdf_dict_gets(dict, "ColorSpace"); if (obj) { colorspace = pdf_load_colorspace(xref, obj); indexed = !strcmp(colorspace->name, "Indexed"); } img = fz_load_jpx(ctx, buf->data, buf->len, colorspace, indexed); if (img && colorspace == NULL) colorspace = fz_keep_colorspace(ctx, img->colorspace); fz_drop_buffer(ctx, buf); buf = NULL; obj = pdf_dict_getsa(dict, "SMask", "Mask"); if (pdf_is_dict(obj)) { if (forcemask) fz_warn(ctx, "Ignoring recursive JPX soft mask"); else image->base.mask = (fz_image *)pdf_load_image_imp(xref, NULL, obj, NULL, 1); } obj = pdf_dict_getsa(dict, "Decode", "D"); if (obj && !indexed) { float decode[FZ_MAX_COLORS * 2]; int i; for (i = 0; i < img->n * 2; i++) decode[i] = pdf_to_real(pdf_array_get(obj, i)); fz_decode_tile(img, decode); } } fz_catch(ctx) { if (colorspace) fz_drop_colorspace(ctx, colorspace); fz_drop_buffer(ctx, buf); fz_drop_pixmap(ctx, img); fz_rethrow(ctx); } FZ_INIT_STORABLE(&image->base, 1, pdf_free_image); image->base.get_pixmap = pdf_image_get_pixmap; image->base.w = img->w; image->base.h = img->h; image->base.bpc = 8; image->base.colorspace = colorspace; image->buffer = NULL; image->tile = img; image->n = img->n; image->interpolate = 0; image->imagemask = 0; image->usecolorkey = 0; }
static fz_image * pdf_load_jpx(fz_context *ctx, pdf_document *doc, pdf_obj *dict, int forcemask) { fz_buffer *buf = NULL; fz_colorspace *colorspace = NULL; fz_pixmap *pix = NULL; pdf_obj *obj; fz_image *mask = NULL; fz_image *img = NULL; fz_var(pix); fz_var(buf); fz_var(colorspace); fz_var(mask); buf = pdf_load_stream(ctx, dict); /* FIXME: We can't handle decode arrays for indexed images currently */ fz_try(ctx) { unsigned char *data; size_t len; obj = pdf_dict_get(ctx, dict, PDF_NAME(ColorSpace)); if (obj) colorspace = pdf_load_colorspace(ctx, obj); len = fz_buffer_storage(ctx, buf, &data); pix = fz_load_jpx(ctx, data, len, colorspace); obj = pdf_dict_geta(ctx, dict, PDF_NAME(SMask), PDF_NAME(Mask)); if (pdf_is_dict(ctx, obj)) { if (forcemask) fz_warn(ctx, "Ignoring recursive JPX soft mask"); else mask = pdf_load_image_imp(ctx, doc, NULL, obj, NULL, 1); } obj = pdf_dict_geta(ctx, dict, PDF_NAME(Decode), PDF_NAME(D)); if (obj && !fz_colorspace_is_indexed(ctx, colorspace)) { float decode[FZ_MAX_COLORS * 2]; int i; for (i = 0; i < pix->n * 2; i++) decode[i] = pdf_array_get_real(ctx, obj, i); fz_decode_tile(ctx, pix, decode); } img = fz_new_image_from_pixmap(ctx, pix, mask); } fz_always(ctx) { fz_drop_image(ctx, mask); fz_drop_pixmap(ctx, pix); fz_drop_colorspace(ctx, colorspace); fz_drop_buffer(ctx, buf); } fz_catch(ctx) { fz_rethrow(ctx); } return img; }