diff options
-rw-r--r-- | android/jni/Core.mk | 1 | ||||
-rw-r--r-- | cbz/mucbz.c | 73 | ||||
-rw-r--r-- | fitz/dev_text.c | 1 | ||||
-rw-r--r-- | fitz/fitz-internal.h | 47 | ||||
-rw-r--r-- | fitz/fitz.h | 2 | ||||
-rw-r--r-- | fitz/image_jpeg.c | 67 | ||||
-rw-r--r-- | fitz/image_png.c | 19 | ||||
-rw-r--r-- | fitz/image_tiff.c | 30 | ||||
-rw-r--r-- | fitz/res_colorspace.c | 100 | ||||
-rw-r--r-- | fitz/res_image.c | 467 | ||||
-rw-r--r-- | fitz/res_pixmap.c | 20 | ||||
-rw-r--r-- | fitz/stm_buffer.c | 15 | ||||
-rw-r--r-- | pdf/mupdf-internal.h | 20 | ||||
-rw-r--r-- | pdf/pdf_colorspace.c | 126 | ||||
-rw-r--r-- | pdf/pdf_image.c | 377 | ||||
-rw-r--r-- | win32/libmupdf.vcproj | 4 | ||||
-rw-r--r-- | xps/xps_image.c | 85 |
17 files changed, 818 insertions, 636 deletions
diff --git a/android/jni/Core.mk b/android/jni/Core.mk index fb889b57..b3619261 100644 --- a/android/jni/Core.mk +++ b/android/jni/Core.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ $(MY_ROOT)/fitz/res_colorspace.c \ $(MY_ROOT)/fitz/res_font.c \ $(MY_ROOT)/fitz/res_func.c \ + $(MY_ROOT)/fitz/res_image.c \ $(MY_ROOT)/fitz/res_path.c \ $(MY_ROOT)/fitz/res_pixmap.c \ $(MY_ROOT)/fitz/res_store.c \ diff --git a/cbz/mucbz.c b/cbz/mucbz.c index 874e1455..bcda8562 100644 --- a/cbz/mucbz.c +++ b/cbz/mucbz.c @@ -19,18 +19,9 @@ static const char *cbz_ext_list[] = { NULL }; -typedef struct cbz_image_s cbz_image; - -struct cbz_image_s -{ - fz_image base; - int xres, yres; - fz_pixmap *pix; -}; - struct cbz_page_s { - cbz_image *image; + fz_image *image; }; typedef struct cbz_entry_s cbz_entry; @@ -351,33 +342,12 @@ cbz_count_pages(cbz_document *doc) return doc->page_count; } -static void -cbz_free_image(fz_context *ctx, fz_storable *image_) -{ - cbz_image *image = (cbz_image *)image_; - - if (image == NULL) - return; - fz_drop_pixmap(ctx, image->pix); - fz_free(ctx, image); -} - -static fz_pixmap * -cbz_image_to_pixmap(fz_context *ctx, fz_image *image_, int x, int w) -{ - cbz_image *image = (cbz_image *)image_; - - return fz_keep_pixmap(ctx, image->pix); -} - cbz_page * cbz_load_page(cbz_document *doc, int number) { fz_context *ctx = doc->ctx; - unsigned char *data = NULL; + unsigned char *data; cbz_page *page = NULL; - cbz_image *image = NULL; - fz_pixmap *pixmap = NULL; int size; if (number < 0 || number >= doc->page_count) @@ -387,8 +357,6 @@ cbz_load_page(cbz_document *doc, int number) fz_var(data); fz_var(page); - fz_var(image); - fz_var(pixmap); fz_try(ctx) { page = fz_malloc_struct(ctx, cbz_page); @@ -396,26 +364,7 @@ cbz_load_page(cbz_document *doc, int number) data = cbz_read_zip_entry(doc, doc->entry[number].offset, &size); - if (size > 2 && data[0] == 0xff && data[1] == 0xd8) - pixmap = fz_load_jpeg(ctx, data, size); - else if (size > 8 && memcmp(data, "\211PNG\r\n\032\n", 8) == 0) - pixmap = fz_load_png(ctx, data, size); - else - fz_throw(ctx, "unknown image format"); - - image = fz_malloc_struct(ctx, cbz_image); - FZ_INIT_STORABLE(&image->base, 1, cbz_free_image); - image->base.w = pixmap->w; - image->base.h = pixmap->h; - image->base.get_pixmap = cbz_image_to_pixmap; - image->xres = pixmap->xres; - image->yres = pixmap->yres; - image->pix = pixmap; - page->image = image; - } - fz_always(ctx) - { - fz_free(ctx, data); + page->image = fz_new_image_from_buffer(ctx, data, size); } fz_catch(ctx) { @@ -431,17 +380,17 @@ cbz_free_page(cbz_document *doc, cbz_page *page) { if (!page) return; - fz_drop_image(doc->ctx, &page->image->base); + fz_drop_image(doc->ctx, page->image); fz_free(doc->ctx, page); } fz_rect * cbz_bound_page(cbz_document *doc, cbz_page *page, fz_rect *bbox) { - cbz_image *image = page->image; + fz_image *image = page->image; bbox->x0 = bbox->y0 = 0; - bbox->x1 = image->base.w * DPI / image->xres; - bbox->y1 = image->base.h * DPI / image->yres; + bbox->x1 = image->w * DPI / image->xres; + bbox->y1 = image->h * DPI / image->yres; return bbox; } @@ -449,11 +398,11 @@ void cbz_run_page(cbz_document *doc, cbz_page *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie) { fz_matrix local_ctm = *ctm; - cbz_image *image = page->image; - float w = image->base.w * DPI / image->xres; - float h = image->base.h * DPI / image->yres; + fz_image *image = page->image; + float w = image->w * DPI / image->xres; + float h = image->h * DPI / image->yres; fz_pre_scale(&local_ctm, w, h); - fz_fill_image(dev, &image->base, &local_ctm, 1); + fz_fill_image(dev, image, &local_ctm, 1); } static int diff --git a/fitz/dev_text.c b/fitz/dev_text.c index df37a6c6..8d6d34e8 100644 --- a/fitz/dev_text.c +++ b/fitz/dev_text.c @@ -837,6 +837,7 @@ fz_new_text_device(fz_context *ctx, fz_text_sheet *sheet, fz_text_page *page) dev->clip_text = fz_text_clip_text; dev->clip_stroke_text = fz_text_clip_stroke_text; dev->ignore_text = fz_text_ignore_text; + return dev; } diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h index d427fa7b..17a7cb8e 100644 --- a/fitz/fitz-internal.h +++ b/fitz/fitz-internal.h @@ -608,6 +608,16 @@ struct fz_buffer_s fz_buffer *fz_new_buffer(fz_context *ctx, int capacity); /* + fz_new_buffer: Create a new buffer. + + capacity: Initial capacity. + + Returns pointer to new buffer. Throws exception on allocation + failure. +*/ +fz_buffer *fz_new_buffer_from_data(fz_context *ctx, unsigned char *data, int size); + +/* fz_resize_buffer: Ensure that a buffer has a given capacity, truncating data if required. @@ -814,8 +824,6 @@ fz_stream *fz_open_jbig2d(fz_stream *chain, fz_buffer *global); * Resources and other graphics related objects. */ -enum { FZ_MAX_COLORS = 32 }; - int fz_lookup_blendmode(char *name); char *fz_blendmode_name(int blendmode); @@ -913,7 +921,9 @@ enum FZ_IMAGE_RAW = 5, FZ_IMAGE_RLD = 6, FZ_IMAGE_FLATE = 7, - FZ_IMAGE_LZW = 8 + FZ_IMAGE_LZW = 8, + FZ_IMAGE_PNG = 9, + FZ_IMAGE_TIFF = 10 }; struct fz_compression_params_s @@ -963,19 +973,40 @@ struct fz_compressed_buffer_s void fz_free_compressed_buffer(fz_context *ctx, fz_compressed_buffer *buf); +fz_image *fz_new_image(fz_context *ctx, int w, int h, int bpc, fz_colorspace *colorspace, int xres, int yres, int interpolate, int imagemask, float *decode, int *colorkey, fz_compressed_buffer *buffer, fz_image *mask); +fz_image *fz_new_image_from_pixmap(fz_context *ctx, fz_pixmap *pixmap, fz_image *mask); +fz_image *fz_new_image_from_buffer(fz_context *ctx, unsigned char *buf, int len); +fz_pixmap *fz_image_get_pixmap(fz_context *ctx, fz_image *image, int w, int h); +void fz_free_image(fz_context *ctx, fz_storable *image); +fz_pixmap *fz_decomp_image_from_stream(fz_context *ctx, fz_stream *stm, fz_image *image, int in_line, int indexed, int l2factor, int native_l2factor); +fz_pixmap *fz_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src); + struct fz_image_s { fz_storable storable; - int w, h, bpc; + int w, h, n, bpc; fz_image *mask; fz_colorspace *colorspace; fz_pixmap *(*get_pixmap)(fz_context *, fz_image *, int w, int h); + fz_compressed_buffer *buffer; + int colorkey[FZ_MAX_COLORS * 2]; + float decode[FZ_MAX_COLORS * 2]; + int imagemask; + int interpolate; + int usecolorkey; + fz_pixmap *tile; /* Private to the implementation */ + int xres; /* As given in the image, not necessarily as rendered */ + int yres; /* As given in the image, not necessarily as rendered */ }; fz_pixmap *fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *cs, int indexed); -fz_pixmap *fz_load_jpeg(fz_context *doc, unsigned char *data, int size); -fz_pixmap *fz_load_png(fz_context *doc, unsigned char *data, int size); -fz_pixmap *fz_load_tiff(fz_context *doc, unsigned char *data, int size); +fz_pixmap *fz_load_jpeg(fz_context *ctx, unsigned char *data, int size); +fz_pixmap *fz_load_png(fz_context *ctx, unsigned char *data, int size); +fz_pixmap *fz_load_tiff(fz_context *ctx, unsigned char *data, int size); + +void fz_load_jpeg_info(fz_context *ctx, unsigned char *data, int size, int *w, int *h, int *xres, int *yres, fz_colorspace **cspace); +void fz_load_png_info(fz_context *ctx, unsigned char *data, int size, int *w, int *h, int *xres, int *yres, fz_colorspace **cspace); +void fz_load_tiff_info(fz_context *ctx, unsigned char *data, int size, int *w, int *h, int *xres, int *yres, fz_colorspace **cspace); struct fz_halftone_s { @@ -1002,10 +1033,12 @@ struct fz_colorspace_s }; fz_colorspace *fz_new_colorspace(fz_context *ctx, char *name, int n); +fz_colorspace *fz_new_indexed_colorspace(fz_context *ctx, fz_colorspace *base, int high, unsigned char *lookup); fz_colorspace *fz_keep_colorspace(fz_context *ctx, fz_colorspace *colorspace); void fz_drop_colorspace(fz_context *ctx, fz_colorspace *colorspace); void fz_free_colorspace_imp(fz_context *ctx, fz_storable *colorspace); + void fz_convert_color(fz_context *ctx, fz_colorspace *dsts, float *dstv, fz_colorspace *srcs, float *srcv); typedef struct fz_color_converter_s fz_color_converter; diff --git a/fitz/fitz.h b/fitz/fitz.h index b0de1f41..45abe6d6 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -1903,6 +1903,8 @@ struct fz_text_block_s fz_text_line *lines; }; +enum { FZ_MAX_COLORS = 32 }; + /* fz_text_line: A text line is a list of text spans, with the same baseline. In typical cases this should correspond (as expected) to diff --git a/fitz/image_jpeg.c b/fitz/image_jpeg.c index e66f3d8d..432ba86d 100644 --- a/fitz/image_jpeg.c +++ b/fitz/image_jpeg.c @@ -145,3 +145,70 @@ fz_load_jpeg(fz_context *ctx, unsigned char *rbuf, int rlen) return image; } + +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; + else if (cinfo.num_components == 3) + *cspacep = fz_device_rgb; + else if (cinfo.num_components == 4) + *cspacep = fz_device_cmyk; + 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); + } +} diff --git a/fitz/image_png.c b/fitz/image_png.c index bda959fe..7eebdced 100644 --- a/fitz/image_png.c +++ b/fitz/image_png.c @@ -578,3 +578,22 @@ fz_load_png(fz_context *ctx, unsigned char *p, int total) return image; } + +void +fz_load_png_info(fz_context *ctx, unsigned char *p, int total, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep) +{ + struct info png; + + png_read_image(ctx, &png, p, total); + + if (png.n == 3 || png.n == 4) + *cspacep = fz_device_rgb; + else + *cspacep = fz_device_gray; + + *wp = png.width; + *hp = png.height; + *xresp = png.xres; + *yresp = png.xres; + fz_free(png.ctx, png.samples); +} diff --git a/fitz/image_tiff.c b/fitz/image_tiff.c index a2b405d9..0efcc622 100644 --- a/fitz/image_tiff.c +++ b/fitz/image_tiff.c @@ -835,3 +835,33 @@ fz_load_tiff(fz_context *ctx, unsigned char *buf, int len) return image; } + +void +fz_load_tiff_info(fz_context *ctx, unsigned char *buf, int len, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep) +{ + struct tiff tiff; + + fz_try(ctx) + { + fz_decode_tiff_header(ctx, &tiff, buf, len); + + *wp = tiff.imagewidth; + *hp = tiff.imagelength; + *xresp = tiff.xresolution; + *yresp = tiff.yresolution; + *cspacep = tiff.colorspace; + } + fz_always(ctx) + { + /* Clean up scratch memory */ + if (tiff.colormap) fz_free(ctx, tiff.colormap); + if (tiff.stripoffsets) fz_free(ctx, tiff.stripoffsets); + if (tiff.stripbytecounts) fz_free(ctx, tiff.stripbytecounts); + if (tiff.samples) fz_free(ctx, tiff.samples); + if (tiff.profile) fz_free(ctx, tiff.profile); + } + fz_catch(ctx) + { + fz_throw(ctx, "out of memory"); + } +} diff --git a/fitz/res_colorspace.c b/fitz/res_colorspace.c index a2ce19b8..5d8c3b02 100644 --- a/fitz/res_colorspace.c +++ b/fitz/res_colorspace.c @@ -1085,3 +1085,103 @@ fz_convert_color(fz_context *ctx, fz_colorspace *ds, float *dv, fz_colorspace *s fz_find_color_converter(&cc, ctx, ds, ss); cc.convert(&cc, dv, sv); } + + +/* Indexed */ + +struct indexed +{ + fz_colorspace *base; + int high; + unsigned char *lookup; +}; + +static void +indexed_to_rgb(fz_context *ctx, fz_colorspace *cs, float *color, float *rgb) +{ + struct indexed *idx = cs->data; + float alt[FZ_MAX_COLORS]; + int i, k; + i = color[0] * 255; + i = fz_clampi(i, 0, idx->high); + for (k = 0; k < idx->base->n; k++) + alt[k] = idx->lookup[i * idx->base->n + k] / 255.0f; + idx->base->to_rgb(ctx, idx->base, alt, rgb); +} + +static void +free_indexed(fz_context *ctx, fz_colorspace *cs) +{ + struct indexed *idx = cs->data; + if (idx->base) + fz_drop_colorspace(ctx, idx->base); + fz_free(ctx, idx->lookup); + fz_free(ctx, idx); +} + +fz_colorspace * +fz_new_indexed_colorspace(fz_context *ctx, fz_colorspace *base, int high, unsigned char *lookup) +{ + fz_colorspace *cs; + struct indexed *idx; + + idx = fz_malloc_struct(ctx, struct indexed); + idx->lookup = lookup; + idx->base = base; + idx->high = high; + + fz_try(ctx) + { + 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) + (base->n * (idx->high + 1)) + base->size; + } + fz_catch(ctx) + { + fz_free(ctx, idx); + fz_throw(ctx, "failed to create indexed colorspace"); + } + return cs; +} + +fz_pixmap * +fz_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src) +{ + struct indexed *idx; + fz_pixmap *dst; + unsigned char *s, *d; + int y, x, k, n, high; + unsigned char *lookup; + fz_irect bbox; + + assert(src->colorspace->to_rgb == indexed_to_rgb); + assert(src->n == 2); + + idx = src->colorspace->data; + high = idx->high; + lookup = idx->lookup; + n = idx->base->n; + + dst = fz_new_pixmap_with_bbox(ctx, idx->base, fz_pixmap_bbox(ctx, src, &bbox)); + s = src->samples; + d = dst->samples; + + for (y = 0; y < src->h; y++) + { + for (x = 0; x < src->w; x++) + { + int v = *s++; + int a = *s++; + v = fz_mini(v, high); + for (k = 0; k < n; k++) + *d++ = fz_mul255(lookup[v * n + k], a); + *d++ = a; + } + } + + dst->interpolate = src->interpolate; + + return dst; +} diff --git a/fitz/res_image.c b/fitz/res_image.c new file mode 100644 index 00000000..c8ba8257 --- /dev/null +++ b/fitz/res_image.c @@ -0,0 +1,467 @@ +#include "fitz-internal.h" + +fz_pixmap * +fz_image_to_pixmap(fz_context *ctx, fz_image *image, int w, int h) +{ + if (image == NULL) + return NULL; + return image->get_pixmap(ctx, image, w, h); +} + +fz_image * +fz_keep_image(fz_context *ctx, fz_image *image) +{ + return (fz_image *)fz_keep_storable(ctx, &image->storable); +} + +void +fz_drop_image(fz_context *ctx, fz_image *image) +{ + fz_drop_storable(ctx, &image->storable); +} + +typedef struct fz_image_key_s fz_image_key; + +struct fz_image_key_s { + int refs; + fz_image *image; + int l2factor; +}; + +static int +fz_make_hash_image_key(fz_store_hash *hash, void *key_) +{ + fz_image_key *key = (fz_image_key *)key_; + + hash->u.pi.ptr = key->image; + hash->u.pi.i = key->l2factor; + return 1; +} + +static void * +fz_keep_image_key(fz_context *ctx, void *key_) +{ + fz_image_key *key = (fz_image_key *)key_; + + fz_lock(ctx, FZ_LOCK_ALLOC); + key->refs++; + fz_unlock(ctx, FZ_LOCK_ALLOC); + + return (void *)key; +} + +static void +fz_drop_image_key(fz_context *ctx, void *key_) +{ + fz_image_key *key = (fz_image_key *)key_; + int drop; + + if (key == NULL) + return; + 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 +fz_cmp_image_key(void *k0_, void *k1_) +{ + fz_image_key *k0 = (fz_image_key *)k0_; + fz_image_key *k1 = (fz_image_key *)k1_; + + return k0->image == k1->image && k0->l2factor == k1->l2factor; +} + +#ifndef NDEBUG +static void +fz_debug_image(FILE *out, void *key_) +{ + fz_image_key *key = (fz_image_key *)key_; + + fprintf(out, "(image %d x %d sf=%d) ", key->image->w, key->image->h, key->l2factor); +} +#endif + +static fz_store_type fz_image_store_type = +{ + fz_make_hash_image_key, + fz_keep_image_key, + fz_drop_image_key, + fz_cmp_image_key, +#ifndef NDEBUG + fz_debug_image +#endif +}; + +static void +fz_mask_color_key(fz_pixmap *pix, int n, int *colorkey) +{ + unsigned char *p = pix->samples; + int len = pix->w * pix->h; + int k, t; + while (len--) + { + t = 1; + for (k = 0; k < n; k++) + if (p[k] < colorkey[k * 2] || p[k] > colorkey[k * 2 + 1]) + t = 0; + if (t) + for (k = 0; k < pix->n; k++) + p[k] = 0; + p += pix->n; + } +} + +fz_pixmap * +fz_decomp_image_from_stream(fz_context *ctx, fz_stream *stm, fz_image *image, int in_line, int indexed, int l2factor, int native_l2factor) +{ + fz_pixmap *tile = NULL; + int stride, len, i; + unsigned char *samples = NULL; + int f = 1<<native_l2factor; + int w = (image->w + f-1) >> native_l2factor; + int h = (image->h + f-1) >> native_l2factor; + + fz_var(tile); + fz_var(samples); + + fz_try(ctx) + { + tile = fz_new_pixmap(ctx, image->colorspace, 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) + fz_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 = fz_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 apply any extra subsampling required */ + if (l2factor - native_l2factor > 0) + { + if (l2factor - native_l2factor > 8) + l2factor = native_l2factor + 8; + fz_subsample_pixmap(ctx, tile, l2factor - native_l2factor); + } + + return tile; +} + +void +fz_free_image(fz_context *ctx, fz_storable *image_) +{ + fz_image *image = (fz_image *)image_; + + if (image == NULL) + return; + fz_drop_pixmap(ctx, image->tile); + fz_free_compressed_buffer(ctx, image->buffer); + fz_drop_colorspace(ctx, image->colorspace); + fz_drop_image(ctx, image->mask); + fz_free(ctx, image); +} + +fz_pixmap * +fz_image_get_pixmap(fz_context *ctx, fz_image *image, int w, int h) +{ + fz_pixmap *tile; + fz_stream *stm; + int l2factor; + fz_image_key key; + int native_l2factor; + int indexed; + fz_image_key *keyp; + + /* Check for 'simple' images which are just pixmaps */ + if (image->buffer == NULL) + { + tile = image->tile; + if (!tile) + return NULL; + return fz_keep_pixmap(ctx, tile); /* That's all we can give you! */ + } + + /* Ensure our expectations for tile size are reasonable */ + if (w > image->w) + w = image->w; + if (h > image->h) + h = image->h; + + /* What is our ideal factor? */ + if (w == 0 || h == 0) + l2factor = 0; + else + for (l2factor=0; image->w>>(l2factor+1) >= w && image->h>>(l2factor+1) >= h && l2factor < 8; l2factor++); + + /* Can we find any suitable tiles in the cache? */ + key.refs = 1; + key.image = image; + key.l2factor = l2factor; + do + { + tile = fz_find_item(ctx, fz_free_pixmap_imp, &key, &fz_image_store_type); + if (tile) + return tile; + key.l2factor--; + } + while (key.l2factor >= 0); + + /* We need to make a new one. */ + /* First check for ones that we can't decode using streams */ + switch (image->buffer->params.type) + { + case FZ_IMAGE_PNG: + tile = fz_load_png(ctx, image->buffer->buffer->data, image->buffer->buffer->len); + break; + case FZ_IMAGE_TIFF: + tile = fz_load_tiff(ctx, image->buffer->buffer->data, image->buffer->buffer->len); + break; + default: + native_l2factor = l2factor; + stm = fz_open_image_decomp_stream(ctx, image->buffer, &native_l2factor); + + indexed = fz_colorspace_is_indexed(image->colorspace); + tile = fz_decomp_image_from_stream(ctx, stm, image, 0, indexed, l2factor, native_l2factor); + break; + } + + + /* Now we try to cache the pixmap. Any failure here will just result + * in us not caching. */ + fz_var(keyp); + fz_try(ctx) + { + fz_pixmap *existing_tile; + + keyp = fz_malloc_struct(ctx, fz_image_key); + keyp->refs = 1; + keyp->image = fz_keep_image(ctx, image); + keyp->l2factor = l2factor; + existing_tile = fz_store_item(ctx, keyp, tile, fz_pixmap_size(ctx, tile), &fz_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); + tile = existing_tile; + } + } + fz_always(ctx) + { + fz_drop_image_key(ctx, keyp); + } + fz_catch(ctx) + { + /* Do nothing */ + } + + return tile; +} + +fz_image * +fz_new_image_from_pixmap(fz_context *ctx, fz_pixmap *pixmap, fz_image *mask) +{ + fz_image *image; + + assert(mask == NULL || mask->mask == NULL); + + fz_try(ctx) + { + image = fz_malloc_struct(ctx, fz_image); + FZ_INIT_STORABLE(image, 1, fz_free_image); + image->w = pixmap->w; + image->h = pixmap->h; + image->n = pixmap->n; + image->colorspace = pixmap->colorspace; + image->bpc = 8; + image->buffer = NULL; + image->get_pixmap = fz_image_get_pixmap; + image->xres = pixmap->xres; + image->yres = pixmap->yres; + image->tile = pixmap; + image->mask = mask; + } + fz_catch(ctx) + { + fz_drop_image(ctx, mask); + fz_rethrow(ctx); + } + return image; +} + +fz_image * +fz_new_image(fz_context *ctx, int w, int h, int bpc, fz_colorspace *colorspace, + int xres, int yres, int interpolate, int imagemask, float *decode, + int *colorkey, fz_compressed_buffer *buffer, fz_image *mask) +{ + fz_image *image; + + assert(mask == NULL || mask->mask == NULL); + + fz_try(ctx) + { + image = fz_malloc_struct(ctx, fz_image); + FZ_INIT_STORABLE(image, 1, fz_free_image); + image->get_pixmap = fz_image_get_pixmap; + image->w = w; + image->h = h; + image->xres = xres; + image->yres = yres; + image->bpc = bpc; + image->n = (colorspace ? colorspace->n : 1); + image->colorspace = colorspace; + image->interpolate = interpolate; + image->imagemask = imagemask; + image->usecolorkey = (colorkey != NULL); + if (colorkey) + memcpy(image->colorkey, colorkey, sizeof(int)*image->n*2); + if (decode) + memcpy(image->decode, decode, sizeof(float)*image->n*2); + else + { + float maxval = fz_colorspace_is_indexed(colorspace) ? (1 << bpc) - 1 : 1; + int i; + for (i = 0; i < image->n; i++) + { + image->decode[2*i] = 0; + image->decode[2*i+1] = maxval; + } + } + image->mask = mask; + image->buffer = buffer; + } + fz_catch(ctx) + { + fz_free_compressed_buffer(ctx, buffer); + fz_rethrow(ctx); + } + + return image; +} + +fz_image * +fz_new_image_from_buffer(fz_context *ctx, unsigned char *buf, int len) +{ + fz_compressed_buffer *bc = NULL; + int w, h, xres, yres; + fz_colorspace *cspace; + unsigned char *free_buf = buf; + + fz_var(bc); + fz_var(free_buf); + + fz_try(ctx) + { + if (len < 8) + fz_throw(ctx, "unknown image file format"); + + bc = fz_malloc_struct(ctx, fz_compressed_buffer); + bc->buffer = fz_new_buffer_from_data(ctx, buf, len); + free_buf = NULL; + + if (buf[0] == 0xff && buf[1] == 0xd8) + { + bc->params.type = FZ_IMAGE_JPEG; + bc->params.u.jpeg.color_transform = -1; + fz_load_jpeg_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); + } + else if (memcmp(buf, "\211PNG\r\n\032\n", 8) == 0) + { + bc->params.type = FZ_IMAGE_PNG; + fz_load_png_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); + } + else if (memcmp(buf, "II", 2) == 0 && buf[2] == 0xBC) + fz_throw(ctx, "JPEG-XR codec is not available"); + else if (memcmp(buf, "MM", 2) == 0 || memcmp(buf, "II", 2) == 0) + { + bc->params.type = FZ_IMAGE_TIFF; + fz_load_tiff_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace); + } + else + fz_throw(ctx, "unknown image file format"); + } + fz_catch(ctx) + { + fz_free(ctx, free_buf); + fz_free_compressed_buffer(ctx, bc); + fz_rethrow(ctx); + } + + return fz_new_image(ctx, w, h, 8, cspace, xres, yres, 0, 0, NULL, NULL, bc, NULL); +} diff --git a/fitz/res_pixmap.c b/fitz/res_pixmap.c index 08e88a32..d8d94252 100644 --- a/fitz/res_pixmap.c +++ b/fitz/res_pixmap.c @@ -673,26 +673,6 @@ fz_pixmap_size(fz_context *ctx, fz_pixmap * pix) return sizeof(*pix) + pix->n * pix->w * pix->h; } -fz_pixmap * -fz_image_to_pixmap(fz_context *ctx, fz_image *image, int w, int h) -{ - if (image == NULL) - return NULL; - return image->get_pixmap(ctx, image, w, h); -} - -fz_image * -fz_keep_image(fz_context *ctx, fz_image *image) -{ - return (fz_image *)fz_keep_storable(ctx, &image->storable); -} - -void -fz_drop_image(fz_context *ctx, fz_image *image) -{ - fz_drop_storable(ctx, &image->storable); -} - #ifdef ARCH_ARM static void fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor, diff --git a/fitz/stm_buffer.c b/fitz/stm_buffer.c index c1405d2f..8b5a40d9 100644 --- a/fitz/stm_buffer.c +++ b/fitz/stm_buffer.c @@ -26,6 +26,21 @@ fz_new_buffer(fz_context *ctx, int size) } fz_buffer * +fz_new_buffer_from_data(fz_context *ctx, unsigned char *data, int size) +{ + fz_buffer *b; + + b = fz_malloc_struct(ctx, fz_buffer); + b->refs = 1; + b->data = data; + b->cap = size; + b->len = size; + b->unused_bits = 0; + + return b; +} + +fz_buffer * fz_keep_buffer(fz_context *ctx, fz_buffer *buf) { if (buf) diff --git a/pdf/mupdf-internal.h b/pdf/mupdf-internal.h index 9dbbd714..d064f71c 100644 --- a/pdf/mupdf-internal.h +++ b/pdf/mupdf-internal.h @@ -9,25 +9,6 @@ void *pdf_get_indirect_document(pdf_obj *obj); void pdf_set_int(pdf_obj *obj, int i); /* - * PDF Images - */ - -typedef struct pdf_image_s pdf_image; - -struct pdf_image_s -{ - fz_image base; - fz_pixmap *tile; - int n; - fz_compressed_buffer *buffer; - int colorkey[FZ_MAX_COLORS * 2]; - float decode[FZ_MAX_COLORS * 2]; - int imagemask; - int interpolate; - int usecolorkey; -}; - -/* * tokenizer and low-level object parser */ @@ -228,7 +209,6 @@ void pdf_print_crypt(pdf_crypt *crypt); fz_function *pdf_load_function(pdf_document *doc, pdf_obj *ref, int in, int out); fz_colorspace *pdf_load_colorspace(pdf_document *doc, pdf_obj *obj); -fz_pixmap *pdf_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src); fz_shade *pdf_load_shading(pdf_document *doc, pdf_obj *obj); diff --git a/pdf/pdf_colorspace.c b/pdf/pdf_colorspace.c index f6a1c3b3..a398b44f 100644 --- a/pdf/pdf_colorspace.c +++ b/pdf/pdf_colorspace.c @@ -143,119 +143,37 @@ load_separation(pdf_document *xref, pdf_obj *array) return cs; } -/* Indexed */ - -struct indexed -{ - fz_colorspace *base; - int high; - unsigned char *lookup; -}; - -static void -indexed_to_rgb(fz_context *ctx, fz_colorspace *cs, float *color, float *rgb) -{ - struct indexed *idx = cs->data; - float alt[FZ_MAX_COLORS]; - int i, k; - i = color[0] * 255; - i = fz_clampi(i, 0, idx->high); - for (k = 0; k < idx->base->n; k++) - alt[k] = idx->lookup[i * idx->base->n + k] / 255.0f; - idx->base->to_rgb(ctx, idx->base, alt, rgb); -} - -static void -free_indexed(fz_context *ctx, fz_colorspace *cs) -{ - struct indexed *idx = cs->data; - if (idx->base) - fz_drop_colorspace(ctx, idx->base); - fz_free(ctx, idx->lookup); - fz_free(ctx, idx); -} - -fz_pixmap * -pdf_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src) -{ - struct indexed *idx; - fz_pixmap *dst; - unsigned char *s, *d; - int y, x, k, n, high; - unsigned char *lookup; - fz_irect bbox; - - assert(src->colorspace->to_rgb == indexed_to_rgb); - assert(src->n == 2); - - idx = src->colorspace->data; - high = idx->high; - lookup = idx->lookup; - n = idx->base->n; - - dst = fz_new_pixmap_with_bbox(ctx, idx->base, fz_pixmap_bbox(ctx, src, &bbox)); - s = src->samples; - d = dst->samples; - - for (y = 0; y < src->h; y++) - { - for (x = 0; x < src->w; x++) - { - int v = *s++; - int a = *s++; - v = fz_mini(v, high); - for (k = 0; k < n; k++) - *d++ = fz_mul255(lookup[v * n + k], a); - *d++ = a; - } - } - - dst->interpolate = src->interpolate; - - return dst; -} 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); + pdf_obj *lookupobj = pdf_array_get(array, 3); fz_colorspace *base = NULL; - fz_colorspace *cs = NULL; - int i, n; + fz_colorspace *cs; + int i, n, high; + unsigned char *lookup = NULL; - fz_var(idx); fz_var(base); - fz_var(cs); fz_try(ctx) { base = pdf_load_colorspace(xref, baseobj); - idx = fz_malloc_struct(ctx, struct indexed); - idx->lookup = NULL; - idx->base = base; - idx->high = pdf_to_int(highobj); - idx->high = fz_clampi(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) + 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(lookup); + unsigned char *buf = (unsigned char *) pdf_to_str_buf(lookupobj); for (i = 0; i < n; i++) - idx->lookup[i] = buf[i]; + lookup[i] = buf[i]; } - else if (pdf_is_indirect(lookup)) + else if (pdf_is_indirect(lookupobj)) { fz_stream *file = NULL; @@ -263,8 +181,8 @@ load_indexed(pdf_document *xref, pdf_obj *array) fz_try(ctx) { - file = pdf_open_stream(xref, pdf_to_num(lookup), pdf_to_gen(lookup)); - i = fz_read(file, idx->lookup, n); + file = pdf_open_stream(xref, pdf_to_num(lookupobj), pdf_to_gen(lookupobj)); + i = fz_read(file, lookup, n); } fz_always(ctx) { @@ -272,24 +190,20 @@ load_indexed(pdf_document *xref, pdf_obj *array) } fz_catch(ctx) { - fz_throw(ctx, "cannot open colorspace lookup table (%d 0 R)", pdf_to_num(lookup)); + fz_throw(ctx, "cannot open colorspace lookup table (%d 0 R)", pdf_to_num(lookupobj)); } } else { fz_throw(ctx, "cannot parse colorspace lookup table"); } + + cs = fz_new_indexed_colorspace(ctx, base, high, lookup); } fz_catch(ctx) { - if (cs == NULL || cs->data != idx) - { - fz_drop_colorspace(ctx, base); - if (idx) - fz_free(ctx, idx->lookup); - fz_free(ctx, idx); - } - fz_drop_colorspace(ctx, cs); + fz_drop_colorspace(ctx, base); + fz_free(ctx, lookup); fz_rethrow(ctx); } diff --git a/pdf/pdf_image.c b/pdf/pdf_image.c index b6795456..1b6cebaf 100644 --- a/pdf/pdf_image.c +++ b/pdf/pdf_image.c @@ -1,313 +1,13 @@ #include "fitz-internal.h" #include "mupdf-internal.h" -typedef struct pdf_image_key_s pdf_image_key; +static fz_image *pdf_load_jpx(pdf_document *xref, pdf_obj *dict, int forcemask); -struct pdf_image_key_s { - int refs; - fz_image *image; - int l2factor; -}; - -static void pdf_load_jpx(pdf_document *xref, pdf_obj *dict, pdf_image *image, int forcemask); - -static void -pdf_mask_color_key(fz_pixmap *pix, int n, int *colorkey) -{ - unsigned char *p = pix->samples; - int len = pix->w * pix->h; - int k, t; - while (len--) - { - t = 1; - for (k = 0; k < n; k++) - if (p[k] < colorkey[k * 2] || p[k] > colorkey[k * 2 + 1]) - t = 0; - if (t) - for (k = 0; k < pix->n; k++) - p[k] = 0; - p += pix->n; - } -} - -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->l2factor; - 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->l2factor == k1->l2factor; -} - -#ifndef NDEBUG -static void -pdf_debug_image(FILE *out, void *key_) -{ - pdf_image_key *key = (pdf_image_key *)key_; - - fprintf(out, "(image %d x %d sf=%d) ", key->image->w, key->image->h, key->l2factor); -} -#endif - -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, -#ifndef NDEBUG - pdf_debug_image -#endif -}; - -static fz_pixmap * -decomp_image_from_stream(fz_context *ctx, fz_stream *stm, pdf_image *image, int in_line, int indexed, int l2factor, int native_l2factor, int cache) -{ - fz_pixmap *tile = NULL; - fz_pixmap *existing_tile; - int stride, len, i; - unsigned char *samples = NULL; - int f = 1<<native_l2factor; - int w = (image->base.w + f-1) >> native_l2factor; - int h = (image->base.h + f-1) >> native_l2factor; - pdf_image_key *key = NULL; - - fz_var(tile); - fz_var(samples); - fz_var(key); - - fz_try(ctx) - { - tile = fz_new_pixmap(ctx, image->base.colorspace, w, h); - tile->interpolate = image->interpolate; - - stride = (w * image->n * image->base.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->base.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->base.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 apply any extra subsampling required */ - if (l2factor - native_l2factor > 0) - { - if (l2factor - native_l2factor > 8) - l2factor = native_l2factor + 8; - fz_subsample_pixmap(ctx, tile, l2factor - native_l2factor); - } - - if (!cache) - return tile; - - /* 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->l2factor = l2factor; - 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); - 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_free_compressed_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 l2factor; - pdf_image_key key; - int native_l2factor; - int indexed; - - /* Check for 'simple' images which are just pixmaps */ - if (image->buffer == NULL) - { - tile = image->tile; - if (!tile) - return NULL; - 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) - l2factor = 0; - else - for (l2factor=0; image->base.w>>(l2factor+1) >= w && image->base.h>>(l2factor+1) >= h && l2factor < 8; l2factor++); - - /* Can we find any suitable tiles in the cache? */ - key.refs = 1; - key.image = &image->base; - key.l2factor = l2factor; - do - { - tile = fz_find_item(ctx, fz_free_pixmap_imp, &key, &pdf_image_store_type); - if (tile) - return tile; - key.l2factor--; - } - while (key.l2factor >= 0); - - /* We need to make a new one. */ - native_l2factor = l2factor; - stm = fz_open_image_decomp_stream(ctx, image->buffer, &native_l2factor); - - indexed = fz_colorspace_is_indexed(image->base.colorspace); - return decomp_image_from_stream(ctx, stm, image, 0, indexed, l2factor, native_l2factor, 1); -} - -static pdf_image * +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; - pdf_image *image = NULL; + fz_image *image = NULL; pdf_obj *obj, *res; int w, h, bpc, n; @@ -315,22 +15,24 @@ pdf_load_image_imp(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *c int interpolate; int indexed; fz_image *mask = NULL; /* explicit mask/soft mask image */ - int usecolorkey; + 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); - - image = fz_malloc_struct(ctx, pdf_image); + fz_var(image); fz_try(ctx) { /* special case for JPEG2000 images */ if (pdf_is_jpx_image(ctx, dict)) { - pdf_load_jpx(xref, dict, image, forcemask); + image = pdf_load_jpx(xref, dict, forcemask); if (forcemask) { @@ -383,12 +85,12 @@ pdf_load_image_imp(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *c obj = res; } - image->base.colorspace = pdf_load_colorspace(xref, obj); + colorspace = pdf_load_colorspace(xref, obj); - if (!strcmp(image->base.colorspace->name, "Indexed")) + if (!strcmp(colorspace->name, "Indexed")) indexed = 1; - n = image->base.colorspace->n; + n = colorspace->n; } else { @@ -399,13 +101,13 @@ pdf_load_image_imp(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *c if (obj) { for (i = 0; i < n * 2; i++) - image->decode[i] = pdf_to_real(pdf_array_get(obj, 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++) - image->decode[i] = i & 1 ? maxval : 0; + decode[i] = i & 1 ? maxval : 0; } obj = pdf_dict_getsa(dict, "SMask", "Mask"); @@ -429,35 +131,26 @@ pdf_load_image_imp(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *c fz_warn(ctx, "invalid value in color key mask"); usecolorkey = 0; } - image->colorkey[i] = pdf_to_int(pdf_array_get(obj, i)); + 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); + 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 * image->n * image->base.bpc + 7) / 8; + int stride = (w * n * bpc + 7) / 8; stm = pdf_open_inline_stream(xref, dict, stride * h, cstm, NULL); } else @@ -465,11 +158,12 @@ pdf_load_image_imp(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *c 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); + 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) { - pdf_free_image(ctx, (fz_storable *) image); + fz_drop_image(ctx, image); fz_rethrow(ctx); } return image; @@ -497,8 +191,8 @@ pdf_is_jpx_image(fz_context *ctx, pdf_obj *dict) return 0; } -static void -pdf_load_jpx(pdf_document *xref, pdf_obj *dict, pdf_image *image, int forcemask) +static fz_image * +pdf_load_jpx(pdf_document *xref, pdf_obj *dict, int forcemask) { fz_buffer *buf = NULL; fz_colorspace *colorspace = NULL; @@ -506,10 +200,12 @@ pdf_load_jpx(pdf_document *xref, pdf_obj *dict, pdf_image *image, int forcemask) pdf_obj *obj; fz_context *ctx = xref->ctx; int indexed = 0; + fz_image *mask = NULL; fz_var(img); fz_var(buf); fz_var(colorspace); + fz_var(mask); buf = pdf_load_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); @@ -537,7 +233,7 @@ pdf_load_jpx(pdf_document *xref, pdf_obj *dict, pdf_image *image, int forcemask) 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); + mask = (fz_image *)pdf_load_image_imp(xref, NULL, obj, NULL, 1); } obj = pdf_dict_getsa(dict, "Decode", "D"); @@ -560,22 +256,11 @@ pdf_load_jpx(pdf_document *xref, pdf_obj *dict, pdf_image *image, int forcemask) 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; + return fz_new_image_from_pixmap(ctx, img, mask); } static int -pdf_image_size(fz_context *ctx, pdf_image *im) +fz_image_size(fz_context *ctx, fz_image *im) { if (im == NULL) return 0; @@ -586,16 +271,16 @@ fz_image * pdf_load_image(pdf_document *xref, pdf_obj *dict) { fz_context *ctx = xref->ctx; - pdf_image *image; + fz_image *image; - if ((image = pdf_find_item(ctx, pdf_free_image, dict))) + if ((image = pdf_find_item(ctx, fz_free_image, dict))) { return (fz_image *)image; } image = pdf_load_image_imp(xref, NULL, dict, NULL, 0); - pdf_store_item(ctx, dict, image, pdf_image_size(ctx, image)); + pdf_store_item(ctx, dict, image, fz_image_size(ctx, image)); return (fz_image *)image; } diff --git a/win32/libmupdf.vcproj b/win32/libmupdf.vcproj index 6faae480..23a4b8ba 100644 --- a/win32/libmupdf.vcproj +++ b/win32/libmupdf.vcproj @@ -553,6 +553,10 @@ > </File> <File + RelativePath="..\fitz\res_image.c" + > + </File> + <File RelativePath="..\fitz\res_path.c" > </File> diff --git a/xps/xps_image.c b/xps/xps_image.c index 449b5dda..ea8d547b 100644 --- a/xps/xps_image.c +++ b/xps/xps_image.c @@ -1,77 +1,12 @@ #include "muxps-internal.h" -typedef struct xps_image_s xps_image; - -struct xps_image_s -{ - fz_image base; - fz_pixmap *pix; - int xres; - int yres; -}; - -static void -xps_free_image(fz_context *ctx, fz_storable *image_) -{ - xps_image *image = (xps_image *)image_; - - if (image == NULL) - return; - - fz_drop_colorspace(ctx, image->base.colorspace); - fz_drop_pixmap(ctx, image->pix); - fz_free(ctx, image); -} - -static fz_pixmap * -xps_image_to_pixmap(fz_context *ctx, fz_image *image_, int x, int w) -{ - xps_image *image = (xps_image *)image_; - - return fz_keep_pixmap(ctx, image->pix); -} - static fz_image * -xps_load_image(fz_context *ctx, byte *buf, int len) +xps_load_image(fz_context *ctx, xps_part *part) { - fz_pixmap *pix; - xps_image *image; - - if (len < 8) - fz_throw(ctx, "unknown image file format"); - - if (buf[0] == 0xff && buf[1] == 0xd8) - pix = fz_load_jpeg(ctx, buf, len); - else if (memcmp(buf, "\211PNG\r\n\032\n", 8) == 0) - pix = fz_load_png(ctx, buf, len); - else if (memcmp(buf, "II", 2) == 0 && buf[2] == 0xBC) - fz_throw(ctx, "JPEG-XR codec is not available"); - else if (memcmp(buf, "MM", 2) == 0 || memcmp(buf, "II", 2) == 0) - pix = fz_load_tiff(ctx, buf, len); - else - fz_throw(ctx, "unknown image file format"); - - fz_try(ctx) - { - image = fz_malloc_struct(ctx, xps_image); - - FZ_INIT_STORABLE(&image->base, 1, xps_free_image); - image->base.w = pix->w; - image->base.h = pix->h; - image->base.mask = NULL; - image->base.colorspace = pix->colorspace; - image->base.get_pixmap = xps_image_to_pixmap; - image->xres = pix->xres; - image->yres = pix->yres; - image->pix = pix; - } - fz_catch(ctx) - { - fz_drop_pixmap(ctx, pix); - fz_rethrow(ctx); - } - - return &image->base; + /* Ownership of data always passes in here */ + byte *data = part->data; + part->data = NULL; + return fz_new_image_from_buffer(ctx, data, part->size); } /* FIXME: area unused! */ @@ -79,16 +14,16 @@ static void xps_paint_image_brush(xps_document *doc, const fz_matrix *ctm, const fz_rect *area, char *base_uri, xps_resource *dict, fz_xml *root, void *vimage) { - xps_image *image = vimage; + fz_image *image = vimage; float xs, ys; fz_matrix local_ctm = *ctm; if (image->xres == 0 || image->yres == 0) return; - xs = image->base.w * 96 / image->xres; - ys = image->base.h * 96 / image->yres; + xs = image->w * 96 / image->xres; + ys = image->h * 96 / image->yres; fz_pre_scale(&local_ctm, xs, ys); - fz_fill_image(doc->dev, &image->base, &local_ctm, doc->opacity[doc->opacity_top]); + fz_fill_image(doc->dev, image, &local_ctm, doc->opacity[doc->opacity_top]); } static xps_part * @@ -160,7 +95,7 @@ xps_parse_image_brush(xps_document *doc, const fz_matrix *ctm, const fz_rect *ar fz_try(doc->ctx) { - image = xps_load_image(doc->ctx, part->data, part->size); + image = xps_load_image(doc->ctx, part); } fz_always(doc->ctx) { |