summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)
{