summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2016-04-07 11:08:42 +0100
committerRobin Watts <robin.watts@artifex.com>2016-04-28 12:30:40 +0100
commitb944f16a564f8a31d9a064980318ad690be31f8e (patch)
tree6fb5a572487943e7cdccee2b201ae526c23bd595
parent6ab232064f3fc9037e97157dd9a77f286ad85e23 (diff)
downloadmupdf-b944f16a564f8a31d9a064980318ad690be31f8e.tar.xz
Partial image decode.
Update the core fz_get_pixmap_from_image code to allow fetching a subarea of a pixmap. We pass in the required subarea, together with the transformation matrix for the whole image. On return, we have a pixmap at least as big as was requested, and the transformation matrix is updated to map the supplied area to the correct place on the screen. The draw device is updated to use this as required. Everywhere else passes NULLs in, and so gets unchanged behaviour. The standard 'get_pixmap' function has been updated to decode just the required areas of the bitmaps. This means that banded rendering of pages will decode just the image subareas that are required for each band, limiting the memory use. The downside to this is that each band will redecode the image again to extract just the section we want. The image subareas are put into the fz_store in the same way as full images. Currently image areas in the store are only matched when they match exactly; subareas are not identified as being able to use existing images.
-rw-r--r--include/mupdf/fitz/image.h24
-rw-r--r--include/mupdf/fitz/math.h15
-rw-r--r--include/mupdf/fitz/output-png.h2
-rw-r--r--include/mupdf/fitz/store.h6
-rw-r--r--include/mupdf/fitz/stream.h11
-rw-r--r--source/fitz/draw-device.c88
-rw-r--r--source/fitz/geometry.c12
-rw-r--r--source/fitz/image.c209
-rw-r--r--source/fitz/pixmap.c4
-rw-r--r--source/fitz/stext-output.c2
-rw-r--r--source/fitz/stream-read.c20
-rw-r--r--source/fitz/svg-device.c6
-rw-r--r--source/fitz/test-device.c2
-rw-r--r--source/gprf/gprf-doc.c10
-rw-r--r--source/pdf/pdf-image.c2
-rw-r--r--source/pdf/pdf-resources.c2
-rw-r--r--source/pdf/pdf-stream.c2
-rw-r--r--source/tools/murun.c4
-rw-r--r--source/tools/pdfextract.c2
19 files changed, 369 insertions, 54 deletions
diff --git a/include/mupdf/fitz/image.h b/include/mupdf/fitz/image.h
index 3355748c..5b9db325 100644
--- a/include/mupdf/fitz/image.h
+++ b/include/mupdf/fitz/image.h
@@ -24,17 +24,23 @@ typedef struct fz_image_s fz_image;
image: The image to retrieve a pixmap from.
- w: The desired width (in pixels). This may be completely ignored, but
- may serve as an indication of a suitable subsample factor to use for
- image types that support this.
+ subarea: The subarea of the image that we actually care about (or NULL
+ to indicate the whole image).
- h: The desired height (in pixels). This may be completely ignored, but
- may serve as an indication of a suitable subsample factor to use for
- image types that support this.
+ trans: Optional, unless subarea is given. If given, then on entry this is
+ the transform that will be applied to the complete image. It should be
+ updated on exit to the transform to apply to the given subarea of the
+ image. This is used to calculate the desired width/height for subsampling.
+
+ w: If non-NULL, a pointer to an int to be updated on exit to the
+ width (in pixels) that the scaled output will cover.
+
+ h: If non-NULL, a pointer to an int to be updated on exit to the
+ height (in pixels) that the scaled output will cover.
Returns a non NULL pixmap pointer. May throw exceptions.
*/
-fz_pixmap *fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, int w, int h);
+fz_pixmap *fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, const fz_irect *subarea, fz_matrix *trans, int *w, int *h);
/*
fz_drop_image: Drop a reference to an image.
@@ -58,7 +64,7 @@ fz_image *fz_new_image_from_data(fz_context *ctx, unsigned char *data, int len);
fz_image *fz_new_image_from_buffer(fz_context *ctx, fz_buffer *buffer);
fz_image *fz_new_image_from_file(fz_context *ctx, const char *path);
void fz_drop_image_imp(fz_context *ctx, fz_storable *image);
-fz_pixmap *fz_decomp_image_from_stream(fz_context *ctx, fz_stream *stm, fz_image *image, int indexed, int l2factor);
+fz_pixmap *fz_decomp_image_from_stream(fz_context *ctx, fz_stream *stm, fz_image *image, fz_irect *subarea, int indexed, int l2factor);
fz_pixmap *fz_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src);
struct fz_image_s
@@ -67,7 +73,7 @@ struct fz_image_s
int w, h, n, bpc;
fz_image *mask;
fz_colorspace *colorspace;
- fz_pixmap *(*get_pixmap)(fz_context *, fz_image *, int w, int h, int *l2factor);
+ fz_pixmap *(*get_pixmap)(fz_context *, fz_image *, fz_irect *subarea, int w, int h, int *l2factor);
int colorkey[FZ_MAX_COLORS * 2];
float decode[FZ_MAX_COLORS * 2];
int imagemask;
diff --git a/include/mupdf/fitz/math.h b/include/mupdf/fitz/math.h
index f16b3627..b7baede8 100644
--- a/include/mupdf/fitz/math.h
+++ b/include/mupdf/fitz/math.h
@@ -294,6 +294,21 @@ fz_matrix *fz_scale(fz_matrix *m, float sx, float sy);
fz_matrix *fz_pre_scale(fz_matrix *m, float sx, float sy);
/*
+ fz_post_scale: Scale a matrix by postmultiplication.
+
+ m: Pointer to the matrix to scale
+
+ sx, sy: Scaling factors along the X- and Y-axes. A scaling
+ factor of 1.0 will not cause any scaling along the relevant
+ axis.
+
+ Returns m (updated).
+
+ Does not throw exceptions.
+*/
+fz_matrix *fz_post_scale(fz_matrix *m, float sx, float sy);
+
+/*
fz_shear: Create a shearing matrix.
The returned matrix is of the form [ 1 sy sx 1 0 0 ].
diff --git a/include/mupdf/fitz/output-png.h b/include/mupdf/fitz/output-png.h
index 34af799a..c77f9e5f 100644
--- a/include/mupdf/fitz/output-png.h
+++ b/include/mupdf/fitz/output-png.h
@@ -29,7 +29,7 @@ void fz_write_png_trailer(fz_context *ctx, fz_output *out, fz_png_output_context
/*
Create a new buffer containing the image/pixmap in PNG format.
*/
-fz_buffer *fz_new_buffer_from_image_as_png(fz_context *ctx, fz_image *image, int w, int h);
+fz_buffer *fz_new_buffer_from_image_as_png(fz_context *ctx, fz_image *image);
fz_buffer *fz_new_buffer_from_pixmap_as_png(fz_context *ctx, fz_pixmap *pixmap);
#endif
diff --git a/include/mupdf/fitz/store.h b/include/mupdf/fitz/store.h
index e98e2394..5dbf5538 100644
--- a/include/mupdf/fitz/store.h
+++ b/include/mupdf/fitz/store.h
@@ -78,6 +78,12 @@ struct fz_store_hash_s
} pi;
struct
{
+ const void *ptr;
+ int i;
+ fz_irect r;
+ } pir;
+ struct
+ {
int id;
float m[4];
} im;
diff --git a/include/mupdf/fitz/stream.h b/include/mupdf/fitz/stream.h
index 233e2b06..90b5ec22 100644
--- a/include/mupdf/fitz/stream.h
+++ b/include/mupdf/fitz/stream.h
@@ -136,6 +136,17 @@ void fz_seek(fz_context *ctx, fz_stream *stm, fz_off_t offset, int whence);
int fz_read(fz_context *ctx, fz_stream *stm, unsigned char *data, int len);
/*
+ fz_skip: Read from a stream discarding data.
+
+ stm: The stream to read from.
+
+ len: The number of bytes to read.
+
+ Returns the number of bytes read. May throw exceptions.
+*/
+int fz_skip(fz_context *ctx, fz_stream *stm, int len);
+
+/*
fz_read_all: Read all of a stream into a buffer.
stm: The stream to read from
diff --git a/source/fitz/draw-device.c b/source/fitz/draw-device.c
index b9db1558..4108cf09 100644
--- a/source/fitz/draw-device.c
+++ b/source/fitz/draw-device.c
@@ -1106,6 +1106,8 @@ fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_m
fz_colorspace *model = state->dest->colorspace;
fz_irect clip;
fz_matrix local_ctm = *ctm;
+ fz_matrix inverse;
+ fz_irect src_area;
fz_intersect_irect(fz_pixmap_bbox(ctx, state->dest, &clip), &state->scissor);
@@ -1120,10 +1122,42 @@ fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_m
if (image->w == 0 || image->h == 0)
return;
- dx = sqrtf(local_ctm.a * local_ctm.a + local_ctm.b * local_ctm.b);
- dy = sqrtf(local_ctm.c * local_ctm.c + local_ctm.d * local_ctm.d);
-
- pixmap = fz_get_pixmap_from_image(ctx, image, dx, dy);
+ /* ctm maps the image (expressed as the unit square) onto the
+ * destination device. Reverse that to get a mapping from
+ * the destination device to the source pixels. */
+ if (fz_try_invert_matrix(&inverse, &local_ctm))
+ {
+ /* Not invertible. Could just bale? Use the whole image
+ * for now. */
+ src_area.x0 = 0;
+ src_area.x1 = image->w;
+ src_area.y0 = 0;
+ src_area.y1 = image->h;
+ }
+ else
+ {
+ float exp;
+ fz_rect rect;
+ fz_irect sane;
+ /* We want to scale from image coords, not from unit square */
+ fz_post_scale(&inverse, image->w, image->h);
+ /* Are we scaling up or down? exp < 1 means scaling down. */
+ exp = fz_matrix_max_expansion(&inverse);
+ fz_rect_from_irect(&rect, &clip);
+ fz_transform_rect(&rect, &inverse);
+ /* Allow for support requirements for scalers. */
+ fz_expand_rect(&rect, fz_max(exp, 1) * 4);
+ fz_irect_from_rect(&src_area, &rect);
+ sane.x0 = 0;
+ sane.y0 = 0;
+ sane.x1 = image->w;
+ sane.y1 = image->h;
+ fz_intersect_irect(&src_area, &sane);
+ if (fz_is_empty_irect(&src_area))
+ return;
+ }
+
+ pixmap = fz_get_pixmap_from_image(ctx, image, &src_area, &local_ctm, &dx, &dy);
orig_pixmap = pixmap;
/* convert images with more components (cmyk->rgb) before scaling */
@@ -1214,6 +1248,8 @@ fz_draw_fill_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const
fz_colorspace *model = state->dest->colorspace;
fz_irect clip;
fz_matrix local_ctm = *ctm;
+ fz_matrix inverse;
+ fz_irect src_area;
fz_pixmap_bbox(ctx, state->dest, &clip);
fz_intersect_irect(&clip, &state->scissor);
@@ -1221,9 +1257,42 @@ fz_draw_fill_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const
if (image->w == 0 || image->h == 0)
return;
- dx = sqrtf(local_ctm.a * local_ctm.a + local_ctm.b * local_ctm.b);
- dy = sqrtf(local_ctm.c * local_ctm.c + local_ctm.d * local_ctm.d);
- pixmap = fz_get_pixmap_from_image(ctx, image, dx, dy);
+ /* ctm maps the image (expressed as the unit square) onto the
+ * destination device. Reverse that to get a mapping from
+ * the destination device to the source pixels. */
+ if (fz_try_invert_matrix(&inverse, &local_ctm))
+ {
+ /* Not invertible. Could just bale? Use the whole image
+ * for now. */
+ src_area.x0 = 0;
+ src_area.x1 = image->w;
+ src_area.y0 = 0;
+ src_area.y1 = image->h;
+ }
+ else
+ {
+ float exp;
+ fz_rect rect;
+ fz_irect sane;
+ /* We want to scale from image coords, not from unit square */
+ fz_post_scale(&inverse, image->w, image->h);
+ /* Are we scaling up or down? exp < 1 means scaling down. */
+ exp = fz_matrix_max_expansion(&inverse);
+ fz_rect_from_irect(&rect, &clip);
+ fz_transform_rect(&rect, &inverse);
+ /* Allow for support requirements for scalers. */
+ fz_expand_rect(&rect, fz_max(exp, 1) * 4);
+ fz_irect_from_rect(&src_area, &rect);
+ sane.x0 = 0;
+ sane.y0 = 0;
+ sane.x1 = image->w;
+ sane.y1 = image->h;
+ fz_intersect_irect(&src_area, &sane);
+ if (fz_is_empty_irect(&src_area))
+ return;
+ }
+
+ pixmap = fz_get_pixmap_from_image(ctx, image, &src_area, &local_ctm, &dx, &dy);
orig_pixmap = pixmap;
fz_try(ctx)
@@ -1321,12 +1390,9 @@ fz_draw_clip_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const
fz_intersect_irect(&bbox, fz_irect_from_rect(&bbox2, scissor));
}
- dx = sqrtf(local_ctm.a * local_ctm.a + local_ctm.b * local_ctm.b);
- dy = sqrtf(local_ctm.c * local_ctm.c + local_ctm.d * local_ctm.d);
-
fz_try(ctx)
{
- pixmap = fz_get_pixmap_from_image(ctx, image, dx, dy);
+ pixmap = fz_get_pixmap_from_image(ctx, image, NULL, &local_ctm, &dx, &dy);
orig_pixmap = pixmap;
state[1].mask = mask = fz_new_pixmap_with_bbox(ctx, NULL, &bbox);
diff --git a/source/fitz/geometry.c b/source/fitz/geometry.c
index 073536ff..f7a92816 100644
--- a/source/fitz/geometry.c
+++ b/source/fitz/geometry.c
@@ -59,6 +59,18 @@ fz_pre_scale(fz_matrix *mat, float sx, float sy)
}
fz_matrix *
+fz_post_scale(fz_matrix *mat, float sx, float sy)
+{
+ mat->a *= sx;
+ mat->b *= sy;
+ mat->c *= sx;
+ mat->d *= sy;
+ mat->e *= sx;
+ mat->f *= sy;
+ return mat;
+}
+
+fz_matrix *
fz_shear(fz_matrix *mat, float h, float v)
{
mat->a = 1; mat->b = v;
diff --git a/source/fitz/image.c b/source/fitz/image.c
index 9c66176f..36026a19 100644
--- a/source/fitz/image.c
+++ b/source/fitz/image.c
@@ -21,14 +21,16 @@ struct fz_image_key_s {
int refs;
fz_image *image;
int l2factor;
+ fz_irect rect;
};
static int
fz_make_hash_image_key(fz_context *ctx, fz_store_hash *hash, void *key_)
{
fz_image_key *key = (fz_image_key *)key_;
- hash->u.pi.ptr = key->image;
- hash->u.pi.i = key->l2factor;
+ hash->u.pir.ptr = key->image;
+ hash->u.pir.i = key->l2factor;
+ hash->u.pir.r = key->rect;
return 1;
}
@@ -55,7 +57,7 @@ fz_cmp_image_key(fz_context *ctx, void *k0_, void *k1_)
{
fz_image_key *k0 = (fz_image_key *)k0_;
fz_image_key *k1 = (fz_image_key *)k1_;
- return k0->image == k1->image && k0->l2factor == k1->l2factor;
+ return k0->image == k1->image && k0->l2factor == k1->l2factor && k0->rect.x0 == k1->rect.x0 && k0->rect.y0 == k1->rect.y0 && k0->rect.x1 == k1->rect.x1 && k0->rect.y1 == k1->rect.y1;
}
static void
@@ -96,7 +98,7 @@ fz_mask_color_key(fz_pixmap *pix, int n, const int *colorkey)
static void
fz_unblend_masked_tile(fz_context *ctx, fz_pixmap *tile, fz_image *image)
{
- fz_pixmap *mask = fz_get_pixmap_from_image(ctx, image->mask, tile->w, tile->h);
+ fz_pixmap *mask = fz_get_pixmap_from_image(ctx, image->mask, NULL, NULL, NULL, NULL);
unsigned char *s = mask->samples, *end = s + mask->w * mask->h;
unsigned char *d = tile->samples;
int k;
@@ -122,14 +124,39 @@ fz_unblend_masked_tile(fz_context *ctx, fz_pixmap *tile, fz_image *image)
}
fz_pixmap *
-fz_decomp_image_from_stream(fz_context *ctx, fz_stream *stm, fz_image *image, int indexed, int l2factor)
+fz_decomp_image_from_stream(fz_context *ctx, fz_stream *stm, fz_image *image, fz_irect *subarea, int indexed, int l2factor)
{
fz_pixmap *tile = NULL;
int stride, len, i;
unsigned char *samples = NULL;
int f = 1<<l2factor;
- int w = (image->w + f-1) >> l2factor;
- int h = (image->h + f-1) >> l2factor;
+ int w = image->w;
+ int h = image->h;
+
+ if (subarea)
+ {
+ int bpp = image->bpc * image->n;
+ int mask;
+ switch (bpp)
+ {
+ case 1: mask = 8*f; break;
+ case 2: mask = 4*f; break;
+ case 4: mask = 2*f; break;
+ default: mask = f; break;
+ }
+ subarea->x0 &= ~(mask - 1);
+ subarea->y0 &= ~(f - 1);
+ subarea->x1 = (subarea->x1 + mask - 1) & ~(mask - 1);
+ if (subarea->x1 > image->w)
+ subarea->x1 = image->w;
+ subarea->y1 = (subarea->y1 + f - 1) & ~(f - 1);
+ if (subarea->y1 > image->h)
+ subarea->y1 = image->h;
+ w = (subarea->x1 - subarea->x0);
+ h = (subarea->y1 - subarea->y0);
+ }
+ w = (w + f - 1) >> l2factor;
+ h = (h + f - 1) >> l2factor;
fz_var(tile);
fz_var(samples);
@@ -143,7 +170,46 @@ fz_decomp_image_from_stream(fz_context *ctx, fz_stream *stm, fz_image *image, in
samples = fz_malloc_array(ctx, h, stride);
- len = fz_read(ctx, stm, samples, h * stride);
+ if (subarea)
+ {
+ int hh;
+ unsigned char *s = samples;
+ int stream_w = (image->w + f - 1)>>l2factor;
+ int stream_stride = (stream_w * image->n * image->bpc + 7) / 8;
+ int l_margin = subarea->x0 >> l2factor;
+ int t_margin = subarea->y0 >> l2factor;
+ int r_margin = (image->w + f - 1 - subarea->x1) >> l2factor;
+ int b_margin = (image->h + f - 1 - subarea->y1) >> l2factor;
+ int l_skip = (l_margin * image->n * image->bpc)/8;
+ int r_skip = (r_margin * image->n * image->bpc)/8;
+ int t_skip = t_margin * stream_stride + l_skip;
+ int b_skip = b_margin * stream_stride + r_skip;
+ int l = fz_skip(ctx, stm, t_skip);
+ len = 0;
+ if (l == t_skip)
+ {
+ hh = h;
+ do
+ {
+ l = fz_read(ctx, stm, s, stride);
+ s += l;
+ len += l;
+ if (l < stride)
+ break;
+ if (--hh == 0)
+ break;
+ l = fz_skip(ctx, stm, r_skip + l_skip);
+ if (l < r_skip + l_skip)
+ break;
+ }
+ while (1);
+ (void)fz_skip(ctx, stm, r_skip + b_skip);
+ }
+ }
+ else
+ {
+ len = fz_read(ctx, stm, samples, h * stride);
+ }
/* Pad truncated images */
if (len < stride * h)
@@ -219,12 +285,13 @@ fz_drop_image_imp(fz_context *ctx, fz_storable *image_)
}
static fz_pixmap *
-standard_image_get_pixmap(fz_context *ctx, fz_image *image, int w, int h, int *l2factor)
+standard_image_get_pixmap(fz_context *ctx, fz_image *image, fz_irect *subarea, int w, int h, int *l2factor)
{
int native_l2factor;
fz_stream *stm;
int indexed;
fz_pixmap *tile;
+ int can_sub = 0;
/* We need to make a new one. */
/* First check for ones that we can't decode using streams */
@@ -271,7 +338,8 @@ standard_image_get_pixmap(fz_context *ctx, fz_image *image, int w, int h, int *l
native_l2factor -= *l2factor;
indexed = fz_colorspace_is_indexed(ctx, image->colorspace);
- tile = fz_decomp_image_from_stream(ctx, stm, image, indexed, native_l2factor);
+ can_sub = 1;
+ tile = fz_decomp_image_from_stream(ctx, stm, image, subarea, indexed, native_l2factor);
/* CMYK JPEGs in XPS documents have to be inverted */
if (image->invert_cmyk_jpeg &&
@@ -285,20 +353,63 @@ standard_image_get_pixmap(fz_context *ctx, fz_image *image, int w, int h, int *l
break;
}
+ if (can_sub == 0 && subarea != NULL)
+ {
+ subarea->x0 = 0;
+ subarea->y0 = 0;
+ subarea->x1 = image->w;
+ subarea->y1 = image->h;
+ }
+
return tile;
}
+static void
+update_ctm_for_subarea(fz_matrix *ctm, const fz_irect *subarea, int w, int h)
+{
+ fz_matrix m;
+
+ if (subarea->x0 == 0 && subarea->y0 == 0 && subarea->x1 == w && subarea->y1 == h)
+ return;
+
+ m.a = (subarea->x1 - subarea->x0) / (float)w;
+ m.b = 0;
+ m.c = 0;
+ m.d = (subarea->y1 - subarea->y0) / (float)h;
+ m.e = subarea->x0 / (float)w;
+ m.f = subarea->y0 / (float)h;
+ fz_concat(ctm, &m, ctm);
+}
+
fz_pixmap *
-fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, int w, int h)
+fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, const fz_irect *subarea, fz_matrix *ctm, int *dw, int *dh)
{
fz_pixmap *tile;
int l2factor, l2factor_remaining;
fz_image_key key;
fz_image_key *keyp;
+ int w;
+ int h;
if (!image)
return NULL;
+ /* Figure out the extent. */
+ if (ctm)
+ {
+ w = sqrtf(ctm->a * ctm->a + ctm->b * ctm->b);
+ if (w > image->w)
+ w = image->w;
+ h = sqrtf(ctm->c * ctm->c + ctm->d * ctm->d);
+ if (h > image->h)
+ w = image->h;
+ }
+ else
+ {
+ w = image->w;
+ h = image->h;
+ }
+
/* 'Simple' images created direct from pixmaps will have no buffer
* of compressed data. We cannot do any better than just returning
* a pointer to the original 'tile'.
@@ -307,13 +418,13 @@ fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, int w, int h)
* with masks applied, so we need both parts of the following test.
*/
if (image->buffer == NULL && image->tile != NULL)
+ {
+ if (dw)
+ *dw = w;
+ if (dh)
+ *dh = h;
return fz_keep_pixmap(ctx, image->tile); /* That's all we can give you! */
-
- /* Ensure our expectations for tile size are reasonable */
- if (w < 0 || w > image->w)
- w = image->w;
- if (h < 0 || h > image->h)
- h = image->h;
+ }
/* What is our ideal factor? We search for the largest factor where
* we can subdivide and stay larger than the required size. We add
@@ -324,6 +435,61 @@ fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, int w, int h)
else
for (l2factor=0; image->w>>(l2factor+1) >= w+2 && image->h>>(l2factor+1) >= h+2 && l2factor < 6; l2factor++);
+ /* Now figure out if we want to decode just a subarea */
+ if (subarea == NULL || (subarea->x1-subarea->x0)*(subarea->y1-subarea->y0) >= (image->w*image->h/10)*9)
+ {
+ /* Either no subarea specified, or a subarea 90% or more of the
+ * whole area specified. Use the whole image. */
+ key.rect.x0 = 0;
+ key.rect.y0 = 0;
+ key.rect.x1 = image->w;
+ key.rect.y1 = image->h;
+ }
+ else
+ {
+ /* Clip to the edges if they are within 1% */
+ key.rect = *subarea;
+ if (key.rect.x0 <= image->w/100)
+ key.rect.x0 = 0;
+ if (key.rect.y0 <= image->h/100)
+ key.rect.y0 = 0;
+ if (key.rect.x1 >= image->w*99/100)
+ key.rect.x1 = image->w;
+ if (key.rect.y1 >= image->h*99/100)
+ key.rect.y1 = image->h;
+ }
+
+ if (ctm)
+ {
+ float frac_w = (key.rect.x1 - key.rect.x0) / (float)image->w;
+ float frac_h = (key.rect.y1 - key.rect.y0) / (float)image->h;
+ float a = ctm->a * frac_w;
+ float b = ctm->b * frac_h;
+ float c = ctm->c * frac_w;
+ float d = ctm->d * frac_h;
+
+ w = sqrtf(a * a + b * b);
+ h = sqrtf(c * c + d * d);
+ }
+ else
+ {
+ w = image->w;
+ h = image->h;
+ }
+
+ /* Return the true sizes to the caller */
+ if (dw)
+ *dw = w;
+ if (dh)
+ *dh = h;
+ if (w > image->w)
+ w = image->w;
+ if (h > image->h)
+ h = image->h;
+
+ if (w == 0 || h == 0)
+ l2factor = 0;
+
/* Can we find any suitable tiles in the cache? */
key.refs = 1;
key.image = image;
@@ -332,7 +498,10 @@ fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, int w, int h)
{
tile = fz_find_item(ctx, fz_drop_pixmap_imp, &key, &fz_image_store_type);
if (tile)
+ {
+ update_ctm_for_subarea(ctm, &key.rect, image->w, image->h);
return tile;
+ }
key.l2factor--;
}
while (key.l2factor >= 0);
@@ -340,7 +509,10 @@ fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, int w, int h)
/* We'll have to decode the image; request the correct amount of
* downscaling. */
l2factor_remaining = l2factor;
- tile = image->get_pixmap(ctx, image, w, h, &l2factor_remaining);
+ tile = image->get_pixmap(ctx, image, &key.rect, w, h, &l2factor_remaining);
+
+ /* Update the ctm to allow for subareas. */
+ update_ctm_for_subarea(ctm, &key.rect, image->w, image->h);
/* l2factor_remaining is updated to the amount of subscaling left to do */
assert(l2factor_remaining >= 0 && l2factor_remaining <= 6);
@@ -360,6 +532,7 @@ fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, int w, int h)
keyp->refs = 1;
keyp->image = fz_keep_image(ctx, image);
keyp->l2factor = l2factor;
+ keyp->rect = key.rect;
existing_tile = fz_store_item(ctx, keyp, tile, fz_pixmap_size(ctx, tile), &fz_image_store_type);
if (existing_tile)
{
diff --git a/source/fitz/pixmap.c b/source/fitz/pixmap.c
index 88e16d9d..fca6f733 100644
--- a/source/fitz/pixmap.c
+++ b/source/fitz/pixmap.c
@@ -1123,9 +1123,9 @@ png_from_pixmap(fz_context *ctx, fz_pixmap *pix, int drop)
}
fz_buffer *
-fz_new_buffer_from_image_as_png(fz_context *ctx, fz_image *image, int w, int h)
+fz_new_buffer_from_image_as_png(fz_context *ctx, fz_image *image)
{
- return png_from_pixmap(ctx, fz_get_pixmap_from_image(ctx, image, image->w, image->h), 1);
+ return png_from_pixmap(ctx, fz_get_pixmap_from_image(ctx, image, NULL, NULL, NULL, NULL), 1);
}
fz_buffer *
diff --git a/source/fitz/stext-output.c b/source/fitz/stext-output.c
index 1ba9fe51..70b0bf7e 100644
--- a/source/fitz/stext-output.c
+++ b/source/fitz/stext-output.c
@@ -258,7 +258,7 @@ fz_print_stext_page_html(fz_context *ctx, fz_output *out, fz_stext_page *page)
break;
default:
{
- fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image->image, image->image->w, image->image->h);
+ fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image->image);
fz_printf(ctx, out, "image/png;base64,");
send_data_base64(ctx, out, buf);
fz_drop_buffer(ctx, buf);
diff --git a/source/fitz/stream-read.c b/source/fitz/stream-read.c
index 2ebd5ad6..2ace7b1f 100644
--- a/source/fitz/stream-read.c
+++ b/source/fitz/stream-read.c
@@ -27,6 +27,26 @@ fz_read(fz_context *ctx, fz_stream *stm, unsigned char *buf, int len)
return count;
}
+static unsigned char skip_buf[4096];
+
+int fz_skip(fz_context *ctx, fz_stream *stm, int len)
+{
+ int count, l, total = 0;
+
+ while (len)
+ {
+ l = len;
+ if (l > sizeof(skip_buf))
+ l = sizeof(skip_buf);
+ count = fz_read(ctx, stm, skip_buf, l);
+ total += count;
+ if (count < l)
+ break;
+ len -= count;
+ }
+ return total;
+}
+
fz_buffer *
fz_read_all(fz_context *ctx, fz_stream *stm, int initial)
{
diff --git a/source/fitz/svg-device.c b/source/fitz/svg-device.c
index d36a5872..5f60cf75 100644
--- a/source/fitz/svg-device.c
+++ b/source/fitz/svg-device.c
@@ -743,7 +743,7 @@ svg_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_ma
break;
default:
{
- fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image, image->w, image->h);
+ fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image);
fz_printf(ctx, out, "image/png;base64,");
send_data_base64(ctx, out, buf);
fz_drop_buffer(ctx, buf);
@@ -830,7 +830,7 @@ svg_dev_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const
break;
default:
{
- fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image, image->w, image->h);
+ fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image);
fz_printf(ctx, out, "image/png;base64,");
send_data_base64(ctx, out, buf);
fz_drop_buffer(ctx, buf);
@@ -874,7 +874,7 @@ svg_dev_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const
break;
default:
{
- fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image, image->w, image->h);
+ fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, image);
fz_printf(ctx, out, "image/png;base64,");
send_data_base64(ctx, out, buf);
fz_drop_buffer(ctx, buf);
diff --git a/source/fitz/test-device.c b/source/fitz/test-device.c
index 64c7804f..6a4e0127 100644
--- a/source/fitz/test-device.c
+++ b/source/fitz/test-device.c
@@ -184,7 +184,7 @@ fz_test_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_ma
return;
}
- pix = fz_get_pixmap_from_image(ctx, image, 0, 0);
+ pix = fz_get_pixmap_from_image(ctx, image, NULL, NULL, 0, 0);
if (pix == NULL) /* Should never happen really, but... */
return;
diff --git a/source/gprf/gprf-doc.c b/source/gprf/gprf-doc.c
index d56501ba..d1dc4aa3 100644
--- a/source/gprf/gprf-doc.c
+++ b/source/gprf/gprf-doc.c
@@ -314,7 +314,7 @@ unsigned char undelta(unsigned char delta, unsigned char *ptr, int len)
}
static fz_pixmap *
-gprf_get_pixmap(fz_context *ctx, fz_image *image_, int w, int h, int *l2factor)
+gprf_get_pixmap(fz_context *ctx, fz_image *image_, fz_irect *area, int w, int h, int *l2factor)
{
/* The file contains RGB + up to FZ_MAX_SEPARATIONS. Hence the
* "3 + FZ_MAX_SEPARATIONS" usage in all the arrays below. */
@@ -332,6 +332,14 @@ gprf_get_pixmap(fz_context *ctx, fz_image *image_, int w, int h, int *l2factor)
fz_var(file);
+ if (area)
+ {
+ area->x0 = 0;
+ area->y0 = 0;
+ area->x1 = image->base.w;
+ area->y1 = image->base.h;
+ }
+
fz_try(ctx)
{
/* First off, figure out if we are doing RGB or separations
diff --git a/source/pdf/pdf-image.c b/source/pdf/pdf-image.c
index 04e1c1f0..e0da7ad9 100644
--- a/source/pdf/pdf-image.c
+++ b/source/pdf/pdf-image.c
@@ -330,7 +330,7 @@ pdf_add_image(fz_context *ctx, pdf_document *doc, fz_image *image, int mask)
/* Currently, set to maintain resolution; should we consider
* subsampling here according to desired output res? */
- pixmap = fz_get_pixmap_from_image(ctx, image, image->w, image->h);
+ pixmap = fz_get_pixmap_from_image(ctx, image, NULL, NULL, NULL, NULL);
colorspace = pixmap->colorspace; /* May be different to image->colorspace! */
n = (pixmap->n == 1 ? 1 : pixmap->n - 1);
size = image->w * image->h * n;
diff --git a/source/pdf/pdf-resources.c b/source/pdf/pdf-resources.c
index 4fae6c87..212c57df 100644
--- a/source/pdf/pdf-resources.c
+++ b/source/pdf/pdf-resources.c
@@ -28,7 +28,7 @@ res_image_get_md5(fz_context *ctx, fz_image *image, unsigned char *digest)
fz_pixmap *pixmap;
fz_md5 state;
- pixmap = fz_get_pixmap_from_image(ctx, image, 0, 0);
+ pixmap = fz_get_pixmap_from_image(ctx, image, NULL, NULL, 0, 0);
fz_md5_init(&state);
fz_md5_update(&state, pixmap->samples, pixmap->w * pixmap->h * pixmap->n);
fz_md5_final(&state, digest);
diff --git a/source/pdf/pdf-stream.c b/source/pdf/pdf-stream.c
index 1743a22c..3c275d2d 100644
--- a/source/pdf/pdf-stream.c
+++ b/source/pdf/pdf-stream.c
@@ -357,7 +357,7 @@ pdf_load_compressed_inline_image(fz_context *ctx, pdf_document *doc, pdf_obj *di
stm = fz_open_leecher(ctx, stm, bc->buffer);
stm = fz_open_image_decomp_stream(ctx, stm, &bc->params, &dummy_l2factor);
- image->tile = fz_decomp_image_from_stream(ctx, stm, image, indexed, 0);
+ image->tile = fz_decomp_image_from_stream(ctx, stm, image, NULL, indexed, 0);
}
fz_catch(ctx)
{
diff --git a/source/tools/murun.c b/source/tools/murun.c
index c2a9f0bc..6e6e2719 100644
--- a/source/tools/murun.c
+++ b/source/tools/murun.c
@@ -1881,12 +1881,10 @@ static void ffi_Image_toPixmap(js_State *J)
{
fz_context *ctx = js_getcontext(J);
fz_image *image = js_touserdata(J, 0, "fz_image");
- int w = js_isnumber(J, 1) ? js_tonumber(J, 1) : image->w;
- int h = js_isnumber(J, 2) ? js_tonumber(J, 2) : image->h;
fz_pixmap *pixmap = NULL;
fz_try(ctx)
- pixmap = fz_get_pixmap_from_image(ctx, image, w, h);
+ pixmap = fz_get_pixmap_from_image(ctx, image, NULL, NULL, NULL, NULL);
fz_catch(ctx)
rethrow(J);
diff --git a/source/tools/pdfextract.c b/source/tools/pdfextract.c
index 74b3654e..3f79137a 100644
--- a/source/tools/pdfextract.c
+++ b/source/tools/pdfextract.c
@@ -72,7 +72,7 @@ static void saveimage(int num)
/* TODO: detect DCTD and save as jpeg */
image = pdf_load_image(ctx, doc, ref);
- pix = fz_get_pixmap_from_image(ctx, image, 0, 0);
+ pix = fz_get_pixmap_from_image(ctx, image, NULL, NULL, 0, 0);
fz_drop_image(ctx, image);
snprintf(buf, sizeof(buf), "img-%04d", num);