summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-02-21 17:09:10 +0000
committerRobin Watts <robin.watts@artifex.com>2012-02-25 08:14:27 -0800
commitf86c02284c259b9034f324dffe76969efa8b2e42 (patch)
tree6e2a0c86ff040ade748d767ecd377282810d0ad4
parent7c19fd50ea7ee9dfd253220a0ea2cac4df7d6345 (diff)
downloadmupdf-f86c02284c259b9034f324dffe76969efa8b2e42.tar.xz
Rework image handling for on demand decode
Introduce a new 'fz_image' type; this type contains rudimentary information about images (such as native, size, colorspace etc) and a function to call to get a pixmap of that image (with a size hint). Instead of passing pixmaps through the device interface (and holding pixmaps in the display list) we now pass images instead. The rendering routines therefore call fz_image_to_pixmap to get pixmaps to render, and fz_pixmap_drop those afterwards. The file format handling routines therefore need to produce images rather than pixmaps; xps and cbz currently just wrap pixmaps as images. PDF is more involved. The stream handling routines in PDF have been altered so that they can recognise when the last stream entry in a filter dictionary is an image decoding filter. Rather than applying this filter, they read and store the parameters into a pdf_image_params structure, and stop decoding at that point. This allows us to read the compressed data for an image into memory as a block. We can then restart the image decode process later. pdf_images therefore consist of the compressed image data for images. When a pixmap is requested for such an image, the code checks to see if we have one (of an appropriate size), and if not, decodes it. The size hint is used to determine whether it is possible to subsample the image; currently this is only supported for JPEGs, but we could add generic subsampling code later. In order to handle caching the produced images, various changes have been made to the store and the underlying hash table. Previously the store was indexed purely by fz_obj keys; we don't have an fz_obj key any more, so have extended the store by adding a concept of a key 'type'. A key type is a pointer to a set of functions that keep/drop/compare and make a hashable key from a key pointer. We make a pdf_store.c file that contains functions to offer the existing fz_obj based functions, and add a new 'type' for keys (based on the fz_image handle, and the subsample factor) in the pdf_image.c file. While working on this, a problem became apparent in the existing store codel; fz_obj objects had no protection on their reference counts, hence an interpreter thread could try to alter a ref count at the same time as a malloc caused an eviction from the store. This has been solved by using the alloc lock as protection. This in turn requires some tweaks to the code to make sure we don't try and keep/drop fz_obj's from the store code while the alloc lock is held. A side effect of this work is that when a hash table is created, we inform it what lock should be used to protect its innards (if any). If the alloc lock is used, the insert method knows to drop/retake it to allow it to safely expand the hash table. Callers to the hash functions have the responsibility of taking/dropping the appropriate lock, and ensuring that they cope with the possibility that insert might drop the alloc lock, causing race conditions.
-rw-r--r--apps/mupdfextract.c5
-rw-r--r--cbz/mucbz.c73
-rw-r--r--draw/draw_device.c180
-rw-r--r--draw/draw_glyph.c2
-rw-r--r--fitz/base_hash.c97
-rw-r--r--fitz/dev_bbox.c4
-rw-r--r--fitz/dev_list.c16
-rw-r--r--fitz/dev_null.c6
-rw-r--r--fitz/dev_trace.c6
-rw-r--r--fitz/filt_dctd.c11
-rw-r--r--fitz/fitz.h72
-rw-r--r--fitz/res_colorspace.c2
-rw-r--r--fitz/res_pixmap.c20
-rw-r--r--fitz/res_store.c130
-rw-r--r--fitz/stm_read.c3
-rw-r--r--pdf/mupdf.h94
-rw-r--r--pdf/pdf_cmap_load.c4
-rw-r--r--pdf/pdf_colorspace.c4
-rw-r--r--pdf/pdf_font.c4
-rw-r--r--pdf/pdf_function.c4
-rw-r--r--pdf/pdf_image.c474
-rw-r--r--pdf/pdf_interpret.c15
-rw-r--r--pdf/pdf_pattern.c6
-rw-r--r--pdf/pdf_shade.c4
-rw-r--r--pdf/pdf_store.c59
-rw-r--r--pdf/pdf_stream.c130
-rw-r--r--pdf/pdf_xobject.c6
-rw-r--r--win32/libmupdf.vcproj4
-rw-r--r--xps/xps_image.c76
29 files changed, 1100 insertions, 411 deletions
diff --git a/apps/mupdfextract.c b/apps/mupdfextract.c
index f309f39a..239e9ea7 100644
--- a/apps/mupdfextract.c
+++ b/apps/mupdfextract.c
@@ -31,6 +31,7 @@ static int isfontdesc(fz_obj *obj)
static void saveimage(int num)
{
+ fz_image *image;
fz_pixmap *img;
fz_obj *ref;
char name[1024];
@@ -39,7 +40,9 @@ static void saveimage(int num)
/* TODO: detect DCTD and save as jpeg */
- img = pdf_load_image(doc, ref);
+ image = pdf_load_image(doc, ref);
+ img = fz_image_to_pixmap(ctx, image, 0, 0);
+ fz_drop_image(ctx, image);
if (dorgb && img->colorspace && img->colorspace != fz_device_rgb)
{
diff --git a/cbz/mucbz.c b/cbz/mucbz.c
index 83c463bd..89c9d4dd 100644
--- a/cbz/mucbz.c
+++ b/cbz/mucbz.c
@@ -19,9 +19,18 @@ 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
{
- fz_pixmap *image;
+ cbz_image *image;
};
typedef struct cbz_entry_s cbz_entry;
@@ -343,12 +352,34 @@ 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;
cbz_page *page = NULL;
+ cbz_image *image = NULL;
+ fz_pixmap *pixmap = NULL;
int size;
if (number < 0 || number >= doc->page_count)
@@ -358,19 +389,31 @@ 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(doc->ctx, cbz_page);
+ page = fz_malloc_struct(ctx, cbz_page);
page->image = NULL;
data = cbz_read_zip_entry(doc, doc->entry[number].offset, &size);
if (data[0] == 0xff && data[1] == 0xd8)
- page->image = fz_load_jpeg(ctx, data, size);
+ pixmap = fz_load_jpeg(ctx, data, size);
else if (memcmp(data, "\211PNG\r\n\032\n", 8) == 0)
- page->image = fz_load_png(ctx, data, size);
+ 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)
{
@@ -378,9 +421,7 @@ cbz_load_page(cbz_document *doc, int number)
}
fz_catch(ctx)
{
- if (page && page->image)
- fz_drop_pixmap(ctx, page->image);
- fz_free(ctx, page);
+ cbz_free_page(doc, page);
fz_rethrow(ctx);
}
@@ -390,29 +431,31 @@ cbz_load_page(cbz_document *doc, int number)
void
cbz_free_page(cbz_document *doc, cbz_page *page)
{
- fz_drop_pixmap(doc->ctx, page->image);
+ if (!page)
+ return;
+ fz_drop_image(doc->ctx, &page->image->base);
fz_free(doc->ctx, page);
}
fz_rect
cbz_bound_page(cbz_document *doc, cbz_page *page)
{
- fz_pixmap *image = page->image;
+ cbz_image *image = page->image;
fz_rect bbox;
bbox.x0 = bbox.y0 = 0;
- bbox.x1 = image->w * DPI / image->xres;
- bbox.y1 = image->h * DPI / image->yres;
+ bbox.x1 = image->base.w * DPI / image->xres;
+ bbox.y1 = image->base.h * DPI / image->yres;
return bbox;
}
void
cbz_run_page(cbz_document *doc, cbz_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
{
- fz_pixmap *image = page->image;
- float w = image->w * DPI / image->xres;
- float h = image->h * DPI / image->yres;
+ cbz_image *image = page->image;
+ float w = image->base.w * DPI / image->xres;
+ float h = image->base.h * DPI / image->yres;
ctm = fz_concat(fz_scale(w, h), ctm);
- fz_fill_image(dev, image, ctm, 1);
+ fz_fill_image(dev, &image->base, ctm, 1);
}
/* Document interface wrappers */
diff --git a/draw/draw_device.c b/draw/draw_device.c
index 279ef64d..65ee5a39 100644
--- a/draw/draw_device.c
+++ b/draw/draw_device.c
@@ -878,11 +878,13 @@ fz_transform_pixmap(fz_context *ctx, fz_pixmap *image, fz_matrix *ctm, int x, in
}
static void
-fz_draw_fill_image(fz_device *devp, fz_pixmap *image, fz_matrix ctm, float alpha)
+fz_draw_fill_image(fz_device *devp, fz_image *image, fz_matrix ctm, float alpha)
{
fz_draw_device *dev = devp->user;
fz_pixmap *converted = NULL;
fz_pixmap *scaled = NULL;
+ fz_pixmap *pixmap;
+ fz_pixmap *orig_pixmap;
int after;
int dx, dy;
fz_context *ctx = dev->ctx;
@@ -903,87 +905,93 @@ fz_draw_fill_image(fz_device *devp, fz_pixmap *image, fz_matrix ctm, float alpha
if (image->w == 0 || image->h == 0)
return;
+ dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b);
+ dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d);
+
+ pixmap = fz_image_to_pixmap(ctx, image, dx, dy);
+ orig_pixmap = pixmap;
+
/* convert images with more components (cmyk->rgb) before scaling */
/* convert images with fewer components (gray->rgb after scaling */
/* convert images with expensive colorspace transforms after scaling */
- if (state->blendmode & FZ_BLEND_KNOCKOUT)
- state = fz_knockout_begin(dev);
+ fz_try(ctx)
+ {
+ if (state->blendmode & FZ_BLEND_KNOCKOUT)
+ state = fz_knockout_begin(dev);
- after = 0;
- if (image->colorspace == fz_device_gray)
- after = 1;
+ after = 0;
+ if (pixmap->colorspace == fz_device_gray)
+ after = 1;
- if (image->colorspace != model && !after)
- {
- converted = fz_new_pixmap_with_rect(ctx, model, fz_bound_pixmap(image));
- fz_convert_pixmap(ctx, image, converted);
- image = converted;
- }
+ if (pixmap->colorspace != model && !after)
+ {
+ converted = fz_new_pixmap_with_rect(ctx, model, fz_bound_pixmap(pixmap));
+ fz_convert_pixmap(ctx, pixmap, converted);
+ pixmap = converted;
+ }
- fz_try(ctx)
- {
- dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b);
- dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d);
- if (dx < image->w && dy < image->h)
+ if (dx < pixmap->w && dy < pixmap->h)
{
int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3);
- scaled = fz_transform_pixmap(ctx, image, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip);
+ scaled = fz_transform_pixmap(ctx, pixmap, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip);
if (!scaled)
{
if (dx < 1)
dx = 1;
if (dy < 1)
dy = 1;
- scaled = fz_scale_pixmap(ctx, image, image->x, image->y, dx, dy, NULL);
+ scaled = fz_scale_pixmap(ctx, pixmap, pixmap->x, pixmap->y, dx, dy, NULL);
}
if (scaled)
- image = scaled;
+ pixmap = scaled;
}
- if (image->colorspace != model)
+ if (pixmap->colorspace != model)
{
- if ((image->colorspace == fz_device_gray && model == fz_device_rgb) ||
- (image->colorspace == fz_device_gray && model == fz_device_bgr))
+ if ((pixmap->colorspace == fz_device_gray && model == fz_device_rgb) ||
+ (pixmap->colorspace == fz_device_gray && model == fz_device_bgr))
{
/* We have special case rendering code for gray -> rgb/bgr */
}
else
{
- converted = fz_new_pixmap_with_rect(ctx, model, fz_bound_pixmap(image));
- fz_convert_pixmap(ctx, image, converted);
- image = converted;
+ converted = fz_new_pixmap_with_rect(ctx, model, fz_bound_pixmap(pixmap));
+ fz_convert_pixmap(ctx, pixmap, converted);
+ pixmap = converted;
}
}
- fz_paint_image(state->dest, state->scissor, state->shape, image, ctm, alpha * 255);
+ fz_paint_image(state->dest, state->scissor, state->shape, pixmap, ctm, alpha * 255);
+
+ if (state->blendmode & FZ_BLEND_KNOCKOUT)
+ fz_knockout_end(dev);
}
- fz_catch(ctx)
+ fz_always(ctx)
{
fz_drop_pixmap(ctx, scaled);
fz_drop_pixmap(ctx, converted);
+ fz_drop_pixmap(ctx, orig_pixmap);
+ }
+ fz_catch(ctx)
+ {
fz_rethrow(ctx);
}
-
- if (scaled)
- fz_drop_pixmap(ctx, scaled);
- if (converted)
- fz_drop_pixmap(ctx, converted);
-
- if (state->blendmode & FZ_BLEND_KNOCKOUT)
- fz_knockout_end(dev);
}
static void
-fz_draw_fill_image_mask(fz_device *devp, fz_pixmap *image, fz_matrix ctm,
+fz_draw_fill_image_mask(fz_device *devp, fz_image *image, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
fz_draw_device *dev = devp->user;
unsigned char colorbv[FZ_MAX_COLORS + 1];
float colorfv[FZ_MAX_COLORS];
fz_pixmap *scaled = NULL;
+ fz_pixmap *pixmap;
+ fz_pixmap *orig_pixmap;
int dx, dy;
int i;
+ fz_context *ctx = dev->ctx;
fz_draw_state *state = &dev->stack[dev->top];
fz_colorspace *model = state->dest->colorspace;
fz_bbox clip = fz_bound_pixmap(state->dest);
@@ -993,43 +1001,57 @@ fz_draw_fill_image_mask(fz_device *devp, fz_pixmap *image, fz_matrix ctm,
if (image->w == 0 || image->h == 0)
return;
- if (state->blendmode & FZ_BLEND_KNOCKOUT)
- state = fz_knockout_begin(dev);
-
dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b);
dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d);
- if (dx < image->w && dy < image->h)
+ pixmap = fz_image_to_pixmap(ctx, image, dx, dy);
+ orig_pixmap = pixmap;
+
+ fz_try(ctx)
{
- int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3);
- scaled = fz_transform_pixmap(dev->ctx, image, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip);
- if (!scaled)
+ if (state->blendmode & FZ_BLEND_KNOCKOUT)
+ state = fz_knockout_begin(dev);
+
+ if (dx < pixmap->w && dy < pixmap->h)
{
- if (dx < 1)
- dx = 1;
- if (dy < 1)
- dy = 1;
- scaled = fz_scale_pixmap(dev->ctx, image, image->x, image->y, dx, dy, NULL);
+ int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3);
+ scaled = fz_transform_pixmap(dev->ctx, pixmap, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip);
+ if (!scaled)
+ {
+ if (dx < 1)
+ dx = 1;
+ if (dy < 1)
+ dy = 1;
+ scaled = fz_scale_pixmap(dev->ctx, pixmap, pixmap->x, pixmap->y, dx, dy, NULL);
+ }
+ if (scaled)
+ pixmap = scaled;
}
- if (scaled)
- image = scaled;
- }
- fz_convert_color(dev->ctx, colorspace, color, model, colorfv);
- for (i = 0; i < model->n; i++)
- colorbv[i] = colorfv[i] * 255;
- colorbv[i] = alpha * 255;
+ fz_convert_color(dev->ctx, colorspace, color, model, colorfv);
+ for (i = 0; i < model->n; i++)
+ colorbv[i] = colorfv[i] * 255;
+ colorbv[i] = alpha * 255;
- fz_paint_image_with_color(state->dest, state->scissor, state->shape, image, ctm, colorbv);
+ fz_paint_image_with_color(state->dest, state->scissor, state->shape, pixmap, ctm, colorbv);
- if (scaled)
- fz_drop_pixmap(dev->ctx, scaled);
+ if (scaled)
+ fz_drop_pixmap(dev->ctx, scaled);
- if (state->blendmode & FZ_BLEND_KNOCKOUT)
- fz_knockout_end(dev);
+ if (state->blendmode & FZ_BLEND_KNOCKOUT)
+ fz_knockout_end(dev);
+ }
+ fz_always(ctx)
+ {
+ fz_drop_pixmap(dev->ctx, orig_pixmap);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
}
static void
-fz_draw_clip_image_mask(fz_device *devp, fz_pixmap *image, fz_rect *rect, fz_matrix ctm)
+fz_draw_clip_image_mask(fz_device *devp, fz_image *image, fz_rect *rect, fz_matrix ctm)
{
fz_draw_device *dev = devp->user;
fz_context *ctx = dev->ctx;
@@ -1038,6 +1060,8 @@ fz_draw_clip_image_mask(fz_device *devp, fz_pixmap *image, fz_rect *rect, fz_mat
fz_pixmap *dest = NULL;
fz_pixmap *shape = NULL;
fz_pixmap *scaled = NULL;
+ fz_pixmap *pixmap;
+ fz_pixmap *orig_pixmap;
int dx, dy;
fz_draw_state *state = push_stack(dev);
fz_colorspace *model = state->dest->colorspace;
@@ -1068,10 +1092,16 @@ fz_draw_clip_image_mask(fz_device *devp, fz_pixmap *image, fz_rect *rect, fz_mat
if (rect)
bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect));
- mask = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox);
- fz_clear_pixmap(dev->ctx, mask);
+ dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b);
+ dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d);
+ pixmap = fz_image_to_pixmap(ctx, image, dx, dy);
+ orig_pixmap = pixmap;
+
fz_try(ctx)
{
+ mask = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox);
+ fz_clear_pixmap(dev->ctx, mask);
+
dest = fz_new_pixmap_with_rect(dev->ctx, model, bbox);
fz_clear_pixmap(dev->ctx, dest);
if (state->shape)
@@ -1080,23 +1110,28 @@ fz_draw_clip_image_mask(fz_device *devp, fz_pixmap *image, fz_rect *rect, fz_mat
fz_clear_pixmap(dev->ctx, shape);
}
- dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b);
- dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d);
- if (dx < image->w && dy < image->h)
+ if (dx < pixmap->w && dy < pixmap->h)
{
int gridfit = !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3);
- scaled = fz_transform_pixmap(dev->ctx, image, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip);
+ scaled = fz_transform_pixmap(dev->ctx, pixmap, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip);
if (!scaled)
{
if (dx < 1)
dx = 1;
if (dy < 1)
dy = 1;
- scaled = fz_scale_pixmap(dev->ctx, image, image->x, image->y, dx, dy, NULL);
+ scaled = fz_scale_pixmap(dev->ctx, pixmap, pixmap->x, pixmap->y, dx, dy, NULL);
}
if (scaled)
- image = scaled;
+ pixmap = scaled;
}
+ fz_paint_image(mask, bbox, state->shape, pixmap, ctm, 255);
+
+ }
+ fz_always(ctx)
+ {
+ fz_drop_pixmap(ctx, scaled);
+ fz_drop_pixmap(ctx, orig_pixmap);
}
fz_catch(ctx)
{
@@ -1106,11 +1141,6 @@ fz_draw_clip_image_mask(fz_device *devp, fz_pixmap *image, fz_rect *rect, fz_mat
fz_rethrow(ctx);
}
- fz_paint_image(mask, bbox, state->shape, image, ctm, 255);
-
- if (scaled)
- fz_drop_pixmap(dev->ctx, scaled);
-
state[1].blendmode |= FZ_BLEND_ISOLATED;
state[1].scissor = bbox;
state[1].dest = dest;
diff --git a/draw/draw_glyph.c b/draw/draw_glyph.c
index 68ae3b80..110a7a25 100644
--- a/draw/draw_glyph.c
+++ b/draw/draw_glyph.c
@@ -30,7 +30,7 @@ fz_new_glyph_cache_context(fz_context *ctx)
cache = fz_malloc_struct(ctx, fz_glyph_cache);
fz_try(ctx)
{
- cache->hash = fz_new_hash_table(ctx, 509, sizeof(fz_glyph_key));
+ cache->hash = fz_new_hash_table(ctx, 509, sizeof(fz_glyph_key), FZ_LOCK_GLYPHCACHE);
}
fz_catch(ctx)
{
diff --git a/fitz/base_hash.c b/fitz/base_hash.c
index 630f6b6a..0fda86cd 100644
--- a/fitz/base_hash.c
+++ b/fitz/base_hash.c
@@ -22,6 +22,7 @@ struct fz_hash_table_s
int keylen;
int size;
int load;
+ int lock; /* -1 or the lock used to protect this hash table */
fz_hash_entry *ents;
};
@@ -42,7 +43,7 @@ static unsigned hash(unsigned char *s, int len)
}
fz_hash_table *
-fz_new_hash_table(fz_context *ctx, int initialsize, int keylen)
+fz_new_hash_table(fz_context *ctx, int initialsize, int keylen, int lock)
{
fz_hash_table *table;
@@ -52,6 +53,7 @@ fz_new_hash_table(fz_context *ctx, int initialsize, int keylen)
table->keylen = keylen;
table->size = initialsize;
table->load = 0;
+ table->lock = lock;
fz_try(ctx)
{
table->ents = fz_malloc_array(ctx, table->size, sizeof(fz_hash_entry));
@@ -98,10 +100,45 @@ fz_free_hash(fz_context *ctx, fz_hash_table *table)
fz_free(ctx, table);
}
+static void *
+do_hash_insert(fz_context *ctx, fz_hash_table *table, void *key, void *val)
+{
+ fz_hash_entry *ents;
+ unsigned size;
+ unsigned pos;
+
+ ents = table->ents;
+ size = table->size;
+ pos = hash(key, table->keylen) % size;
+
+ if (table->lock >= 0)
+ fz_assert_lock_held(ctx, table->lock);
+
+ while (1)
+ {
+ if (!ents[pos].val)
+ {
+ memcpy(ents[pos].key, key, table->keylen);
+ ents[pos].val = val;
+ table->load ++;
+ return NULL;
+ }
+
+ if (memcmp(key, ents[pos].key, table->keylen) == 0)
+ {
+ fz_warn(ctx, "assert: overwrite hash slot");
+ return ents[pos].val = val;
+ }
+
+ pos = (pos + 1) % size;
+ }
+}
+
static void
fz_resize_hash(fz_context *ctx, fz_hash_table *table, int newsize)
{
fz_hash_entry *oldents = table->ents;
+ fz_hash_entry *newents = table->ents;
int oldsize = table->size;
int oldload = table->load;
int i;
@@ -112,7 +149,22 @@ fz_resize_hash(fz_context *ctx, fz_hash_table *table, int newsize)
return;
}
- table->ents = fz_malloc_array(ctx, newsize, sizeof(fz_hash_entry));
+ if (table->lock == FZ_LOCK_ALLOC)
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
+ newents = fz_malloc_array(ctx, newsize, sizeof(fz_hash_entry));
+ if (table->lock == FZ_LOCK_ALLOC)
+ fz_lock(ctx, FZ_LOCK_ALLOC);
+ if (table->lock >= 0)
+ {
+ if (table->size >= newsize)
+ {
+ /* Someone else fixed it before we could lock! */
+ fz_unlock(ctx, table->lock);
+ fz_free(ctx, newents);
+ return;
+ }
+ }
+ table->ents = newents;
memset(table->ents, 0, sizeof(fz_hash_entry) * newsize);
table->size = newsize;
table->load = 0;
@@ -121,11 +173,15 @@ fz_resize_hash(fz_context *ctx, fz_hash_table *table, int newsize)
{
if (oldents[i].val)
{
- fz_hash_insert(ctx, table, oldents[i].key, oldents[i].val);
+ do_hash_insert(ctx, table, oldents[i].key, oldents[i].val);
}
}
+ if (table->lock == FZ_LOCK_ALLOC)
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
fz_free(ctx, oldents);
+ if (table->lock == FZ_LOCK_ALLOC)
+ fz_lock(ctx, FZ_LOCK_ALLOC);
}
void *
@@ -135,6 +191,9 @@ fz_hash_find(fz_context *ctx, fz_hash_table *table, void *key)
unsigned size = table->size;
unsigned pos = hash(key, table->keylen) % size;
+ if (table->lock >= 0)
+ fz_assert_lock_held(ctx, table->lock);
+
while (1)
{
if (!ents[pos].val)
@@ -150,37 +209,12 @@ fz_hash_find(fz_context *ctx, fz_hash_table *table, void *key)
void *
fz_hash_insert(fz_context *ctx, fz_hash_table *table, void *key, void *val)
{
- fz_hash_entry *ents;
- unsigned size;
- unsigned pos;
-
if (table->load > table->size * 8 / 10)
{
fz_resize_hash(ctx, table, table->size * 2);
}
- ents = table->ents;
- size = table->size;
- pos = hash(key, table->keylen) % size;
-
- while (1)
- {
- if (!ents[pos].val)
- {
- memcpy(ents[pos].key, key, table->keylen);
- ents[pos].val = val;
- table->load ++;
- return NULL;
- }
-
- if (memcmp(key, ents[pos].key, table->keylen) == 0)
- {
- fz_warn(ctx, "assert: overwrite hash slot");
- return ents[pos].val;
- }
-
- pos = (pos + 1) % size;
- }
+ return do_hash_insert(ctx, table, key, val);
}
void
@@ -191,11 +225,14 @@ fz_hash_remove(fz_context *ctx, fz_hash_table *table, void *key)
unsigned pos = hash(key, table->keylen) % size;
unsigned hole, look, code;
+ if (table->lock >= 0)
+ fz_assert_lock_held(ctx, table->lock);
+
while (1)
{
if (!ents[pos].val)
{
- fz_warn(ctx, "assert: remove inexistent hash entry");
+ fz_warn(ctx, "assert: remove non-existent hash entry");
return;
}
diff --git a/fitz/dev_bbox.c b/fitz/dev_bbox.c
index 636ceb94..b015c585 100644
--- a/fitz/dev_bbox.c
+++ b/fitz/dev_bbox.c
@@ -47,7 +47,7 @@ fz_bbox_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha)
}
static void
-fz_bbox_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha)
+fz_bbox_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha)
{
fz_bbox *result = dev->user;
fz_bbox bbox = fz_round_rect(fz_transform_rect(ctm, fz_unit_rect));
@@ -55,7 +55,7 @@ fz_bbox_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha)
}
static void
-fz_bbox_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm,
+fz_bbox_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
fz_bbox_fill_image(dev, image, ctm, alpha);
diff --git a/fitz/dev_list.c b/fitz/dev_list.c
index adc691d0..1d82421e 100644
--- a/fitz/dev_list.c
+++ b/fitz/dev_list.c
@@ -37,7 +37,7 @@ struct fz_display_node_s
fz_path *path;
fz_text *text;
fz_shade *shade;
- fz_pixmap *image;
+ fz_image *image;
int blendmode;
} item;
fz_stroke_state *stroke;
@@ -207,7 +207,7 @@ fz_free_display_node(fz_context *ctx, fz_display_node *node)
case FZ_CMD_FILL_IMAGE:
case FZ_CMD_FILL_IMAGE_MASK:
case FZ_CMD_CLIP_IMAGE_MASK:
- fz_drop_pixmap(ctx, node->item.image);
+ fz_drop_image(ctx, node->item.image);
break;
case FZ_CMD_POP_CLIP:
case FZ_CMD_BEGIN_MASK:
@@ -435,35 +435,35 @@ fz_list_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha)
}
static void
-fz_list_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha)
+fz_list_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha)
{
fz_display_node *node;
node = fz_new_display_node(dev->ctx, FZ_CMD_FILL_IMAGE, ctm, NULL, NULL, alpha);
node->rect = fz_transform_rect(ctm, fz_unit_rect);
- node->item.image = fz_keep_pixmap(dev->ctx, image);
+ node->item.image = fz_keep_image(dev->ctx, image);
fz_append_display_node(dev->user, node);
}
static void
-fz_list_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm,
+fz_list_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
fz_display_node *node;
node = fz_new_display_node(dev->ctx, FZ_CMD_FILL_IMAGE_MASK, ctm, colorspace, color, alpha);
node->rect = fz_transform_rect(ctm, fz_unit_rect);
- node->item.image = fz_keep_pixmap(dev->ctx, image);
+ node->item.image = fz_keep_image(dev->ctx, image);
fz_append_display_node(dev->user, node);
}
static void
-fz_list_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm)
+fz_list_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm)
{
fz_display_node *node;
node = fz_new_display_node(dev->ctx, FZ_CMD_CLIP_IMAGE_MASK, ctm, NULL, NULL, 0);
node->rect = fz_transform_rect(ctm, fz_unit_rect);
if (rect)
node->rect = fz_intersect_rect(node->rect, *rect);
- node->item.image = fz_keep_pixmap(dev->ctx, image);
+ node->item.image = fz_keep_image(dev->ctx, image);
fz_append_display_node(dev->user, node);
}
diff --git a/fitz/dev_null.c b/fitz/dev_null.c
index b4ba5cbe..d817932d 100644
--- a/fitz/dev_null.c
+++ b/fitz/dev_null.c
@@ -103,14 +103,14 @@ fz_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha)
}
void
-fz_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha)
+fz_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha)
{
if (dev->fill_image)
dev->fill_image(dev, image, ctm, alpha);
}
void
-fz_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm,
+fz_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
if (dev->fill_image_mask)
@@ -118,7 +118,7 @@ fz_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm,
}
void
-fz_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm)
+fz_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm)
{
if (dev->clip_image_mask)
dev->clip_image_mask(dev, image, rect, ctm);
diff --git a/fitz/dev_trace.c b/fitz/dev_trace.c
index 1c2e1ed1..9faffc35 100644
--- a/fitz/dev_trace.c
+++ b/fitz/dev_trace.c
@@ -197,7 +197,7 @@ fz_trace_ignore_text(fz_device *dev, fz_text *text, fz_matrix ctm)
}
static void
-fz_trace_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha)
+fz_trace_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha)
{
printf("<fill_image alpha=\"%g\" ", alpha);
fz_trace_matrix(ctm);
@@ -213,7 +213,7 @@ fz_trace_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha)
}
static void
-fz_trace_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm,
+fz_trace_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm,
fz_colorspace *colorspace, float *color, float alpha)
{
printf("<fill_image_mask ");
@@ -223,7 +223,7 @@ fz_colorspace *colorspace, float *color, float alpha)
}
static void
-fz_trace_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm)
+fz_trace_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm)
{
printf("<clip_image_mask ");
fz_trace_matrix(ctm);
diff --git a/fitz/filt_dctd.c b/fitz/filt_dctd.c
index 4357f3d7..3abe0468 100644
--- a/fitz/filt_dctd.c
+++ b/fitz/filt_dctd.c
@@ -12,6 +12,7 @@ struct fz_dctd_s
int color_transform;
int init;
int stride;
+ int factor;
unsigned char *scanline;
unsigned char *rp, *wp;
struct jpeg_decompress_struct cinfo;
@@ -150,6 +151,9 @@ read_dctd(fz_stream *stm, unsigned char *buf, int len)
break;
}
+ cinfo->scale_num = 8/state->factor;
+ cinfo->scale_denom = 8;
+
jpeg_start_decompress(cinfo);
state->stride = cinfo->output_width * cinfo->output_components;
@@ -216,6 +220,12 @@ skip:
fz_stream *
fz_open_dctd(fz_stream *chain, int color_transform)
{
+ return fz_open_resized_dctd(chain, color_transform, 1);
+}
+
+fz_stream *
+fz_open_resized_dctd(fz_stream *chain, int color_transform, int factor)
+{
fz_context *ctx = chain->ctx;
fz_dctd *state = NULL;
@@ -228,6 +238,7 @@ fz_open_dctd(fz_stream *chain, int color_transform)
state->chain = chain;
state->color_transform = color_transform;
state->init = 0;
+ state->factor = factor;
}
fz_catch(ctx)
{
diff --git a/fitz/fitz.h b/fitz/fitz.h
index d2672031..856df7e5 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -504,7 +504,7 @@ extern char *fz_optarg;
typedef struct fz_hash_table_s fz_hash_table;
-fz_hash_table *fz_new_hash_table(fz_context *ctx, int initialsize, int keylen);
+fz_hash_table *fz_new_hash_table(fz_context *ctx, int initialsize, int keylen, int lock);
void fz_debug_hash(fz_context *ctx, fz_hash_table *table);
void fz_empty_hash(fz_context *ctx, fz_hash_table *table);
void fz_free_hash(fz_context *ctx, fz_hash_table *table);
@@ -810,6 +810,36 @@ enum {
FZ_STORE_DEFAULT = 256 << 20,
};
+typedef struct fz_store_hash_s fz_store_hash;
+
+struct fz_store_hash_s
+{
+ fz_store_free_fn *free;
+ union
+ {
+ struct
+ {
+ int i0;
+ int i1;
+ } i;
+ struct
+ {
+ void *ptr;
+ int i;
+ } pi;
+ } u;
+};
+
+typedef struct fz_store_type_s fz_store_type;
+
+struct fz_store_type_s
+{
+ int (*make_hash_key)(fz_store_hash *, void *);
+ void *(*keep_key)(fz_context *,void *);
+ void (*drop_key)(fz_context *,void *);
+ int (*cmp_key)(void *, void *);
+};
+
void fz_new_store_context(fz_context *ctx, unsigned int max);
void fz_drop_store_context(fz_context *ctx);
fz_store *fz_store_keep(fz_context *ctx);
@@ -818,9 +848,9 @@ void fz_debug_store(fz_context *ctx);
void *fz_keep_storable(fz_context *, fz_storable *);
void fz_drop_storable(fz_context *, fz_storable *);
-void fz_store_item(fz_context *ctx, fz_obj *key, void *val, unsigned int itemsize);
-void *fz_find_item(fz_context *ctx, fz_store_free_fn *freefn, fz_obj *key);
-void fz_remove_item(fz_context *ctx, fz_store_free_fn *freefn, fz_obj *key);
+void *fz_store_item(fz_context *ctx, void *key, void *val, unsigned int itemsize, fz_store_type *type);
+void *fz_find_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type);
+void fz_remove_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type);
void fz_empty_store(fz_context *ctx);
int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase);
@@ -959,6 +989,7 @@ fz_stream *fz_open_a85d(fz_stream *chain);
fz_stream *fz_open_ahxd(fz_stream *chain);
fz_stream *fz_open_rld(fz_stream *chain);
fz_stream *fz_open_dctd(fz_stream *chain, int color_transform);
+fz_stream *fz_open_resized_dctd(fz_stream *chain, int color_transform, int factor);
fz_stream *fz_open_faxd(fz_stream *chain,
int k, int end_of_line, int encoded_byte_align,
int columns, int rows, int end_of_block, int black_is_1);
@@ -1023,6 +1054,27 @@ void fz_write_pnm(fz_context *ctx, fz_pixmap *pixmap, char *filename);
void fz_write_pam(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha);
void fz_write_png(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha);
+/*
+ * Images are either a reference to a pixmap, or details of how to make
+ * a pixmap. To know how to make a pixmap we need a block of compressed
+ * data (typically a stream decoded all the way until the image filter)
+ * and then the details of the params for the filter to do the final step.
+ */
+typedef struct fz_image_s fz_image;
+
+struct fz_image_s
+{
+ fz_storable storable;
+ int w, h;
+ fz_image *mask;
+ fz_colorspace *colorspace;
+ fz_pixmap *(*get_pixmap)(fz_context *, fz_image *, int w, int h);
+};
+
+fz_pixmap *fz_image_to_pixmap(fz_context *, fz_image *, int w, int h);
+void fz_drop_image(fz_context *ctx, fz_image *image);
+fz_image *fz_keep_image(fz_context *ctx, fz_image *image);
+
fz_pixmap *fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *cs);
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);
@@ -1413,9 +1465,9 @@ struct fz_device_s
void (*ignore_text)(fz_device *, fz_text *, fz_matrix);
void (*fill_shade)(fz_device *, fz_shade *shd, fz_matrix ctm, float alpha);
- void (*fill_image)(fz_device *, fz_pixmap *img, fz_matrix ctm, float alpha);
- void (*fill_image_mask)(fz_device *, fz_pixmap *img, fz_matrix ctm, fz_colorspace *, float *color, float alpha);
- void (*clip_image_mask)(fz_device *, fz_pixmap *img, fz_rect *rect, fz_matrix ctm);
+ void (*fill_image)(fz_device *, fz_image *img, fz_matrix ctm, float alpha);
+ void (*fill_image_mask)(fz_device *, fz_image *img, fz_matrix ctm, fz_colorspace *, float *color, float alpha);
+ void (*clip_image_mask)(fz_device *, fz_image *img, fz_rect *rect, fz_matrix ctm);
void (*pop_clip)(fz_device *);
@@ -1439,9 +1491,9 @@ void fz_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke,
void fz_ignore_text(fz_device *dev, fz_text *text, fz_matrix ctm);
void fz_pop_clip(fz_device *dev);
void fz_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha);
-void fz_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha);
-void fz_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
-void fz_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm);
+void fz_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha);
+void fz_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
+void fz_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm);
void fz_begin_mask(fz_device *dev, fz_rect area, int luminosity, fz_colorspace *colorspace, float *bc);
void fz_end_mask(fz_device *dev);
void fz_begin_group(fz_device *dev, fz_rect area, int isolated, int knockout, int blendmode, float alpha);
diff --git a/fitz/res_colorspace.c b/fitz/res_colorspace.c
index 413da3ae..c25fc99f 100644
--- a/fitz/res_colorspace.c
+++ b/fitz/res_colorspace.c
@@ -465,7 +465,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst)
fz_hash_table *lookup;
unsigned char *color;
- lookup = fz_new_hash_table(ctx, 509, srcn);
+ lookup = fz_new_hash_table(ctx, 509, srcn, -1);
for (y = 0; y < src->h; y++)
{
diff --git a/fitz/res_pixmap.c b/fitz/res_pixmap.c
index 500eb4be..328a8c2d 100644
--- a/fitz/res_pixmap.c
+++ b/fitz/res_pixmap.c
@@ -551,3 +551,23 @@ fz_pixmap_size(fz_context *ctx, fz_pixmap * pix)
return 0;
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);
+}
diff --git a/fitz/res_store.c b/fitz/res_store.c
index 5eec1f0d..461ea7c8 100644
--- a/fitz/res_store.c
+++ b/fitz/res_store.c
@@ -1,21 +1,14 @@
#include "fitz.h"
-#include "mupdf.h"
struct fz_item_s
{
- fz_obj *key;
+ void *key;
fz_storable *val;
unsigned int size;
fz_item *next;
fz_item *prev;
fz_store *store;
-};
-
-struct refkey
-{
- fz_store_free_fn *free;
- int num;
- int gen;
+ fz_store_type *type;
};
struct fz_store_s
@@ -43,7 +36,7 @@ fz_new_store_context(fz_context *ctx, unsigned int max)
store = fz_malloc_struct(ctx, fz_store);
fz_try(ctx)
{
- store->hash = fz_new_hash_table(ctx, 4096, sizeof(struct refkey));
+ store->hash = fz_new_hash_table(ctx, 4096, sizeof(fz_store_hash), FZ_LOCK_ALLOC);
}
fz_catch(ctx)
{
@@ -114,20 +107,19 @@ evict(fz_context *ctx, fz_item *item)
store->head = item->next;
/* Drop a reference to the value (freeing if required) */
drop = (item->val->refs > 0 && --item->val->refs == 0);
- fz_unlock(ctx, FZ_LOCK_ALLOC);
/* Remove from the hash table */
- if (fz_is_indirect(item->key))
+ if (item->type->make_hash_key)
{
- struct refkey refkey;
- refkey.free = item->val->free;
- refkey.num = fz_to_num(item->key);
- refkey.gen = fz_to_gen(item->key);
- fz_hash_remove(ctx, store->hash, &refkey);
+ fz_store_hash hash = { NULL };
+ hash.free = item->val->free;
+ if (item->type->make_hash_key(&hash, item->key))
+ fz_hash_remove(ctx, store->hash, &hash);
}
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
if (drop)
item->val->free(ctx, item->val);
/* Always drops the key and free the item */
- fz_drop_obj(item->key);
+ item->type->drop_key(ctx, item->key);
fz_free(ctx, item);
fz_lock(ctx, FZ_LOCK_ALLOC);
}
@@ -194,30 +186,21 @@ ensure_space(fz_context *ctx, unsigned int tofree)
return count;
}
-void
-fz_store_item(fz_context *ctx, fz_obj *key, void *val_, unsigned int itemsize)
+void *
+fz_store_item(fz_context *ctx, void *key, void *val_, unsigned int itemsize, fz_store_type *type)
{
fz_item *item = NULL;
unsigned int size;
fz_storable *val = (fz_storable *)val_;
fz_store *store = ctx->store;
- int indirect;
- struct refkey refkey;
+ fz_store_hash hash = { NULL };
+ int use_hash = 0;
if (!store)
- return;
+ return NULL;
fz_var(item);
- /* Form the key before we take the lock */
- indirect = fz_is_indirect(key);
- if (indirect)
- {
- refkey.free = val->free;
- refkey.num = fz_to_num(key);
- refkey.gen = fz_to_gen(key);
- }
-
/* If we fail for any reason, we swallow the exception and continue.
* All that the above program will see is that we failed to store
* the item. */
@@ -227,9 +210,16 @@ fz_store_item(fz_context *ctx, fz_obj *key, void *val_, unsigned int itemsize)
}
fz_catch(ctx)
{
- return;
+ return NULL;
}
+ if (type->make_hash_key)
+ {
+ hash.free = val->free;
+ use_hash = type->make_hash_key(&hash, key);
+ }
+
+ type->keep_key(ctx, key);
fz_lock(ctx, FZ_LOCK_ALLOC);
if (store->max != FZ_STORE_UNLIMITED)
{
@@ -242,34 +232,41 @@ fz_store_item(fz_context *ctx, fz_obj *key, void *val_, unsigned int itemsize)
/* Failed to free any space */
fz_unlock(ctx, FZ_LOCK_ALLOC);
fz_free(ctx, item);
- return;
+ type->drop_key(ctx, key);
+ return NULL;
}
}
}
store->size += itemsize;
- item->key = fz_keep_obj(key);
+ item->key = key;
item->val = val;
item->size = itemsize;
item->next = NULL;
+ item->type = type;
/* If we can index it fast, put it into the hash table */
- if (indirect)
+ if (use_hash)
{
- fz_unlock(ctx, FZ_LOCK_ALLOC);
+ fz_pixmap *existing;
+
fz_try(ctx)
{
- fz_hash_insert(ctx, store->hash, &refkey, item);
+ /* May drop and retake the lock */
+ existing = fz_hash_insert(ctx, store->hash, &hash, item);
}
fz_catch(ctx)
{
- fz_free(ctx, item);
- fz_lock(ctx, FZ_LOCK_ALLOC);
store->size -= itemsize;
fz_unlock(ctx, FZ_LOCK_ALLOC);
- return;
+ fz_free(ctx, item);
+ return NULL;
+ }
+ if (existing)
+ {
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
+ return existing;
}
- fz_lock(ctx, FZ_LOCK_ALLOC);
}
/* Now we can never fail, bump the ref */
if (val->refs > 0)
@@ -283,15 +280,17 @@ fz_store_item(fz_context *ctx, fz_obj *key, void *val_, unsigned int itemsize)
store->head = item;
item->prev = NULL;
fz_unlock(ctx, FZ_LOCK_ALLOC);
+
+ return NULL;
}
void *
-fz_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key)
+fz_find_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type)
{
- struct refkey refkey;
fz_item *item;
fz_store *store = ctx->store;
- int indirect;
+ fz_store_hash hash = { NULL };
+ int use_hash = 0;
if (!store)
return NULL;
@@ -299,27 +298,24 @@ fz_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key)
if (!key)
return NULL;
- /* Form the key before we take the lock */
- indirect = fz_is_indirect(key);
- if (indirect)
+ if (type->make_hash_key)
{
- refkey.free = free;
- refkey.num = fz_to_num(key);
- refkey.gen = fz_to_gen(key);
+ hash.free = free;
+ use_hash = type->make_hash_key(&hash, key);
}
fz_lock(ctx, FZ_LOCK_ALLOC);
- if (indirect)
+ if (use_hash)
{
/* We can find objects keyed on indirected objects quickly */
- item = fz_hash_find(ctx, store->hash, &refkey);
+ item = fz_hash_find(ctx, store->hash, &hash);
}
else
{
/* Others we have to hunt for slowly */
for (item = store->head; item; item = item->next)
{
- if (item->val->free == free && !fz_objcmp(item->key, key))
+ if (item->val->free == free && !type->cmp_key(item->key, key))
break;
}
}
@@ -355,35 +351,33 @@ fz_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key)
}
void
-fz_remove_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key)
+fz_remove_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type)
{
- struct refkey refkey;
fz_item *item;
fz_store *store = ctx->store;
- int drop, indirect;
+ int drop;
+ fz_store_hash hash;
+ int use_hash = 0;
- /* Form the key before we take the lock */
- indirect = fz_is_indirect(key);
- if (indirect)
+ if (type->make_hash_key)
{
- refkey.free = free;
- refkey.num = fz_to_num(key);
- refkey.gen = fz_to_gen(key);
+ hash.free = free;
+ use_hash = type->make_hash_key(&hash, key);
}
fz_lock(ctx, FZ_LOCK_ALLOC);
- if (indirect)
+ if (use_hash)
{
/* We can find objects keyed on indirect objects quickly */
- item = fz_hash_find(ctx, store->hash, &refkey);
+ item = fz_hash_find(ctx, store->hash, &hash);
if (item)
- fz_hash_remove(ctx, store->hash, &refkey);
+ fz_hash_remove(ctx, store->hash, &hash);
}
else
{
/* Others we have to hunt for slowly */
for (item = store->head; item; item = item->next)
- if (item->val->free == free && !fz_objcmp(item->key, key))
+ if (item->val->free == free && !type->cmp_key(item->key, key))
break;
}
if (item)
@@ -400,7 +394,7 @@ fz_remove_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key)
fz_unlock(ctx, FZ_LOCK_ALLOC);
if (drop)
item->val->free(ctx, item->val);
- fz_drop_obj(item->key);
+ type->drop_key(ctx, item->key);
fz_free(ctx, item);
}
else
diff --git a/fitz/stm_read.c b/fitz/stm_read.c
index 2066b14c..81411c54 100644
--- a/fitz/stm_read.c
+++ b/fitz/stm_read.c
@@ -101,7 +101,7 @@ fz_read_all(fz_stream *stm, int initial)
if (initial < 1024)
initial = 1024;
- buf = fz_new_buffer(ctx, initial);
+ buf = fz_new_buffer(ctx, initial+1);
while (1)
{
@@ -110,7 +110,6 @@ fz_read_all(fz_stream *stm, int initial)
if (buf->len / 200 > initial)
{
- fz_drop_buffer(ctx, buf);
fz_throw(ctx, "compression bomb detected");
}
diff --git a/pdf/mupdf.h b/pdf/mupdf.h
index 39245177..b233288f 100644
--- a/pdf/mupdf.h
+++ b/pdf/mupdf.h
@@ -5,6 +5,83 @@
#error "fitz.h must be included before mupdf.h"
#endif
+/*
+ * PDF Images
+ */
+
+typedef struct pdf_image_params_s pdf_image_params;
+
+struct pdf_image_params_s
+{
+ int type;
+ fz_colorspace *colorspace;
+ union
+ {
+ struct
+ {
+ int columns;
+ int rows;
+ int k;
+ int eol;
+ int eba;
+ int eob;
+ int bi1;
+ }
+ fax;
+ struct
+ {
+ int ct;
+ }
+ jpeg;
+ struct
+ {
+ int columns;
+ int colors;
+ int predictor;
+ int bpc;
+ }
+ flate;
+ struct
+ {
+ int columns;
+ int colors;
+ int predictor;
+ int bpc;
+ int ec;
+ }
+ lzw;
+ }
+ u;
+};
+
+
+typedef struct pdf_image_s pdf_image;
+
+struct pdf_image_s
+{
+ fz_image base;
+ fz_pixmap *tile;
+ int n, bpc;
+ pdf_image_params params;
+ fz_buffer *buffer;
+ int colorkey[FZ_MAX_COLORS * 2];
+ float decode[FZ_MAX_COLORS * 2];
+ int imagemask;
+ int interpolate;
+ int usecolorkey;
+};
+
+enum
+{
+ PDF_IMAGE_RAW,
+ PDF_IMAGE_FAX,
+ PDF_IMAGE_JPEG,
+ PDF_IMAGE_RLD,
+ PDF_IMAGE_FLATE,
+ PDF_IMAGE_LZW,
+ PDF_IMAGE_JPX
+};
+
typedef struct pdf_document_s pdf_document;
/*
@@ -102,12 +179,15 @@ fz_obj *pdf_load_object(pdf_document *doc, int num, int gen);
void pdf_update_object(pdf_document *doc, int num, int gen, fz_obj *newobj);
int pdf_is_stream(pdf_document *doc, int num, int gen);
-fz_stream *pdf_open_inline_stream(pdf_document *doc, fz_obj *stmobj, int length, fz_stream *chain);
+fz_stream *pdf_open_inline_stream(pdf_document *doc, fz_obj *stmobj, int length, fz_stream *chain, pdf_image_params *params);
fz_buffer *pdf_load_raw_stream(pdf_document *doc, int num, int gen);
fz_buffer *pdf_load_stream(pdf_document *doc, int num, int gen);
+fz_buffer *pdf_load_image_stream(pdf_document *doc, int num, int gen, pdf_image_params *params);
fz_stream *pdf_open_raw_stream(pdf_document *doc, int num, int gen);
+fz_stream *pdf_open_image_stream(pdf_document *doc, int num, int gen, pdf_image_params *params);
fz_stream *pdf_open_stream(pdf_document *doc, int num, int gen);
fz_stream *pdf_open_stream_with_offset(pdf_document *doc, int num, int gen, fz_obj *dict, int stm_ofs);
+fz_stream *pdf_open_image_decomp_stream(fz_context *ctx, fz_buffer *, pdf_image_params *params, int *factor);
pdf_document *pdf_open_document_with_stream(fz_stream *file);
pdf_document *pdf_open_document(fz_context *ctx, const char *filename);
@@ -171,8 +251,8 @@ fz_pixmap *pdf_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src);
fz_shade *pdf_load_shading(pdf_document *doc, fz_obj *obj);
-fz_pixmap *pdf_load_inline_image(pdf_document *doc, fz_obj *rdb, fz_obj *dict, fz_stream *file);
-fz_pixmap *pdf_load_image(pdf_document *doc, fz_obj *obj);
+fz_image *pdf_load_inline_image(pdf_document *doc, fz_obj *rdb, fz_obj *dict, fz_stream *file);
+fz_image *pdf_load_image(pdf_document *doc, fz_obj *obj);
int pdf_is_jpx_image(fz_context *ctx, fz_obj *dict);
/*
@@ -471,4 +551,12 @@ void pdf_run_page_with_usage(pdf_document *doc, pdf_page *page, fz_device *dev,
void pdf_run_page(pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie);
void pdf_run_glyph(pdf_document *doc, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate);
+/*
+ * PDF interface to store
+ */
+
+void pdf_store_item(fz_context *ctx, fz_obj *key, void *val, unsigned int itemsize);
+void *pdf_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key);
+void pdf_remove_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key);
+
#endif
diff --git a/pdf/pdf_cmap_load.c b/pdf/pdf_cmap_load.c
index 3257516c..9e6b13ce 100644
--- a/pdf/pdf_cmap_load.c
+++ b/pdf/pdf_cmap_load.c
@@ -31,7 +31,7 @@ pdf_load_embedded_cmap(pdf_document *xref, fz_obj *stmobj)
fz_var(file);
fz_var(cmap);
- if ((cmap = fz_find_item(ctx, pdf_free_cmap_imp, stmobj)))
+ if ((cmap = pdf_find_item(ctx, pdf_free_cmap_imp, stmobj)))
{
return cmap;
}
@@ -63,7 +63,7 @@ pdf_load_embedded_cmap(pdf_document *xref, fz_obj *stmobj)
pdf_drop_cmap(ctx, usecmap);
}
- fz_store_item(ctx, stmobj, cmap, pdf_cmap_size(ctx, cmap));
+ pdf_store_item(ctx, stmobj, cmap, pdf_cmap_size(ctx, cmap));
}
fz_catch(ctx)
{
diff --git a/pdf/pdf_colorspace.c b/pdf/pdf_colorspace.c
index 7a410df8..a6515d42 100644
--- a/pdf/pdf_colorspace.c
+++ b/pdf/pdf_colorspace.c
@@ -395,7 +395,7 @@ pdf_load_colorspace(pdf_document *xref, fz_obj *obj)
fz_context *ctx = xref->ctx;
fz_colorspace *cs;
- if ((cs = fz_find_item(ctx, fz_free_colorspace_imp, obj)))
+ if ((cs = pdf_find_item(ctx, fz_free_colorspace_imp, obj)))
{
return cs;
}
@@ -403,7 +403,7 @@ pdf_load_colorspace(pdf_document *xref, fz_obj *obj)
cs = pdf_load_colorspace_imp(xref, obj);
/* RJW: "cannot load colorspace (%d %d R)", fz_to_num(obj), fz_to_gen(obj) */
- fz_store_item(ctx, obj, cs, cs->size);
+ pdf_store_item(ctx, obj, cs, cs->size);
return cs;
}
diff --git a/pdf/pdf_font.c b/pdf/pdf_font.c
index 3e30c332..fd2afab2 100644
--- a/pdf/pdf_font.c
+++ b/pdf/pdf_font.c
@@ -1081,7 +1081,7 @@ pdf_load_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict)
fz_context *ctx = xref->ctx;
pdf_font_desc *fontdesc;
- if ((fontdesc = fz_find_item(ctx, pdf_free_font_imp, dict)))
+ if ((fontdesc = pdf_find_item(ctx, pdf_free_font_imp, dict)))
{
return fontdesc;
}
@@ -1121,7 +1121,7 @@ pdf_load_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict)
if (fontdesc->font->ft_substitute && !fontdesc->to_ttf_cmap)
pdf_make_width_table(ctx, fontdesc);
- fz_store_item(ctx, dict, fontdesc, fontdesc->size);
+ pdf_store_item(ctx, dict, fontdesc, fontdesc->size);
return fontdesc;
}
diff --git a/pdf/pdf_function.c b/pdf/pdf_function.c
index 23acc4db..4478827c 100644
--- a/pdf/pdf_function.c
+++ b/pdf/pdf_function.c
@@ -1362,7 +1362,7 @@ pdf_load_function(pdf_document *xref, fz_obj *dict)
fz_obj *obj;
int i;
- if ((func = fz_find_item(ctx, pdf_free_function_imp, dict)))
+ if ((func = pdf_find_item(ctx, pdf_free_function_imp, dict)))
{
return func;
}
@@ -1432,7 +1432,7 @@ pdf_load_function(pdf_document *xref, fz_obj *dict)
fz_throw(ctx, "unknown function type (%d %d R)", fz_to_num(dict), fz_to_gen(dict));
}
- fz_store_item(ctx, dict, func, func->size);
+ pdf_store_item(ctx, dict, func, func->size);
}
fz_catch(ctx)
{
diff --git a/pdf/pdf_image.c b/pdf/pdf_image.c
index 3aa26f08..9626d6f0 100644
--- a/pdf/pdf_image.c
+++ b/pdf/pdf_image.c
@@ -1,10 +1,15 @@
#include "fitz.h"
#include "mupdf.h"
-/* TODO: store JPEG compressed samples */
-/* TODO: store flate compressed samples */
+typedef struct pdf_image_key_s pdf_image_key;
-static fz_pixmap *pdf_load_jpx(pdf_document *xref, fz_obj *dict);
+struct pdf_image_key_s {
+ int refs;
+ fz_image *image;
+ int factor;
+};
+
+static void pdf_load_jpx(pdf_document *xref, fz_obj *dict, pdf_image *image);
static void
pdf_mask_color_key(fz_pixmap *pix, int n, int *colorkey)
@@ -25,49 +30,293 @@ pdf_mask_color_key(fz_pixmap *pix, int n, int *colorkey)
}
}
+static int
+pdf_make_hash_image_key(fz_store_hash *hash, void *key_)
+{
+ pdf_image_key *key = (pdf_image_key *)key_;
+
+ hash->u.pi.ptr = key->image;
+ hash->u.pi.i = key->factor;
+ return 1;
+}
+
+static void *
+pdf_keep_image_key(fz_context *ctx, void *key_)
+{
+ pdf_image_key *key = (pdf_image_key *)key_;
+
+ fz_lock(ctx, FZ_LOCK_ALLOC);
+ key->refs++;
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
+
+ return (void *)key;
+}
+
+static void
+pdf_drop_image_key(fz_context *ctx, void *key_)
+{
+ pdf_image_key *key = (pdf_image_key *)key_;
+ int drop;
+
+ fz_lock(ctx, FZ_LOCK_ALLOC);
+ drop = --key->refs;
+ fz_unlock(ctx, FZ_LOCK_ALLOC);
+ if (drop == 0)
+ {
+ fz_drop_image(ctx, key->image);
+ fz_free(ctx, key);
+ }
+}
+
+static int
+pdf_cmp_image_key(void *k0_, void *k1_)
+{
+ pdf_image_key *k0 = (pdf_image_key *)k0_;
+ pdf_image_key *k1 = (pdf_image_key *)k1_;
+
+ return k0->image == k1->image && k0->factor == k1->factor;
+}
+
+static fz_store_type pdf_image_store_type =
+{
+ pdf_make_hash_image_key,
+ pdf_keep_image_key,
+ pdf_drop_image_key,
+ pdf_cmp_image_key
+};
+
static fz_pixmap *
+decomp_image_from_stream(fz_context *ctx, fz_stream *stm, pdf_image *image, int in_line, int indexed, int factor)
+{
+ fz_pixmap *tile = NULL;
+ fz_pixmap *existing_tile;
+ int stride, len, i;
+ unsigned char *samples = NULL;
+ int w = (image->base.w + (factor-1)) / factor;
+ int h = (image->base.h + (factor-1)) / factor;
+ pdf_image_key *key;
+
+ fz_var(tile);
+ fz_var(samples);
+
+ fz_try(ctx)
+ {
+ tile = fz_new_pixmap(ctx, image->base.colorspace, w, h);
+ tile->mask = fz_image_to_pixmap(ctx, image->base.mask, w, h);
+ tile->interpolate = image->interpolate;
+
+ stride = (w * image->n * image->bpc + 7) / 8;
+
+ samples = fz_malloc_array(ctx, h, stride);
+
+ len = fz_read(stm, samples, h * stride);
+ if (len < 0)
+ {
+ fz_throw(ctx, "cannot read image data");
+ }
+
+ /* Make sure we read the EOF marker (for inline images only) */
+ if (in_line)
+ {
+ unsigned char tbuf[512];
+ fz_try(ctx)
+ {
+ int tlen = fz_read(stm, tbuf, sizeof tbuf);
+ if (tlen > 0)
+ fz_warn(ctx, "ignoring garbage at end of image");
+ }
+ fz_catch(ctx)
+ {
+ fz_warn(ctx, "ignoring error at end of image");
+ }
+ }
+
+ /* Pad truncated images */
+ if (len < stride * h)
+ {
+ fz_warn(ctx, "padding truncated image");
+ memset(samples + len, 0, stride * h - len);
+ }
+
+ /* Invert 1-bit image masks */
+ if (image->imagemask)
+ {
+ /* 0=opaque and 1=transparent so we need to invert */
+ unsigned char *p = samples;
+ len = h * stride;
+ for (i = 0; i < len; i++)
+ p[i] = ~p[i];
+ }
+
+ fz_unpack_tile(tile, samples, image->n, image->bpc, stride, indexed);
+
+ fz_free(ctx, samples);
+ samples = NULL;
+
+ if (image->usecolorkey)
+ pdf_mask_color_key(tile, image->n, image->colorkey);
+
+ if (indexed)
+ {
+ fz_pixmap *conv;
+ fz_decode_indexed_tile(tile, image->decode, (1 << image->bpc) - 1);
+ conv = pdf_expand_indexed_pixmap(ctx, tile);
+ fz_drop_pixmap(ctx, tile);
+ tile = conv;
+ }
+ else
+ {
+ fz_decode_tile(tile, image->decode);
+ }
+ }
+ fz_always(ctx)
+ {
+ fz_close(stm);
+ }
+ fz_catch(ctx)
+ {
+ if (tile)
+ fz_drop_pixmap(ctx, tile);
+ fz_free(ctx, samples);
+
+ fz_rethrow(ctx);
+ }
+
+ /* Now we try to cache the pixmap. Any failure here will just result
+ * in us not caching. */
+ fz_try(ctx)
+ {
+ key = fz_malloc_struct(ctx, pdf_image_key);
+ key->refs = 1;
+ key->image = fz_keep_image(ctx, &image->base);
+ key->factor = factor;
+ existing_tile = fz_store_item(ctx, key, tile, fz_pixmap_size(ctx, tile), &pdf_image_store_type);
+ if (existing_tile)
+ {
+ /* We already have a tile. This must have been produced by a
+ * racing thread. We'll throw away ours and use that one. */
+ fz_drop_pixmap(ctx, tile);
+ fz_free(ctx, key);
+ tile = existing_tile;
+ }
+ }
+ fz_always(ctx)
+ {
+ pdf_drop_image_key(ctx, key);
+ }
+ fz_catch(ctx)
+ {
+ /* Do nothing */
+ }
+
+ return tile;
+}
+
+static void
+pdf_free_image(fz_context *ctx, fz_storable *image_)
+{
+ pdf_image *image = (pdf_image *)image_;
+
+ if (image == NULL)
+ return;
+ fz_drop_pixmap(ctx, image->tile);
+ fz_drop_buffer(ctx, image->buffer);
+ fz_drop_colorspace(ctx, image->base.colorspace);
+ fz_drop_image(ctx, image->base.mask);
+ fz_free(ctx, image);
+}
+
+static fz_pixmap *
+pdf_image_get_pixmap(fz_context *ctx, fz_image *image_, int w, int h)
+{
+ pdf_image *image = (pdf_image *)image_;
+ fz_pixmap *tile;
+ fz_stream *stm;
+ int factor;
+ pdf_image_key key;
+
+ /* Check for 'simple' images which are just pixmaps */
+ if (image->buffer == NULL)
+ {
+ tile = image->tile;
+ if (!tile)
+ return NULL;
+ if (image->base.mask)
+ {
+ fz_drop_pixmap(ctx, tile->mask);
+ tile->mask = fz_image_to_pixmap(ctx, image->base.mask, w, h);
+ }
+ return fz_keep_pixmap(ctx, tile); /* That's all we can give you! */
+ }
+
+ /* Ensure our expectations for tile size are reasonable */
+ if (w > image->base.w)
+ w = image->base.w;
+ if (h > image->base.h)
+ h = image->base.h;
+
+ /* What is our ideal factor? */
+ if (w == 0 || h == 0)
+ factor = 1;
+ else
+ for (factor=1; image->base.w/(2*factor) >= w && image->base.h/(2*factor) >= h && factor < 8; factor *= 2);
+
+ /* Can we find any suitable tiles in the cache? */
+ key.refs = 1;
+ key.image = &image->base;
+ key.factor = factor;
+ do
+ {
+ tile = fz_find_item(ctx, fz_free_pixmap_imp, &key, &pdf_image_store_type);
+ if (tile)
+ return tile;
+ key.factor >>= 1;
+ }
+ while (key.factor > 0);
+
+ /* We need to make a new one. */
+ stm = pdf_open_image_decomp_stream(ctx, image->buffer, &image->params, &factor);
+
+ return decomp_image_from_stream(ctx, stm, image, 0, 0, factor);
+}
+
+static pdf_image *
pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cstm, int forcemask)
{
fz_stream *stm = NULL;
- fz_pixmap *tile = NULL;
+ pdf_image *image = NULL;
fz_obj *obj, *res;
int w, h, bpc, n;
int imagemask;
int interpolate;
int indexed;
- fz_colorspace *colorspace = NULL;
- fz_pixmap *mask = NULL; /* explicit mask/softmask image */
+ fz_image *mask = NULL; /* explicit mask/softmask image */
int usecolorkey;
- int colorkey[FZ_MAX_COLORS * 2];
- float decode[FZ_MAX_COLORS * 2];
- int stride;
- unsigned char *samples = NULL;
- int i, len;
+ int i;
fz_context *ctx = xref->ctx;
fz_var(stm);
- fz_var(tile);
- fz_var(colorspace);
fz_var(mask);
- fz_var(samples);
+
+ image = fz_malloc_struct(ctx, pdf_image);
fz_try(ctx)
{
/* special case for JPEG2000 images */
if (pdf_is_jpx_image(ctx, dict))
{
- tile = pdf_load_jpx(xref, dict);
+ pdf_load_jpx(xref, dict, image);
/* RJW: "cannot load jpx image" */
if (forcemask)
{
- if (tile->n != 2)
+ fz_pixmap *mask_pixmap;
+ if (image->n != 2)
fz_throw(ctx, "softmask must be grayscale");
- mask = fz_alpha_from_gray(ctx, tile, 1);
- fz_drop_pixmap(ctx, tile);
- tile = mask;
- mask = NULL;
+ mask_pixmap = fz_alpha_from_gray(ctx, image->tile, 1);
+ fz_drop_pixmap(ctx, image->tile);
+ image->tile = mask_pixmap;
}
break; /* Out of fz_try */
}
@@ -109,13 +358,13 @@ pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cst
obj = res;
}
- colorspace = pdf_load_colorspace(xref, obj);
+ image->base.colorspace = pdf_load_colorspace(xref, obj);
/* RJW: "cannot load image colorspace" */
- if (!strcmp(colorspace->name, "Indexed"))
+ if (!strcmp(image->base.colorspace->name, "Indexed"))
indexed = 1;
- n = colorspace->n;
+ n = image->base.colorspace->n;
}
else
{
@@ -126,13 +375,13 @@ pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cst
if (obj)
{
for (i = 0; i < n * 2; i++)
- decode[i] = fz_to_real(fz_array_get(obj, i));
+ image->decode[i] = fz_to_real(fz_array_get(obj, i));
}
else
{
float maxval = indexed ? (1 << bpc) - 1 : 1;
for (i = 0; i < n * 2; i++)
- decode[i] = i & 1 ? maxval : 0;
+ image->decode[i] = i & 1 ? maxval : 0;
}
obj = fz_dict_getsa(dict, "SMask", "Mask");
@@ -141,7 +390,7 @@ pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cst
/* Not allowed for inline images */
if (!cstm)
{
- mask = pdf_load_image_imp(xref, rdb, obj, NULL, 1);
+ mask = (fz_image *)pdf_load_image_imp(xref, rdb, obj, NULL, 1);
/* RJW: "cannot load image mask/softmask" */
}
}
@@ -155,36 +404,36 @@ pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cst
fz_warn(ctx, "invalid value in color key mask");
usecolorkey = 0;
}
- colorkey[i] = fz_to_int(fz_array_get(obj, i));
+ image->colorkey[i] = fz_to_int(fz_array_get(obj, i));
}
}
- /* Allocate now, to fail early if we run out of memory */
- fz_try(ctx)
- {
- tile = fz_new_pixmap(ctx, colorspace, w, h);
- }
- fz_catch(ctx)
+ /* Now, do we load a ref, or do we load the actual thing? */
+ image->params.type = PDF_IMAGE_RAW;
+ FZ_INIT_STORABLE(&image->base, 1, pdf_free_image);
+ image->base.get_pixmap = pdf_image_get_pixmap;
+ image->base.w = w;
+ image->base.h = h;
+ image->n = n;
+ image->bpc = bpc;
+ image->interpolate = interpolate;
+ image->imagemask = imagemask;
+ image->usecolorkey = usecolorkey;
+ image->base.mask = mask;
+ image->params.colorspace = image->base.colorspace; /* Uses the same ref as for the base one */
+ if (!indexed && !cstm)
{
- fz_drop_colorspace(ctx, colorspace);
- fz_rethrow(ctx);
- }
-
- if (colorspace)
- {
- fz_drop_colorspace(ctx, colorspace);
- colorspace = NULL;
+ /* Just load the compressed image data now and we can
+ * decode it on demand. */
+ image->buffer = pdf_load_image_stream(xref, fz_to_num(dict), fz_to_gen(dict), &image->params);
+ break; /* Out of fz_try */
}
- tile->mask = mask;
- mask = NULL;
- tile->interpolate = interpolate;
-
- stride = (w * n * bpc + 7) / 8;
-
+ /* We need to decompress the image now */
if (cstm)
{
- stm = pdf_open_inline_stream(xref, dict, stride * h, cstm);
+ int stride = (w * image->n * image->bpc + 7) / 8;
+ stm = pdf_open_inline_stream(xref, dict, stride * h, cstm, NULL);
}
else
{
@@ -192,92 +441,20 @@ pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cst
/* RJW: "cannot open image data stream (%d 0 R)", fz_to_num(dict) */
}
- samples = fz_malloc_array(ctx, h, stride);
-
- len = fz_read(stm, samples, h * stride);
- if (len < 0)
- {
- fz_throw(ctx, "cannot read image data");
- }
-
- /* Make sure we read the EOF marker (for inline images only) */
- if (cstm)
- {
- unsigned char tbuf[512];
- fz_try(ctx)
- {
- int tlen = fz_read(stm, tbuf, sizeof tbuf);
- if (tlen > 0)
- fz_warn(ctx, "ignoring garbage at end of image");
- }
- fz_catch(ctx)
- {
- fz_warn(ctx, "ignoring error at end of image");
- }
- }
-
- fz_close(stm);
- stm = NULL;
-
- /* Pad truncated images */
- if (len < stride * h)
- {
- fz_warn(ctx, "padding truncated image (%d 0 R)", fz_to_num(dict));
- memset(samples + len, 0, stride * h - len);
- }
-
- /* Invert 1-bit image masks */
- if (imagemask)
- {
- /* 0=opaque and 1=transparent so we need to invert */
- unsigned char *p = samples;
- len = h * stride;
- for (i = 0; i < len; i++)
- p[i] = ~p[i];
- }
-
- fz_unpack_tile(tile, samples, n, bpc, stride, indexed);
-
- fz_free(ctx, samples);
- samples = NULL;
-
- if (usecolorkey)
- pdf_mask_color_key(tile, n, colorkey);
-
- if (indexed)
- {
- fz_pixmap *conv;
- fz_decode_indexed_tile(tile, decode, (1 << bpc) - 1);
- conv = pdf_expand_indexed_pixmap(ctx, tile);
- fz_drop_pixmap(ctx, tile);
- tile = conv;
- }
- else
- {
- fz_decode_tile(tile, decode);
- }
+ image->tile = decomp_image_from_stream(ctx, stm, image, cstm != NULL, indexed, 1);
}
fz_catch(ctx)
{
- if (colorspace)
- fz_drop_colorspace(ctx, colorspace);
- if (mask)
- fz_drop_pixmap(ctx, mask);
- if (tile)
- fz_drop_pixmap(ctx, tile);
- fz_close(stm);
- fz_free(ctx, samples);
-
+ fz_drop_image(ctx, &image->base);
fz_rethrow(ctx);
}
-
- return tile;
+ return image;
}
-fz_pixmap *
+fz_image *
pdf_load_inline_image(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *file)
{
- return pdf_load_image_imp(xref, rdb, dict, file, 0);
+ return (fz_image *)pdf_load_image_imp(xref, rdb, dict, file, 0);
/* RJW: "cannot load inline image" */
}
@@ -297,8 +474,8 @@ pdf_is_jpx_image(fz_context *ctx, fz_obj *dict)
return 0;
}
-static fz_pixmap *
-pdf_load_jpx(pdf_document *xref, fz_obj *dict)
+static void
+pdf_load_jpx(pdf_document *xref, fz_obj *dict, pdf_image *image)
{
fz_buffer *buf = NULL;
fz_colorspace *colorspace = NULL;
@@ -328,18 +505,13 @@ pdf_load_jpx(pdf_document *xref, fz_obj *dict)
img = fz_load_jpx(ctx, buf->data, buf->len, colorspace);
/* RJW: "cannot load jpx image" */
- if (colorspace)
- {
- fz_drop_colorspace(ctx, colorspace);
- colorspace = NULL;
- }
fz_drop_buffer(ctx, buf);
buf = NULL;
obj = fz_dict_getsa(dict, "SMask", "Mask");
if (fz_is_dict(obj))
{
- img->mask = pdf_load_image_imp(xref, NULL, obj, NULL, 1);
+ image->base.mask = (fz_image *)pdf_load_image_imp(xref, NULL, obj, NULL, 1);
/* RJW: "cannot load image mask/softmask" */
}
@@ -363,24 +535,44 @@ pdf_load_jpx(pdf_document *xref, fz_obj *dict)
fz_drop_pixmap(ctx, img);
fz_rethrow(ctx);
}
- return img;
+ image->params.type = PDF_IMAGE_RAW;
+ FZ_INIT_STORABLE(&image->base, 1, pdf_free_image);
+ image->base.get_pixmap = pdf_image_get_pixmap;
+ image->base.w = img->w;
+ image->base.h = img->h;
+ image->base.colorspace = colorspace;
+ image->tile = img;
+ image->n = img->n;
+ image->bpc = 8;
+ image->interpolate = 0;
+ image->imagemask = 0;
+ image->usecolorkey = 0;
+ image->params.colorspace = colorspace; /* Uses the same ref as for the base one */
+}
+
+static int
+pdf_image_size(fz_context *ctx, pdf_image *im)
+{
+ if (im == NULL)
+ return 0;
+ return sizeof(*im) + fz_pixmap_size(ctx, im->tile) + (im->buffer ? im->buffer->cap : 0);
}
-fz_pixmap *
+fz_image *
pdf_load_image(pdf_document *xref, fz_obj *dict)
{
fz_context *ctx = xref->ctx;
- fz_pixmap *pix;
+ pdf_image *image;
- if ((pix = fz_find_item(ctx, fz_free_pixmap_imp, dict)))
+ if ((image = pdf_find_item(ctx, pdf_free_image, dict)))
{
- return pix;
+ return (fz_image *)image;
}
- pix = pdf_load_image_imp(xref, NULL, dict, NULL, 0);
+ image = pdf_load_image_imp(xref, NULL, dict, NULL, 0);
/* RJW: "cannot load image (%d 0 R)", fz_to_num(dict) */
- fz_store_item(ctx, dict, pix, fz_pixmap_size(ctx, pix));
+ pdf_store_item(ctx, dict, image, pdf_image_size(ctx, image));
- return pix;
+ return (fz_image *)image;
}
diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c
index ea7f7692..effea657 100644
--- a/pdf/pdf_interpret.c
+++ b/pdf/pdf_interpret.c
@@ -362,7 +362,7 @@ pdf_show_shade(pdf_csi *csi, fz_shade *shd)
}
static void
-pdf_show_image(pdf_csi *csi, fz_pixmap *image)
+pdf_show_image(pdf_csi *csi, fz_image *image)
{
pdf_gstate *gstate = csi->gstate + csi->gtop;
fz_matrix image_ctm;
@@ -1627,7 +1627,7 @@ static void pdf_run_BI(pdf_csi *csi, fz_obj *rdb, fz_stream *file)
int ch;
char *buf = csi->xref->scratch;
int buflen = sizeof(csi->xref->scratch);
- fz_pixmap *img;
+ fz_image *img;
fz_obj *obj;
obj = pdf_parse_dict(csi->xref, file, buf, buflen);
@@ -1645,7 +1645,7 @@ static void pdf_run_BI(pdf_csi *csi, fz_obj *rdb, fz_stream *file)
pdf_show_image(csi, img);
- fz_drop_pixmap(ctx, img);
+ fz_drop_image(ctx, img);
/* find EI */
ch = fz_read_byte(file);
@@ -1798,19 +1798,20 @@ static void pdf_run_Do(pdf_csi *csi, fz_obj *rdb)
{
if ((csi->dev->hints & FZ_IGNORE_IMAGE) == 0)
{
- fz_pixmap *img;
- img = pdf_load_image(csi->xref, obj);
+ fz_image *img = pdf_load_image(csi->xref, obj);
/* RJW: "cannot load image (%d %d R)", fz_to_num(obj), fz_to_gen(obj) */
fz_try(ctx)
{
pdf_show_image(csi, img);
}
+ fz_always(ctx)
+ {
+ fz_drop_image(ctx, img);
+ }
fz_catch(ctx)
{
- fz_drop_pixmap(ctx, img);
fz_rethrow(ctx);
}
- fz_drop_pixmap(ctx, img);
}
}
diff --git a/pdf/pdf_pattern.c b/pdf/pdf_pattern.c
index 9ffbee02..c1869474 100644
--- a/pdf/pdf_pattern.c
+++ b/pdf/pdf_pattern.c
@@ -40,7 +40,7 @@ pdf_load_pattern(pdf_document *xref, fz_obj *dict)
fz_obj *obj;
fz_context *ctx = xref->ctx;
- if ((pat = fz_find_item(ctx, pdf_free_pattern_imp, dict)))
+ if ((pat = pdf_find_item(ctx, pdf_free_pattern_imp, dict)))
{
return pat;
}
@@ -51,7 +51,7 @@ pdf_load_pattern(pdf_document *xref, fz_obj *dict)
pat->contents = NULL;
/* Store pattern now, to avoid possible recursion if objects refer back to this one */
- fz_store_item(ctx, dict, pat, pdf_pattern_size(pat));
+ pdf_store_item(ctx, dict, pat, pdf_pattern_size(pat));
pat->ismask = fz_to_int(fz_dict_gets(dict, "PaintType")) == 2;
pat->xstep = fz_to_real(fz_dict_gets(dict, "XStep"));
@@ -76,7 +76,7 @@ pdf_load_pattern(pdf_document *xref, fz_obj *dict)
}
fz_catch(ctx)
{
- fz_remove_item(ctx, pdf_free_pattern_imp, dict);
+ pdf_remove_item(ctx, pdf_free_pattern_imp, dict);
pdf_drop_pattern(ctx, pat);
fz_throw(ctx, "cannot load pattern stream (%d %d R)", fz_to_num(dict), fz_to_gen(dict));
}
diff --git a/pdf/pdf_shade.c b/pdf/pdf_shade.c
index fb5dd72c..1be2bb15 100644
--- a/pdf/pdf_shade.c
+++ b/pdf/pdf_shade.c
@@ -1100,7 +1100,7 @@ pdf_load_shading(pdf_document *xref, fz_obj *dict)
fz_context *ctx = xref->ctx;
fz_shade *shade;
- if ((shade = fz_find_item(ctx, fz_free_shade_imp, dict)))
+ if ((shade = pdf_find_item(ctx, fz_free_shade_imp, dict)))
{
return shade;
}
@@ -1138,7 +1138,7 @@ pdf_load_shading(pdf_document *xref, fz_obj *dict)
/* RJW: "cannot load shading dictionary (%d %d R)", fz_to_num(dict), fz_to_gen(dict) */
}
- fz_store_item(ctx, dict, shade, fz_shade_size(shade));
+ pdf_store_item(ctx, dict, shade, fz_shade_size(shade));
return shade;
}
diff --git a/pdf/pdf_store.c b/pdf/pdf_store.c
new file mode 100644
index 00000000..4f51526d
--- /dev/null
+++ b/pdf/pdf_store.c
@@ -0,0 +1,59 @@
+#include "fitz.h"
+#include "mupdf.h"
+
+static int
+pdf_make_hash_key(fz_store_hash *hash, void *key_)
+{
+ fz_obj *key = (fz_obj *)key_;
+
+ if (!fz_is_indirect(key))
+ return 0;
+ hash->u.i.i0 = fz_to_num(key);
+ hash->u.i.i1 = fz_to_gen(key);
+ return 1;
+}
+
+static void *
+pdf_keep_key(fz_context *ctx, void *key)
+{
+ return (void *)fz_keep_obj((fz_obj *)key);
+}
+
+static void
+pdf_drop_key(fz_context *ctx, void *key)
+{
+ fz_drop_obj((fz_obj *)key);
+}
+
+static int
+pdf_cmp_key(void *k0, void *k1)
+{
+ return fz_objcmp((fz_obj *)k0, (fz_obj *)k1);
+}
+
+static fz_store_type pdf_obj_store_type =
+{
+ pdf_make_hash_key,
+ pdf_keep_key,
+ pdf_drop_key,
+ pdf_cmp_key
+};
+
+void
+pdf_store_item(fz_context *ctx, fz_obj *key, void *val, unsigned int itemsize)
+{
+ fz_store_item(ctx, key, val, itemsize, &pdf_obj_store_type);
+}
+
+void *
+pdf_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key)
+{
+ return fz_find_item(ctx, free, key, &pdf_obj_store_type);
+}
+
+void
+pdf_remove_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key)
+{
+ fz_remove_item(ctx, free, key, &pdf_obj_store_type);
+}
+
diff --git a/pdf/pdf_stream.c b/pdf/pdf_stream.c
index c66e703e..28fc616f 100644
--- a/pdf/pdf_stream.c
+++ b/pdf/pdf_stream.c
@@ -49,7 +49,7 @@ pdf_stream_has_crypt(fz_context *ctx, fz_obj *stm)
* Create a filter given a name and param dictionary.
*/
static fz_stream *
-build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int num, int gen)
+build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int num, int gen, pdf_image_params *params)
{
fz_context *ctx = chain->ctx;
char *s = fz_to_name(f);
@@ -79,6 +79,19 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int
fz_obj *rows = fz_dict_gets(p, "Rows");
fz_obj *eob = fz_dict_gets(p, "EndOfBlock");
fz_obj *bi1 = fz_dict_gets(p, "BlackIs1");
+ if (params)
+ {
+ /* We will shortstop here */
+ params->type = PDF_IMAGE_FAX;
+ params->u.fax.k = (k ? fz_to_int(k) : 0);
+ params->u.fax.eol = (eol ? fz_to_bool(eol) : 0);
+ params->u.fax.eba = (eba ? fz_to_bool(eba) : 0);
+ params->u.fax.columns = (columns ? fz_to_int(columns) : 1728);
+ params->u.fax.rows = (rows ? fz_to_int(rows) : 0);
+ params->u.fax.eob = (eob ? fz_to_bool(eob) : 1);
+ params->u.fax.bi1 = (bi1 ? fz_to_bool(bi1) : 0);
+ return chain;
+ }
return fz_open_faxd(chain,
k ? fz_to_int(k) : 0,
eol ? fz_to_bool(eol) : 0,
@@ -92,14 +105,38 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int
else if (!strcmp(s, "DCTDecode") || !strcmp(s, "DCT"))
{
fz_obj *ct = fz_dict_gets(p, "ColorTransform");
+ if (params)
+ {
+ /* We will shortstop here */
+ params->type = PDF_IMAGE_JPEG;
+ params->u.jpeg.ct = (ct ? fz_to_int(ct) : -1);
+ return chain;
+ }
return fz_open_dctd(chain, ct ? fz_to_int(ct) : -1);
}
else if (!strcmp(s, "RunLengthDecode") || !strcmp(s, "RL"))
+ {
+ if (params)
+ {
+ /* We will shortstop here */
+ params->type = PDF_IMAGE_RLD;
+ return chain;
+ }
return fz_open_rld(chain);
-
+ }
else if (!strcmp(s, "FlateDecode") || !strcmp(s, "Fl"))
{
+ if (params)
+ {
+ /* We will shortstop here */
+ params->type = PDF_IMAGE_FLATE;
+ params->u.flate.predictor = predictor;
+ params->u.flate.columns = columns;
+ params->u.flate.colors = colors;
+ params->u.flate.bpc = bpc;
+ return chain;
+ }
chain = fz_open_flated(chain);
if (predictor > 1)
chain = fz_open_predict(chain, predictor, columns, colors, bpc);
@@ -109,6 +146,17 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int
else if (!strcmp(s, "LZWDecode") || !strcmp(s, "LZW"))
{
fz_obj *ec = fz_dict_gets(p, "EarlyChange");
+ if (params)
+ {
+ /* We will shortstop here */
+ params->type = PDF_IMAGE_LZW;
+ params->u.lzw.predictor = predictor;
+ params->u.lzw.columns = columns;
+ params->u.lzw.colors = colors;
+ params->u.lzw.bpc = bpc;
+ params->u.lzw.ec = (ec ? fz_to_int(ec) : 1);
+ return chain;
+ }
chain = fz_open_lzwd(chain, ec ? fz_to_int(ec) : 1);
if (predictor > 1)
chain = fz_open_predict(chain, predictor, columns, colors, bpc);
@@ -155,7 +203,7 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int
* Assume ownership of head.
*/
static fz_stream *
-build_filter_chain(fz_stream *chain, pdf_document *xref, fz_obj *fs, fz_obj *ps, int num, int gen)
+build_filter_chain(fz_stream *chain, pdf_document *xref, fz_obj *fs, fz_obj *ps, int num, int gen, pdf_image_params *params)
{
fz_obj *f;
fz_obj *p;
@@ -166,7 +214,7 @@ build_filter_chain(fz_stream *chain, pdf_document *xref, fz_obj *fs, fz_obj *ps,
{
f = fz_array_get(fs, i);
p = fz_array_get(ps, i);
- chain = build_filter(chain, xref, f, p, num, gen);
+ chain = build_filter(chain, xref, f, p, num, gen, (i == n-1 ? params : NULL));
}
return chain;
@@ -210,7 +258,7 @@ pdf_open_raw_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int nu
* to stream length and decrypting.
*/
static fz_stream *
-pdf_open_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int num, int gen)
+pdf_open_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int num, int gen, pdf_image_params *imparams)
{
fz_obj *filters;
fz_obj *params;
@@ -221,9 +269,9 @@ pdf_open_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int num, i
chain = pdf_open_raw_filter(chain, xref, stmobj, num, gen);
if (fz_is_name(filters))
- chain = build_filter(chain, xref, filters, params, num, gen);
+ chain = build_filter(chain, xref, filters, params, num, gen, imparams);
else if (fz_array_len(filters) > 0)
- chain = build_filter_chain(chain, xref, filters, params, num, gen);
+ chain = build_filter_chain(chain, xref, filters, params, num, gen, imparams);
fz_lock_stream(chain);
return chain;
@@ -234,7 +282,7 @@ pdf_open_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int num, i
* constraining to stream length, and without decryption.
*/
fz_stream *
-pdf_open_inline_stream(pdf_document *xref, fz_obj *stmobj, int length, fz_stream *chain)
+pdf_open_inline_stream(pdf_document *xref, fz_obj *stmobj, int length, fz_stream *chain, pdf_image_params *imparams)
{
fz_obj *filters;
fz_obj *params;
@@ -246,9 +294,9 @@ pdf_open_inline_stream(pdf_document *xref, fz_obj *stmobj, int length, fz_stream
fz_keep_stream(chain);
if (fz_is_name(filters))
- return build_filter(chain, xref, filters, params, 0, 0);
+ return build_filter(chain, xref, filters, params, 0, 0, imparams);
if (fz_array_len(filters) > 0)
- return build_filter_chain(chain, xref, filters, params, 0, 0);
+ return build_filter_chain(chain, xref, filters, params, 0, 0, imparams);
return fz_open_null(chain, length);
}
@@ -290,6 +338,12 @@ pdf_open_raw_stream(pdf_document *xref, int num, int gen)
fz_stream *
pdf_open_stream(pdf_document *xref, int num, int gen)
{
+ return pdf_open_image_stream(xref, num, gen, NULL);
+}
+
+fz_stream *
+pdf_open_image_stream(pdf_document *xref, int num, int gen, pdf_image_params *params)
+{
pdf_xref_entry *x;
fz_stream *stm;
@@ -304,12 +358,56 @@ pdf_open_stream(pdf_document *xref, int num, int gen)
if (x->stm_ofs == 0)
fz_throw(xref->ctx, "object is not a stream");
- stm = pdf_open_filter(xref->file, xref, x->obj, num, gen);
+ stm = pdf_open_filter(xref->file, xref, x->obj, num, gen, params);
fz_seek(xref->file, x->stm_ofs, 0);
return stm;
}
fz_stream *
+pdf_open_image_decomp_stream(fz_context *ctx, fz_buffer *buffer, pdf_image_params *params, int *factor)
+{
+ fz_stream *chain = fz_open_buffer(ctx, buffer);
+
+ switch (params->type)
+ {
+ case PDF_IMAGE_FAX:
+ *factor = 1;
+ return fz_open_faxd(chain,
+ params->u.fax.k,
+ params->u.fax.eol,
+ params->u.fax.eba,
+ params->u.fax.columns,
+ params->u.fax.rows,
+ params->u.fax.eob,
+ params->u.fax.bi1);
+ case PDF_IMAGE_JPEG:
+ if (*factor > 8)
+ *factor = 8;
+ return fz_open_resized_dctd(chain, params->u.jpeg.ct, *factor);
+ case PDF_IMAGE_RLD:
+ *factor = 1;
+ return fz_open_rld(chain);
+ case PDF_IMAGE_FLATE:
+ *factor = 1;
+ chain = fz_open_flated(chain);
+ if (params->u.flate.predictor > 1)
+ chain = fz_open_predict(chain, params->u.flate.predictor, params->u.flate.columns, params->u.flate.colors, params->u.flate.bpc);
+ return chain;
+ case PDF_IMAGE_LZW:
+ *factor = 1;
+ chain = fz_open_lzwd(chain, params->u.lzw.ec);
+ if (params->u.lzw.predictor > 1)
+ chain = fz_open_predict(chain, params->u.lzw.predictor, params->u.lzw.columns, params->u.lzw.colors, params->u.lzw.bpc);
+ return chain;
+ default:
+ *factor = 1;
+ break;
+ }
+
+ return chain;
+}
+
+fz_stream *
pdf_open_stream_with_offset(pdf_document *xref, int num, int gen, fz_obj *dict, int stm_ofs)
{
fz_stream *stm;
@@ -317,7 +415,7 @@ pdf_open_stream_with_offset(pdf_document *xref, int num, int gen, fz_obj *dict,
if (stm_ofs == 0)
fz_throw(xref->ctx, "object is not a stream");
- stm = pdf_open_filter(xref->file, xref, dict, num, gen);
+ stm = pdf_open_filter(xref->file, xref, dict, num, gen, NULL);
fz_seek(xref->file, stm_ofs, 0);
return stm;
}
@@ -372,6 +470,12 @@ pdf_guess_filter_length(int len, char *filter)
fz_buffer *
pdf_load_stream(pdf_document *xref, int num, int gen)
{
+ return pdf_load_image_stream(xref, num, gen, NULL);
+}
+
+fz_buffer *
+pdf_load_image_stream(pdf_document *xref, int num, int gen, pdf_image_params *params)
+{
fz_context *ctx = xref->ctx;
fz_stream *stm = NULL;
fz_obj *dict, *obj;
@@ -392,7 +496,7 @@ pdf_load_stream(pdf_document *xref, int num, int gen)
fz_drop_obj(dict);
- stm = pdf_open_stream(xref, num, gen);
+ stm = pdf_open_image_stream(xref, num, gen, params);
/* RJW: "cannot open stream (%d %d R)", num, gen */
fz_try(ctx)
diff --git a/pdf/pdf_xobject.c b/pdf/pdf_xobject.c
index 91bf4db3..9f6d10ce 100644
--- a/pdf/pdf_xobject.c
+++ b/pdf/pdf_xobject.c
@@ -43,7 +43,7 @@ pdf_load_xobject(pdf_document *xref, fz_obj *dict)
fz_obj *obj;
fz_context *ctx = xref->ctx;
- if ((form = fz_find_item(ctx, pdf_free_xobject_imp, dict)))
+ if ((form = pdf_find_item(ctx, pdf_free_xobject_imp, dict)))
{
return form;
}
@@ -56,7 +56,7 @@ pdf_load_xobject(pdf_document *xref, fz_obj *dict)
form->me = NULL;
/* Store item immediately, to avoid possible recursion if objects refer back to this one */
- fz_store_item(ctx, dict, form, pdf_xobject_size(form));
+ pdf_store_item(ctx, dict, form, pdf_xobject_size(form));
obj = fz_dict_gets(dict, "BBox");
form->bbox = pdf_to_rect(ctx, obj);
@@ -102,7 +102,7 @@ pdf_load_xobject(pdf_document *xref, fz_obj *dict)
}
fz_catch(ctx)
{
- fz_remove_item(ctx, pdf_free_xobject_imp, dict);
+ pdf_remove_item(ctx, pdf_free_xobject_imp, dict);
pdf_drop_xobject(ctx, form);
fz_throw(ctx, "cannot load xobject content stream (%d %d R)", fz_to_num(dict), fz_to_gen(dict));
}
diff --git a/win32/libmupdf.vcproj b/win32/libmupdf.vcproj
index 9a8bb6e9..e06193f8 100644
--- a/win32/libmupdf.vcproj
+++ b/win32/libmupdf.vcproj
@@ -310,6 +310,10 @@
>
</File>
<File
+ RelativePath="..\pdf\pdf_store.c"
+ >
+ </File>
+ <File
RelativePath="..\pdf\pdf_stream.c"
>
</File>
diff --git a/xps/xps_image.c b/xps/xps_image.c
index 10d3baee..a2021223 100644
--- a/xps/xps_image.c
+++ b/xps/xps_image.c
@@ -1,41 +1,93 @@
#include "fitz.h"
#include "muxps.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)
{
- fz_pixmap *image;
+ fz_pixmap *pix;
+ xps_image *image;
if (len < 8)
fz_throw(ctx, "unknown image file format");
if (buf[0] == 0xff && buf[1] == 0xd8)
- image = fz_load_jpeg(ctx, buf, len);
+ pix = fz_load_jpeg(ctx, buf, len);
else if (memcmp(buf, "\211PNG\r\n\032\n", 8) == 0)
- image = fz_load_png(ctx, buf, len);
+ 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)
- image = fz_load_tiff(ctx, buf, len);
+ pix = fz_load_tiff(ctx, buf, len);
else
fz_throw(ctx, "unknown image file format");
- return image;
+ 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;
}
static void
xps_paint_image_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict,
xml_element *root, void *vimage)
{
- fz_pixmap *pixmap = vimage;
+ xps_image *image = vimage;
float xs, ys;
- if (pixmap->xres == 0 || pixmap->yres == 0)
+ if (image->xres == 0 || image->yres == 0)
return;
- xs = pixmap->w * 96 / pixmap->xres;
- ys = pixmap->h * 96 / pixmap->yres;
+ xs = image->base.w * 96 / image->xres;
+ ys = image->base.h * 96 / image->yres;
ctm = fz_concat(fz_scale(xs, ys), ctm);
- fz_fill_image(doc->dev, pixmap, ctm, doc->opacity[doc->opacity_top]);
+ fz_fill_image(doc->dev, &image->base, ctm, doc->opacity[doc->opacity_top]);
}
static xps_part *
@@ -93,7 +145,7 @@ xps_parse_image_brush(xps_document *doc, fz_matrix ctm, fz_rect area,
char *base_uri, xps_resource *dict, xml_element *root)
{
xps_part *part;
- fz_pixmap *image;
+ fz_image *image;
fz_try(doc->ctx)
{
@@ -119,5 +171,5 @@ xps_parse_image_brush(xps_document *doc, fz_matrix ctm, fz_rect area,
xps_parse_tiling_brush(doc, ctm, area, base_uri, dict, root, xps_paint_image_brush, image);
- fz_drop_pixmap(doc->ctx, image);
+ fz_drop_image(doc->ctx, image);
}