summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2013-04-05 15:49:10 +0100
committerRobin Watts <robin.watts@artifex.com>2013-04-11 19:00:39 +0100
commit53b5ede268394d651df1f12da490884bf870006a (patch)
tree72145964ff775415674c73b1e05ea18669238278
parent05f9887c211fff4195b5959bc71d2ef4b773fdc2 (diff)
downloadmupdf-53b5ede268394d651df1f12da490884bf870006a.tar.xz
Move pdf_image to fz_image.
In order to be able to output images (either in the pdfwrite device or in the html conversion), we need to be able to get to the original compressed data stream (or else we're going to end up recompressing images). To do that, we need to expose all of the contents of pdf_image into fz_image, so it makes sense to just amalgamate the two. This has knock on effects for the creation of indexed colorspaces, requiring some of that logic to be moved. Also, we need to make xps use the same structures; this means pushing PNG and TIFF support into the decoding code. Also we need to be able to load just the headers from PNG/TIFF/JPEGs as xps doesn't include dimension/resolution information. Also, separate out all the fz_image stuff into fitz/res_image.c rather than having it in res_pixmap.
-rw-r--r--android/jni/Core.mk1
-rw-r--r--cbz/mucbz.c73
-rw-r--r--fitz/dev_text.c1
-rw-r--r--fitz/fitz-internal.h47
-rw-r--r--fitz/fitz.h2
-rw-r--r--fitz/image_jpeg.c67
-rw-r--r--fitz/image_png.c19
-rw-r--r--fitz/image_tiff.c30
-rw-r--r--fitz/res_colorspace.c100
-rw-r--r--fitz/res_image.c467
-rw-r--r--fitz/res_pixmap.c20
-rw-r--r--fitz/stm_buffer.c15
-rw-r--r--pdf/mupdf-internal.h20
-rw-r--r--pdf/pdf_colorspace.c126
-rw-r--r--pdf/pdf_image.c377
-rw-r--r--win32/libmupdf.vcproj4
-rw-r--r--xps/xps_image.c85
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)
{