diff options
Diffstat (limited to 'pdf')
-rw-r--r-- | pdf/mupdf.h | 94 | ||||
-rw-r--r-- | pdf/pdf_cmap_load.c | 4 | ||||
-rw-r--r-- | pdf/pdf_colorspace.c | 4 | ||||
-rw-r--r-- | pdf/pdf_font.c | 4 | ||||
-rw-r--r-- | pdf/pdf_function.c | 4 | ||||
-rw-r--r-- | pdf/pdf_image.c | 474 | ||||
-rw-r--r-- | pdf/pdf_interpret.c | 15 | ||||
-rw-r--r-- | pdf/pdf_pattern.c | 6 | ||||
-rw-r--r-- | pdf/pdf_shade.c | 4 | ||||
-rw-r--r-- | pdf/pdf_store.c | 59 | ||||
-rw-r--r-- | pdf/pdf_stream.c | 130 | ||||
-rw-r--r-- | pdf/pdf_xobject.c | 6 |
12 files changed, 624 insertions, 180 deletions
diff --git a/pdf/mupdf.h b/pdf/mupdf.h index 39245177..b233288f 100644 --- a/pdf/mupdf.h +++ b/pdf/mupdf.h @@ -5,6 +5,83 @@ #error "fitz.h must be included before mupdf.h" #endif +/* + * PDF Images + */ + +typedef struct pdf_image_params_s pdf_image_params; + +struct pdf_image_params_s +{ + int type; + fz_colorspace *colorspace; + union + { + struct + { + int columns; + int rows; + int k; + int eol; + int eba; + int eob; + int bi1; + } + fax; + struct + { + int ct; + } + jpeg; + struct + { + int columns; + int colors; + int predictor; + int bpc; + } + flate; + struct + { + int columns; + int colors; + int predictor; + int bpc; + int ec; + } + lzw; + } + u; +}; + + +typedef struct pdf_image_s pdf_image; + +struct pdf_image_s +{ + fz_image base; + fz_pixmap *tile; + int n, bpc; + pdf_image_params params; + fz_buffer *buffer; + int colorkey[FZ_MAX_COLORS * 2]; + float decode[FZ_MAX_COLORS * 2]; + int imagemask; + int interpolate; + int usecolorkey; +}; + +enum +{ + PDF_IMAGE_RAW, + PDF_IMAGE_FAX, + PDF_IMAGE_JPEG, + PDF_IMAGE_RLD, + PDF_IMAGE_FLATE, + PDF_IMAGE_LZW, + PDF_IMAGE_JPX +}; + typedef struct pdf_document_s pdf_document; /* @@ -102,12 +179,15 @@ fz_obj *pdf_load_object(pdf_document *doc, int num, int gen); void pdf_update_object(pdf_document *doc, int num, int gen, fz_obj *newobj); int pdf_is_stream(pdf_document *doc, int num, int gen); -fz_stream *pdf_open_inline_stream(pdf_document *doc, fz_obj *stmobj, int length, fz_stream *chain); +fz_stream *pdf_open_inline_stream(pdf_document *doc, fz_obj *stmobj, int length, fz_stream *chain, pdf_image_params *params); fz_buffer *pdf_load_raw_stream(pdf_document *doc, int num, int gen); fz_buffer *pdf_load_stream(pdf_document *doc, int num, int gen); +fz_buffer *pdf_load_image_stream(pdf_document *doc, int num, int gen, pdf_image_params *params); fz_stream *pdf_open_raw_stream(pdf_document *doc, int num, int gen); +fz_stream *pdf_open_image_stream(pdf_document *doc, int num, int gen, pdf_image_params *params); fz_stream *pdf_open_stream(pdf_document *doc, int num, int gen); fz_stream *pdf_open_stream_with_offset(pdf_document *doc, int num, int gen, fz_obj *dict, int stm_ofs); +fz_stream *pdf_open_image_decomp_stream(fz_context *ctx, fz_buffer *, pdf_image_params *params, int *factor); pdf_document *pdf_open_document_with_stream(fz_stream *file); pdf_document *pdf_open_document(fz_context *ctx, const char *filename); @@ -171,8 +251,8 @@ fz_pixmap *pdf_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src); fz_shade *pdf_load_shading(pdf_document *doc, fz_obj *obj); -fz_pixmap *pdf_load_inline_image(pdf_document *doc, fz_obj *rdb, fz_obj *dict, fz_stream *file); -fz_pixmap *pdf_load_image(pdf_document *doc, fz_obj *obj); +fz_image *pdf_load_inline_image(pdf_document *doc, fz_obj *rdb, fz_obj *dict, fz_stream *file); +fz_image *pdf_load_image(pdf_document *doc, fz_obj *obj); int pdf_is_jpx_image(fz_context *ctx, fz_obj *dict); /* @@ -471,4 +551,12 @@ void pdf_run_page_with_usage(pdf_document *doc, pdf_page *page, fz_device *dev, void pdf_run_page(pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie); void pdf_run_glyph(pdf_document *doc, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate); +/* + * PDF interface to store + */ + +void pdf_store_item(fz_context *ctx, fz_obj *key, void *val, unsigned int itemsize); +void *pdf_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key); +void pdf_remove_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key); + #endif diff --git a/pdf/pdf_cmap_load.c b/pdf/pdf_cmap_load.c index 3257516c..9e6b13ce 100644 --- a/pdf/pdf_cmap_load.c +++ b/pdf/pdf_cmap_load.c @@ -31,7 +31,7 @@ pdf_load_embedded_cmap(pdf_document *xref, fz_obj *stmobj) fz_var(file); fz_var(cmap); - if ((cmap = fz_find_item(ctx, pdf_free_cmap_imp, stmobj))) + if ((cmap = pdf_find_item(ctx, pdf_free_cmap_imp, stmobj))) { return cmap; } @@ -63,7 +63,7 @@ pdf_load_embedded_cmap(pdf_document *xref, fz_obj *stmobj) pdf_drop_cmap(ctx, usecmap); } - fz_store_item(ctx, stmobj, cmap, pdf_cmap_size(ctx, cmap)); + pdf_store_item(ctx, stmobj, cmap, pdf_cmap_size(ctx, cmap)); } fz_catch(ctx) { diff --git a/pdf/pdf_colorspace.c b/pdf/pdf_colorspace.c index 7a410df8..a6515d42 100644 --- a/pdf/pdf_colorspace.c +++ b/pdf/pdf_colorspace.c @@ -395,7 +395,7 @@ pdf_load_colorspace(pdf_document *xref, fz_obj *obj) fz_context *ctx = xref->ctx; fz_colorspace *cs; - if ((cs = fz_find_item(ctx, fz_free_colorspace_imp, obj))) + if ((cs = pdf_find_item(ctx, fz_free_colorspace_imp, obj))) { return cs; } @@ -403,7 +403,7 @@ pdf_load_colorspace(pdf_document *xref, fz_obj *obj) cs = pdf_load_colorspace_imp(xref, obj); /* RJW: "cannot load colorspace (%d %d R)", fz_to_num(obj), fz_to_gen(obj) */ - fz_store_item(ctx, obj, cs, cs->size); + pdf_store_item(ctx, obj, cs, cs->size); return cs; } diff --git a/pdf/pdf_font.c b/pdf/pdf_font.c index 3e30c332..fd2afab2 100644 --- a/pdf/pdf_font.c +++ b/pdf/pdf_font.c @@ -1081,7 +1081,7 @@ pdf_load_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict) fz_context *ctx = xref->ctx; pdf_font_desc *fontdesc; - if ((fontdesc = fz_find_item(ctx, pdf_free_font_imp, dict))) + if ((fontdesc = pdf_find_item(ctx, pdf_free_font_imp, dict))) { return fontdesc; } @@ -1121,7 +1121,7 @@ pdf_load_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict) if (fontdesc->font->ft_substitute && !fontdesc->to_ttf_cmap) pdf_make_width_table(ctx, fontdesc); - fz_store_item(ctx, dict, fontdesc, fontdesc->size); + pdf_store_item(ctx, dict, fontdesc, fontdesc->size); return fontdesc; } diff --git a/pdf/pdf_function.c b/pdf/pdf_function.c index 23acc4db..4478827c 100644 --- a/pdf/pdf_function.c +++ b/pdf/pdf_function.c @@ -1362,7 +1362,7 @@ pdf_load_function(pdf_document *xref, fz_obj *dict) fz_obj *obj; int i; - if ((func = fz_find_item(ctx, pdf_free_function_imp, dict))) + if ((func = pdf_find_item(ctx, pdf_free_function_imp, dict))) { return func; } @@ -1432,7 +1432,7 @@ pdf_load_function(pdf_document *xref, fz_obj *dict) fz_throw(ctx, "unknown function type (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); } - fz_store_item(ctx, dict, func, func->size); + pdf_store_item(ctx, dict, func, func->size); } fz_catch(ctx) { diff --git a/pdf/pdf_image.c b/pdf/pdf_image.c index 3aa26f08..9626d6f0 100644 --- a/pdf/pdf_image.c +++ b/pdf/pdf_image.c @@ -1,10 +1,15 @@ #include "fitz.h" #include "mupdf.h" -/* TODO: store JPEG compressed samples */ -/* TODO: store flate compressed samples */ +typedef struct pdf_image_key_s pdf_image_key; -static fz_pixmap *pdf_load_jpx(pdf_document *xref, fz_obj *dict); +struct pdf_image_key_s { + int refs; + fz_image *image; + int factor; +}; + +static void pdf_load_jpx(pdf_document *xref, fz_obj *dict, pdf_image *image); static void pdf_mask_color_key(fz_pixmap *pix, int n, int *colorkey) @@ -25,49 +30,293 @@ pdf_mask_color_key(fz_pixmap *pix, int n, int *colorkey) } } +static int +pdf_make_hash_image_key(fz_store_hash *hash, void *key_) +{ + pdf_image_key *key = (pdf_image_key *)key_; + + hash->u.pi.ptr = key->image; + hash->u.pi.i = key->factor; + return 1; +} + +static void * +pdf_keep_image_key(fz_context *ctx, void *key_) +{ + pdf_image_key *key = (pdf_image_key *)key_; + + fz_lock(ctx, FZ_LOCK_ALLOC); + key->refs++; + fz_unlock(ctx, FZ_LOCK_ALLOC); + + return (void *)key; +} + +static void +pdf_drop_image_key(fz_context *ctx, void *key_) +{ + pdf_image_key *key = (pdf_image_key *)key_; + int drop; + + fz_lock(ctx, FZ_LOCK_ALLOC); + drop = --key->refs; + fz_unlock(ctx, FZ_LOCK_ALLOC); + if (drop == 0) + { + fz_drop_image(ctx, key->image); + fz_free(ctx, key); + } +} + +static int +pdf_cmp_image_key(void *k0_, void *k1_) +{ + pdf_image_key *k0 = (pdf_image_key *)k0_; + pdf_image_key *k1 = (pdf_image_key *)k1_; + + return k0->image == k1->image && k0->factor == k1->factor; +} + +static fz_store_type pdf_image_store_type = +{ + pdf_make_hash_image_key, + pdf_keep_image_key, + pdf_drop_image_key, + pdf_cmp_image_key +}; + static fz_pixmap * +decomp_image_from_stream(fz_context *ctx, fz_stream *stm, pdf_image *image, int in_line, int indexed, int factor) +{ + fz_pixmap *tile = NULL; + fz_pixmap *existing_tile; + int stride, len, i; + unsigned char *samples = NULL; + int w = (image->base.w + (factor-1)) / factor; + int h = (image->base.h + (factor-1)) / factor; + pdf_image_key *key; + + fz_var(tile); + fz_var(samples); + + fz_try(ctx) + { + tile = fz_new_pixmap(ctx, image->base.colorspace, w, h); + tile->mask = fz_image_to_pixmap(ctx, image->base.mask, w, h); + tile->interpolate = image->interpolate; + + stride = (w * image->n * image->bpc + 7) / 8; + + samples = fz_malloc_array(ctx, h, stride); + + len = fz_read(stm, samples, h * stride); + if (len < 0) + { + fz_throw(ctx, "cannot read image data"); + } + + /* Make sure we read the EOF marker (for inline images only) */ + if (in_line) + { + unsigned char tbuf[512]; + fz_try(ctx) + { + int tlen = fz_read(stm, tbuf, sizeof tbuf); + if (tlen > 0) + fz_warn(ctx, "ignoring garbage at end of image"); + } + fz_catch(ctx) + { + fz_warn(ctx, "ignoring error at end of image"); + } + } + + /* Pad truncated images */ + if (len < stride * h) + { + fz_warn(ctx, "padding truncated image"); + memset(samples + len, 0, stride * h - len); + } + + /* Invert 1-bit image masks */ + if (image->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, image->n, image->bpc, stride, indexed); + + fz_free(ctx, samples); + samples = NULL; + + if (image->usecolorkey) + pdf_mask_color_key(tile, image->n, image->colorkey); + + if (indexed) + { + fz_pixmap *conv; + fz_decode_indexed_tile(tile, image->decode, (1 << image->bpc) - 1); + conv = pdf_expand_indexed_pixmap(ctx, tile); + fz_drop_pixmap(ctx, tile); + tile = conv; + } + else + { + fz_decode_tile(tile, image->decode); + } + } + fz_always(ctx) + { + fz_close(stm); + } + fz_catch(ctx) + { + if (tile) + fz_drop_pixmap(ctx, tile); + fz_free(ctx, samples); + + fz_rethrow(ctx); + } + + /* Now we try to cache the pixmap. Any failure here will just result + * in us not caching. */ + fz_try(ctx) + { + key = fz_malloc_struct(ctx, pdf_image_key); + key->refs = 1; + key->image = fz_keep_image(ctx, &image->base); + key->factor = factor; + existing_tile = fz_store_item(ctx, key, tile, fz_pixmap_size(ctx, tile), &pdf_image_store_type); + if (existing_tile) + { + /* We already have a tile. This must have been produced by a + * racing thread. We'll throw away ours and use that one. */ + fz_drop_pixmap(ctx, tile); + fz_free(ctx, key); + tile = existing_tile; + } + } + fz_always(ctx) + { + pdf_drop_image_key(ctx, key); + } + fz_catch(ctx) + { + /* Do nothing */ + } + + return tile; +} + +static void +pdf_free_image(fz_context *ctx, fz_storable *image_) +{ + pdf_image *image = (pdf_image *)image_; + + if (image == NULL) + return; + fz_drop_pixmap(ctx, image->tile); + fz_drop_buffer(ctx, image->buffer); + fz_drop_colorspace(ctx, image->base.colorspace); + fz_drop_image(ctx, image->base.mask); + fz_free(ctx, image); +} + +static fz_pixmap * +pdf_image_get_pixmap(fz_context *ctx, fz_image *image_, int w, int h) +{ + pdf_image *image = (pdf_image *)image_; + fz_pixmap *tile; + fz_stream *stm; + int factor; + pdf_image_key key; + + /* Check for 'simple' images which are just pixmaps */ + if (image->buffer == NULL) + { + tile = image->tile; + if (!tile) + return NULL; + if (image->base.mask) + { + fz_drop_pixmap(ctx, tile->mask); + tile->mask = fz_image_to_pixmap(ctx, image->base.mask, w, h); + } + return fz_keep_pixmap(ctx, tile); /* That's all we can give you! */ + } + + /* Ensure our expectations for tile size are reasonable */ + if (w > image->base.w) + w = image->base.w; + if (h > image->base.h) + h = image->base.h; + + /* What is our ideal factor? */ + if (w == 0 || h == 0) + factor = 1; + else + for (factor=1; image->base.w/(2*factor) >= w && image->base.h/(2*factor) >= h && factor < 8; factor *= 2); + + /* Can we find any suitable tiles in the cache? */ + key.refs = 1; + key.image = &image->base; + key.factor = factor; + do + { + tile = fz_find_item(ctx, fz_free_pixmap_imp, &key, &pdf_image_store_type); + if (tile) + return tile; + key.factor >>= 1; + } + while (key.factor > 0); + + /* We need to make a new one. */ + stm = pdf_open_image_decomp_stream(ctx, image->buffer, &image->params, &factor); + + return decomp_image_from_stream(ctx, stm, image, 0, 0, factor); +} + +static pdf_image * pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cstm, int forcemask) { fz_stream *stm = NULL; - fz_pixmap *tile = NULL; + pdf_image *image = NULL; fz_obj *obj, *res; int w, h, bpc, n; int imagemask; int interpolate; int indexed; - fz_colorspace *colorspace = NULL; - fz_pixmap *mask = NULL; /* explicit mask/softmask image */ + fz_image *mask = NULL; /* explicit mask/softmask image */ int usecolorkey; - int colorkey[FZ_MAX_COLORS * 2]; - float decode[FZ_MAX_COLORS * 2]; - int stride; - unsigned char *samples = NULL; - int i, len; + int i; fz_context *ctx = xref->ctx; fz_var(stm); - fz_var(tile); - fz_var(colorspace); fz_var(mask); - fz_var(samples); + + image = fz_malloc_struct(ctx, pdf_image); fz_try(ctx) { /* special case for JPEG2000 images */ if (pdf_is_jpx_image(ctx, dict)) { - tile = pdf_load_jpx(xref, dict); + pdf_load_jpx(xref, dict, image); /* RJW: "cannot load jpx image" */ if (forcemask) { - if (tile->n != 2) + fz_pixmap *mask_pixmap; + if (image->n != 2) fz_throw(ctx, "softmask must be grayscale"); - mask = fz_alpha_from_gray(ctx, tile, 1); - fz_drop_pixmap(ctx, tile); - tile = mask; - mask = NULL; + 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 */ } @@ -109,13 +358,13 @@ pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cst obj = res; } - colorspace = pdf_load_colorspace(xref, obj); + image->base.colorspace = pdf_load_colorspace(xref, obj); /* RJW: "cannot load image colorspace" */ - if (!strcmp(colorspace->name, "Indexed")) + if (!strcmp(image->base.colorspace->name, "Indexed")) indexed = 1; - n = colorspace->n; + n = image->base.colorspace->n; } else { @@ -126,13 +375,13 @@ pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cst if (obj) { for (i = 0; i < n * 2; i++) - decode[i] = fz_to_real(fz_array_get(obj, i)); + image->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; + image->decode[i] = i & 1 ? maxval : 0; } obj = fz_dict_getsa(dict, "SMask", "Mask"); @@ -141,7 +390,7 @@ pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cst /* Not allowed for inline images */ if (!cstm) { - mask = pdf_load_image_imp(xref, rdb, obj, NULL, 1); + mask = (fz_image *)pdf_load_image_imp(xref, rdb, obj, NULL, 1); /* RJW: "cannot load image mask/softmask" */ } } @@ -155,36 +404,36 @@ pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cst fz_warn(ctx, "invalid value in color key mask"); usecolorkey = 0; } - colorkey[i] = fz_to_int(fz_array_get(obj, i)); + image->colorkey[i] = fz_to_int(fz_array_get(obj, i)); } } - /* Allocate now, to fail early if we run out of memory */ - fz_try(ctx) - { - tile = fz_new_pixmap(ctx, colorspace, w, h); - } - fz_catch(ctx) + /* Now, do we load a ref, or do we load the actual thing? */ + image->params.type = PDF_IMAGE_RAW; + 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->n = n; + image->bpc = bpc; + image->interpolate = interpolate; + image->imagemask = imagemask; + image->usecolorkey = usecolorkey; + image->base.mask = mask; + image->params.colorspace = image->base.colorspace; /* Uses the same ref as for the base one */ + if (!indexed && !cstm) { - fz_drop_colorspace(ctx, colorspace); - fz_rethrow(ctx); - } - - if (colorspace) - { - fz_drop_colorspace(ctx, colorspace); - colorspace = NULL; + /* Just load the compressed image data now and we can + * decode it on demand. */ + image->buffer = pdf_load_image_stream(xref, fz_to_num(dict), fz_to_gen(dict), &image->params); + break; /* Out of fz_try */ } - tile->mask = mask; - mask = NULL; - tile->interpolate = interpolate; - - stride = (w * n * bpc + 7) / 8; - + /* We need to decompress the image now */ if (cstm) { - stm = pdf_open_inline_stream(xref, dict, stride * h, cstm); + int stride = (w * image->n * image->bpc + 7) / 8; + stm = pdf_open_inline_stream(xref, dict, stride * h, cstm, NULL); } else { @@ -192,92 +441,20 @@ pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cst /* RJW: "cannot open image data stream (%d 0 R)", fz_to_num(dict) */ } - samples = fz_malloc_array(ctx, h, stride); - - len = fz_read(stm, samples, h * stride); - if (len < 0) - { - fz_throw(ctx, "cannot read image data"); - } - - /* Make sure we read the EOF marker (for inline images only) */ - if (cstm) - { - unsigned char tbuf[512]; - fz_try(ctx) - { - int tlen = fz_read(stm, tbuf, sizeof tbuf); - if (tlen > 0) - fz_warn(ctx, "ignoring garbage at end of image"); - } - fz_catch(ctx) - { - fz_warn(ctx, "ignoring error at end of image"); - } - } - - fz_close(stm); - stm = NULL; - - /* Pad truncated images */ - if (len < stride * h) - { - fz_warn(ctx, "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(ctx, samples); - samples = NULL; - - 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(ctx, tile); - fz_drop_pixmap(ctx, tile); - tile = conv; - } - else - { - fz_decode_tile(tile, decode); - } + image->tile = decomp_image_from_stream(ctx, stm, image, cstm != NULL, indexed, 1); } fz_catch(ctx) { - if (colorspace) - fz_drop_colorspace(ctx, colorspace); - if (mask) - fz_drop_pixmap(ctx, mask); - if (tile) - fz_drop_pixmap(ctx, tile); - fz_close(stm); - fz_free(ctx, samples); - + fz_drop_image(ctx, &image->base); fz_rethrow(ctx); } - - return tile; + return image; } -fz_pixmap * +fz_image * pdf_load_inline_image(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *file) { - return pdf_load_image_imp(xref, rdb, dict, file, 0); + return (fz_image *)pdf_load_image_imp(xref, rdb, dict, file, 0); /* RJW: "cannot load inline image" */ } @@ -297,8 +474,8 @@ pdf_is_jpx_image(fz_context *ctx, fz_obj *dict) return 0; } -static fz_pixmap * -pdf_load_jpx(pdf_document *xref, fz_obj *dict) +static void +pdf_load_jpx(pdf_document *xref, fz_obj *dict, pdf_image *image) { fz_buffer *buf = NULL; fz_colorspace *colorspace = NULL; @@ -328,18 +505,13 @@ pdf_load_jpx(pdf_document *xref, fz_obj *dict) img = fz_load_jpx(ctx, buf->data, buf->len, colorspace); /* RJW: "cannot load jpx image" */ - if (colorspace) - { - fz_drop_colorspace(ctx, colorspace); - colorspace = NULL; - } fz_drop_buffer(ctx, buf); buf = NULL; obj = fz_dict_getsa(dict, "SMask", "Mask"); if (fz_is_dict(obj)) { - img->mask = pdf_load_image_imp(xref, NULL, obj, NULL, 1); + image->base.mask = (fz_image *)pdf_load_image_imp(xref, NULL, obj, NULL, 1); /* RJW: "cannot load image mask/softmask" */ } @@ -363,24 +535,44 @@ pdf_load_jpx(pdf_document *xref, fz_obj *dict) fz_drop_pixmap(ctx, img); fz_rethrow(ctx); } - return img; + image->params.type = PDF_IMAGE_RAW; + 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.colorspace = colorspace; + image->tile = img; + image->n = img->n; + image->bpc = 8; + image->interpolate = 0; + image->imagemask = 0; + image->usecolorkey = 0; + image->params.colorspace = colorspace; /* Uses the same ref as for the base one */ +} + +static int +pdf_image_size(fz_context *ctx, pdf_image *im) +{ + if (im == NULL) + return 0; + return sizeof(*im) + fz_pixmap_size(ctx, im->tile) + (im->buffer ? im->buffer->cap : 0); } -fz_pixmap * +fz_image * pdf_load_image(pdf_document *xref, fz_obj *dict) { fz_context *ctx = xref->ctx; - fz_pixmap *pix; + pdf_image *image; - if ((pix = fz_find_item(ctx, fz_free_pixmap_imp, dict))) + if ((image = pdf_find_item(ctx, pdf_free_image, dict))) { - return pix; + return (fz_image *)image; } - pix = pdf_load_image_imp(xref, NULL, dict, NULL, 0); + image = pdf_load_image_imp(xref, NULL, dict, NULL, 0); /* RJW: "cannot load image (%d 0 R)", fz_to_num(dict) */ - fz_store_item(ctx, dict, pix, fz_pixmap_size(ctx, pix)); + pdf_store_item(ctx, dict, image, pdf_image_size(ctx, image)); - return pix; + return (fz_image *)image; } diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c index ea7f7692..effea657 100644 --- a/pdf/pdf_interpret.c +++ b/pdf/pdf_interpret.c @@ -362,7 +362,7 @@ pdf_show_shade(pdf_csi *csi, fz_shade *shd) } static void -pdf_show_image(pdf_csi *csi, fz_pixmap *image) +pdf_show_image(pdf_csi *csi, fz_image *image) { pdf_gstate *gstate = csi->gstate + csi->gtop; fz_matrix image_ctm; @@ -1627,7 +1627,7 @@ static void pdf_run_BI(pdf_csi *csi, fz_obj *rdb, fz_stream *file) int ch; char *buf = csi->xref->scratch; int buflen = sizeof(csi->xref->scratch); - fz_pixmap *img; + fz_image *img; fz_obj *obj; obj = pdf_parse_dict(csi->xref, file, buf, buflen); @@ -1645,7 +1645,7 @@ static void pdf_run_BI(pdf_csi *csi, fz_obj *rdb, fz_stream *file) pdf_show_image(csi, img); - fz_drop_pixmap(ctx, img); + fz_drop_image(ctx, img); /* find EI */ ch = fz_read_byte(file); @@ -1798,19 +1798,20 @@ static void pdf_run_Do(pdf_csi *csi, fz_obj *rdb) { if ((csi->dev->hints & FZ_IGNORE_IMAGE) == 0) { - fz_pixmap *img; - img = pdf_load_image(csi->xref, obj); + fz_image *img = pdf_load_image(csi->xref, obj); /* RJW: "cannot load image (%d %d R)", fz_to_num(obj), fz_to_gen(obj) */ fz_try(ctx) { pdf_show_image(csi, img); } + fz_always(ctx) + { + fz_drop_image(ctx, img); + } fz_catch(ctx) { - fz_drop_pixmap(ctx, img); fz_rethrow(ctx); } - fz_drop_pixmap(ctx, img); } } diff --git a/pdf/pdf_pattern.c b/pdf/pdf_pattern.c index 9ffbee02..c1869474 100644 --- a/pdf/pdf_pattern.c +++ b/pdf/pdf_pattern.c @@ -40,7 +40,7 @@ pdf_load_pattern(pdf_document *xref, fz_obj *dict) fz_obj *obj; fz_context *ctx = xref->ctx; - if ((pat = fz_find_item(ctx, pdf_free_pattern_imp, dict))) + if ((pat = pdf_find_item(ctx, pdf_free_pattern_imp, dict))) { return pat; } @@ -51,7 +51,7 @@ pdf_load_pattern(pdf_document *xref, fz_obj *dict) pat->contents = NULL; /* Store pattern now, to avoid possible recursion if objects refer back to this one */ - fz_store_item(ctx, dict, pat, pdf_pattern_size(pat)); + pdf_store_item(ctx, dict, pat, pdf_pattern_size(pat)); pat->ismask = fz_to_int(fz_dict_gets(dict, "PaintType")) == 2; pat->xstep = fz_to_real(fz_dict_gets(dict, "XStep")); @@ -76,7 +76,7 @@ pdf_load_pattern(pdf_document *xref, fz_obj *dict) } fz_catch(ctx) { - fz_remove_item(ctx, pdf_free_pattern_imp, dict); + pdf_remove_item(ctx, pdf_free_pattern_imp, dict); pdf_drop_pattern(ctx, pat); fz_throw(ctx, "cannot load pattern stream (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); } diff --git a/pdf/pdf_shade.c b/pdf/pdf_shade.c index fb5dd72c..1be2bb15 100644 --- a/pdf/pdf_shade.c +++ b/pdf/pdf_shade.c @@ -1100,7 +1100,7 @@ pdf_load_shading(pdf_document *xref, fz_obj *dict) fz_context *ctx = xref->ctx; fz_shade *shade; - if ((shade = fz_find_item(ctx, fz_free_shade_imp, dict))) + if ((shade = pdf_find_item(ctx, fz_free_shade_imp, dict))) { return shade; } @@ -1138,7 +1138,7 @@ pdf_load_shading(pdf_document *xref, fz_obj *dict) /* RJW: "cannot load shading dictionary (%d %d R)", fz_to_num(dict), fz_to_gen(dict) */ } - fz_store_item(ctx, dict, shade, fz_shade_size(shade)); + pdf_store_item(ctx, dict, shade, fz_shade_size(shade)); return shade; } diff --git a/pdf/pdf_store.c b/pdf/pdf_store.c new file mode 100644 index 00000000..4f51526d --- /dev/null +++ b/pdf/pdf_store.c @@ -0,0 +1,59 @@ +#include "fitz.h" +#include "mupdf.h" + +static int +pdf_make_hash_key(fz_store_hash *hash, void *key_) +{ + fz_obj *key = (fz_obj *)key_; + + if (!fz_is_indirect(key)) + return 0; + hash->u.i.i0 = fz_to_num(key); + hash->u.i.i1 = fz_to_gen(key); + return 1; +} + +static void * +pdf_keep_key(fz_context *ctx, void *key) +{ + return (void *)fz_keep_obj((fz_obj *)key); +} + +static void +pdf_drop_key(fz_context *ctx, void *key) +{ + fz_drop_obj((fz_obj *)key); +} + +static int +pdf_cmp_key(void *k0, void *k1) +{ + return fz_objcmp((fz_obj *)k0, (fz_obj *)k1); +} + +static fz_store_type pdf_obj_store_type = +{ + pdf_make_hash_key, + pdf_keep_key, + pdf_drop_key, + pdf_cmp_key +}; + +void +pdf_store_item(fz_context *ctx, fz_obj *key, void *val, unsigned int itemsize) +{ + fz_store_item(ctx, key, val, itemsize, &pdf_obj_store_type); +} + +void * +pdf_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key) +{ + return fz_find_item(ctx, free, key, &pdf_obj_store_type); +} + +void +pdf_remove_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key) +{ + fz_remove_item(ctx, free, key, &pdf_obj_store_type); +} + diff --git a/pdf/pdf_stream.c b/pdf/pdf_stream.c index c66e703e..28fc616f 100644 --- a/pdf/pdf_stream.c +++ b/pdf/pdf_stream.c @@ -49,7 +49,7 @@ pdf_stream_has_crypt(fz_context *ctx, fz_obj *stm) * Create a filter given a name and param dictionary. */ static fz_stream * -build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int num, int gen) +build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int num, int gen, pdf_image_params *params) { fz_context *ctx = chain->ctx; char *s = fz_to_name(f); @@ -79,6 +79,19 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int fz_obj *rows = fz_dict_gets(p, "Rows"); fz_obj *eob = fz_dict_gets(p, "EndOfBlock"); fz_obj *bi1 = fz_dict_gets(p, "BlackIs1"); + if (params) + { + /* We will shortstop here */ + params->type = PDF_IMAGE_FAX; + params->u.fax.k = (k ? fz_to_int(k) : 0); + params->u.fax.eol = (eol ? fz_to_bool(eol) : 0); + params->u.fax.eba = (eba ? fz_to_bool(eba) : 0); + params->u.fax.columns = (columns ? fz_to_int(columns) : 1728); + params->u.fax.rows = (rows ? fz_to_int(rows) : 0); + params->u.fax.eob = (eob ? fz_to_bool(eob) : 1); + params->u.fax.bi1 = (bi1 ? fz_to_bool(bi1) : 0); + return chain; + } return fz_open_faxd(chain, k ? fz_to_int(k) : 0, eol ? fz_to_bool(eol) : 0, @@ -92,14 +105,38 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int else if (!strcmp(s, "DCTDecode") || !strcmp(s, "DCT")) { fz_obj *ct = fz_dict_gets(p, "ColorTransform"); + if (params) + { + /* We will shortstop here */ + params->type = PDF_IMAGE_JPEG; + params->u.jpeg.ct = (ct ? fz_to_int(ct) : -1); + return chain; + } return fz_open_dctd(chain, ct ? fz_to_int(ct) : -1); } else if (!strcmp(s, "RunLengthDecode") || !strcmp(s, "RL")) + { + if (params) + { + /* We will shortstop here */ + params->type = PDF_IMAGE_RLD; + return chain; + } return fz_open_rld(chain); - + } else if (!strcmp(s, "FlateDecode") || !strcmp(s, "Fl")) { + if (params) + { + /* We will shortstop here */ + params->type = PDF_IMAGE_FLATE; + params->u.flate.predictor = predictor; + params->u.flate.columns = columns; + params->u.flate.colors = colors; + params->u.flate.bpc = bpc; + return chain; + } chain = fz_open_flated(chain); if (predictor > 1) chain = fz_open_predict(chain, predictor, columns, colors, bpc); @@ -109,6 +146,17 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int else if (!strcmp(s, "LZWDecode") || !strcmp(s, "LZW")) { fz_obj *ec = fz_dict_gets(p, "EarlyChange"); + if (params) + { + /* We will shortstop here */ + params->type = PDF_IMAGE_LZW; + params->u.lzw.predictor = predictor; + params->u.lzw.columns = columns; + params->u.lzw.colors = colors; + params->u.lzw.bpc = bpc; + params->u.lzw.ec = (ec ? fz_to_int(ec) : 1); + return chain; + } chain = fz_open_lzwd(chain, ec ? fz_to_int(ec) : 1); if (predictor > 1) chain = fz_open_predict(chain, predictor, columns, colors, bpc); @@ -155,7 +203,7 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int * Assume ownership of head. */ static fz_stream * -build_filter_chain(fz_stream *chain, pdf_document *xref, fz_obj *fs, fz_obj *ps, int num, int gen) +build_filter_chain(fz_stream *chain, pdf_document *xref, fz_obj *fs, fz_obj *ps, int num, int gen, pdf_image_params *params) { fz_obj *f; fz_obj *p; @@ -166,7 +214,7 @@ build_filter_chain(fz_stream *chain, pdf_document *xref, fz_obj *fs, fz_obj *ps, { f = fz_array_get(fs, i); p = fz_array_get(ps, i); - chain = build_filter(chain, xref, f, p, num, gen); + chain = build_filter(chain, xref, f, p, num, gen, (i == n-1 ? params : NULL)); } return chain; @@ -210,7 +258,7 @@ pdf_open_raw_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int nu * to stream length and decrypting. */ static fz_stream * -pdf_open_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int num, int gen) +pdf_open_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int num, int gen, pdf_image_params *imparams) { fz_obj *filters; fz_obj *params; @@ -221,9 +269,9 @@ pdf_open_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int num, i chain = pdf_open_raw_filter(chain, xref, stmobj, num, gen); if (fz_is_name(filters)) - chain = build_filter(chain, xref, filters, params, num, gen); + chain = build_filter(chain, xref, filters, params, num, gen, imparams); else if (fz_array_len(filters) > 0) - chain = build_filter_chain(chain, xref, filters, params, num, gen); + chain = build_filter_chain(chain, xref, filters, params, num, gen, imparams); fz_lock_stream(chain); return chain; @@ -234,7 +282,7 @@ pdf_open_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int num, i * constraining to stream length, and without decryption. */ fz_stream * -pdf_open_inline_stream(pdf_document *xref, fz_obj *stmobj, int length, fz_stream *chain) +pdf_open_inline_stream(pdf_document *xref, fz_obj *stmobj, int length, fz_stream *chain, pdf_image_params *imparams) { fz_obj *filters; fz_obj *params; @@ -246,9 +294,9 @@ pdf_open_inline_stream(pdf_document *xref, fz_obj *stmobj, int length, fz_stream fz_keep_stream(chain); if (fz_is_name(filters)) - return build_filter(chain, xref, filters, params, 0, 0); + return build_filter(chain, xref, filters, params, 0, 0, imparams); if (fz_array_len(filters) > 0) - return build_filter_chain(chain, xref, filters, params, 0, 0); + return build_filter_chain(chain, xref, filters, params, 0, 0, imparams); return fz_open_null(chain, length); } @@ -290,6 +338,12 @@ pdf_open_raw_stream(pdf_document *xref, int num, int gen) fz_stream * pdf_open_stream(pdf_document *xref, int num, int gen) { + return pdf_open_image_stream(xref, num, gen, NULL); +} + +fz_stream * +pdf_open_image_stream(pdf_document *xref, int num, int gen, pdf_image_params *params) +{ pdf_xref_entry *x; fz_stream *stm; @@ -304,12 +358,56 @@ pdf_open_stream(pdf_document *xref, int num, int gen) if (x->stm_ofs == 0) fz_throw(xref->ctx, "object is not a stream"); - stm = pdf_open_filter(xref->file, xref, x->obj, num, gen); + stm = pdf_open_filter(xref->file, xref, x->obj, num, gen, params); fz_seek(xref->file, x->stm_ofs, 0); return stm; } fz_stream * +pdf_open_image_decomp_stream(fz_context *ctx, fz_buffer *buffer, pdf_image_params *params, int *factor) +{ + fz_stream *chain = fz_open_buffer(ctx, buffer); + + switch (params->type) + { + case PDF_IMAGE_FAX: + *factor = 1; + return fz_open_faxd(chain, + params->u.fax.k, + params->u.fax.eol, + params->u.fax.eba, + params->u.fax.columns, + params->u.fax.rows, + params->u.fax.eob, + params->u.fax.bi1); + case PDF_IMAGE_JPEG: + if (*factor > 8) + *factor = 8; + return fz_open_resized_dctd(chain, params->u.jpeg.ct, *factor); + case PDF_IMAGE_RLD: + *factor = 1; + return fz_open_rld(chain); + case PDF_IMAGE_FLATE: + *factor = 1; + chain = fz_open_flated(chain); + if (params->u.flate.predictor > 1) + chain = fz_open_predict(chain, params->u.flate.predictor, params->u.flate.columns, params->u.flate.colors, params->u.flate.bpc); + return chain; + case PDF_IMAGE_LZW: + *factor = 1; + chain = fz_open_lzwd(chain, params->u.lzw.ec); + if (params->u.lzw.predictor > 1) + chain = fz_open_predict(chain, params->u.lzw.predictor, params->u.lzw.columns, params->u.lzw.colors, params->u.lzw.bpc); + return chain; + default: + *factor = 1; + break; + } + + return chain; +} + +fz_stream * pdf_open_stream_with_offset(pdf_document *xref, int num, int gen, fz_obj *dict, int stm_ofs) { fz_stream *stm; @@ -317,7 +415,7 @@ pdf_open_stream_with_offset(pdf_document *xref, int num, int gen, fz_obj *dict, if (stm_ofs == 0) fz_throw(xref->ctx, "object is not a stream"); - stm = pdf_open_filter(xref->file, xref, dict, num, gen); + stm = pdf_open_filter(xref->file, xref, dict, num, gen, NULL); fz_seek(xref->file, stm_ofs, 0); return stm; } @@ -372,6 +470,12 @@ pdf_guess_filter_length(int len, char *filter) fz_buffer * pdf_load_stream(pdf_document *xref, int num, int gen) { + return pdf_load_image_stream(xref, num, gen, NULL); +} + +fz_buffer * +pdf_load_image_stream(pdf_document *xref, int num, int gen, pdf_image_params *params) +{ fz_context *ctx = xref->ctx; fz_stream *stm = NULL; fz_obj *dict, *obj; @@ -392,7 +496,7 @@ pdf_load_stream(pdf_document *xref, int num, int gen) fz_drop_obj(dict); - stm = pdf_open_stream(xref, num, gen); + stm = pdf_open_image_stream(xref, num, gen, params); /* RJW: "cannot open stream (%d %d R)", num, gen */ fz_try(ctx) diff --git a/pdf/pdf_xobject.c b/pdf/pdf_xobject.c index 91bf4db3..9f6d10ce 100644 --- a/pdf/pdf_xobject.c +++ b/pdf/pdf_xobject.c @@ -43,7 +43,7 @@ pdf_load_xobject(pdf_document *xref, fz_obj *dict) fz_obj *obj; fz_context *ctx = xref->ctx; - if ((form = fz_find_item(ctx, pdf_free_xobject_imp, dict))) + if ((form = pdf_find_item(ctx, pdf_free_xobject_imp, dict))) { return form; } @@ -56,7 +56,7 @@ pdf_load_xobject(pdf_document *xref, fz_obj *dict) form->me = NULL; /* Store item immediately, to avoid possible recursion if objects refer back to this one */ - fz_store_item(ctx, dict, form, pdf_xobject_size(form)); + pdf_store_item(ctx, dict, form, pdf_xobject_size(form)); obj = fz_dict_gets(dict, "BBox"); form->bbox = pdf_to_rect(ctx, obj); @@ -102,7 +102,7 @@ pdf_load_xobject(pdf_document *xref, fz_obj *dict) } fz_catch(ctx) { - fz_remove_item(ctx, pdf_free_xobject_imp, dict); + 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)", fz_to_num(dict), fz_to_gen(dict)); } |