summaryrefslogtreecommitdiff
path: root/fitz
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 /fitz
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.
Diffstat (limited to 'fitz')
-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
10 files changed, 741 insertions, 27 deletions
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)