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