summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2016-04-12 13:17:02 +0100
committerRobin Watts <robin.watts@artifex.com>2016-04-28 12:30:41 +0100
commit3dc16d54db4669415412bb44790d4653962747f6 (patch)
treef45096e35afbd29f22e4e2c7c2a16c61ec9da468
parentb944f16a564f8a31d9a064980318ad690be31f8e (diff)
downloadmupdf-3dc16d54db4669415412bb44790d4653962747f6.tar.xz
Introduce tuning context.
For now, just use it for controlling image decoding and image scaling.
-rw-r--r--include/mupdf/fitz/context.h75
-rw-r--r--scripts/cmapdump.c9
-rw-r--r--source/fitz/context.c44
-rw-r--r--source/fitz/draw-device.c13
-rw-r--r--source/fitz/image.c42
5 files changed, 168 insertions, 15 deletions
diff --git a/include/mupdf/fitz/context.h b/include/mupdf/fitz/context.h
index 449ed368..3b46de34 100644
--- a/include/mupdf/fitz/context.h
+++ b/include/mupdf/fitz/context.h
@@ -3,6 +3,7 @@
#include "mupdf/fitz/version.h"
#include "mupdf/fitz/system.h"
+#include "mupdf/fitz/math.h"
/*
Contexts
@@ -18,6 +19,7 @@ typedef struct fz_colorspace_context_s fz_colorspace_context;
typedef struct fz_aa_context_s fz_aa_context;
typedef struct fz_style_context_s fz_style_context;
typedef struct fz_locks_context_s fz_locks_context;
+typedef struct fz_tuning_context_s fz_tuning_context;
typedef struct fz_store_s fz_store;
typedef struct fz_glyph_cache_s fz_glyph_cache;
typedef struct fz_document_handler_context_s fz_document_handler_context;
@@ -116,6 +118,7 @@ struct fz_context_s
fz_style_context *style;
fz_store *store;
fz_glyph_cache *glyph_cache;
+ fz_tuning_context *tuning;
fz_document_handler_context *handler;
};
@@ -211,6 +214,65 @@ void fz_set_user_context(fz_context *ctx, void *user);
void *fz_user_context(fz_context *ctx);
/*
+ In order to tune MuPDFs behaviour, certain functions can
+ (optionally) be provided by callers.
+*/
+
+/*
+ fz_tune_image_decode_fn: Given the width and height of an image,
+ the subsample factor, and the subarea of the image actually
+ required, the caller can decide whether to decode the whole image
+ or just a subarea.
+
+ arg: The caller supplied opaque argument.
+
+ w, h: The width/height of the complete image.
+
+ l2factor: The log2 factor for subsampling (i.e. image will be
+ decoded to (w>>l2factor, h>>l2factor)).
+
+ subarea: The actual subarea required for the current operation.
+ The tuning function is allowed to increase this in size if required.
+*/
+typedef void (fz_tune_image_decode_fn)(void *arg, int w, int h, int l2factor, fz_irect *subarea);
+
+/*
+ fz_tune_image_scale_fn: Given the source width and height of
+ image, together with the actual required width and height,
+ decide whether we should use mitchell scaling.
+
+ arg: The caller supplied opaque argument.
+
+ dst_w, dst_h: The actual width/height required on the target device.
+
+ src_w, src_h: The source width/height of the image.
+
+ Return 0 not to use the Mitchell scaler, 1 to use the Mitchell scaler. All
+ other values reserved.
+*/
+typedef int (fz_tune_image_scale_fn)(void *arg, int dst_w, int dst_h, int src_w, int src_h);
+
+/*
+ fz_tune_image_decode: Set the tuning function to use for
+ image decode.
+
+ image_decode: Function to use.
+
+ arg: Opaque argument to be passed to tuning function.
+*/
+void fz_tune_image_decode(fz_context *ctx, fz_tune_image_decode_fn *image_decode, void *arg);
+
+/*
+ fz_tune_image_scale: Set the tuning function to use for
+ image scaling.
+
+ image_scale: Function to use.
+
+ arg: Opaque argument to be passed to tuning function.
+*/
+void fz_tune_image_scale(fz_context *ctx, fz_tune_image_scale_fn *image_scale, void *arg);
+
+/*
fz_aa_level: Get the number of bits of antialiasing we are
using (for graphics). Between 0 and 8.
*/
@@ -482,6 +544,19 @@ void fz_new_document_handler_context(fz_context *ctx);
void fz_drop_document_handler_context(fz_context *ctx);
fz_document_handler_context *fz_keep_document_handler_context(fz_context *ctx);
+/* Tuning context implementation details */
+struct fz_tuning_context_s
+{
+ int refs;
+ fz_tune_image_decode_fn *image_decode;
+ void *image_decode_arg;
+ fz_tune_image_scale_fn *image_scale;
+ void *image_scale_arg;
+};
+
+fz_tune_image_decode_fn fz_default_image_decode;
+fz_tune_image_scale_fn fz_default_image_scale;
+
/* Default allocator */
extern fz_alloc_context fz_alloc_default;
diff --git a/scripts/cmapdump.c b/scripts/cmapdump.c
index 540fd946..9cc3523b 100644
--- a/scripts/cmapdump.c
+++ b/scripts/cmapdump.c
@@ -287,3 +287,12 @@ fz_document_handler_context *fz_keep_document_handler_context(fz_context *ctx)
{
return NULL;
}
+
+void fz_default_image_decode(void *arg, int w, int h, int l2factor, fz_irect *irect)
+{
+}
+
+int fz_default_image_scale(void *arg, int w, int h, int src_w, int src_h)
+{
+ return 0;
+}
diff --git a/source/fitz/context.c b/source/fitz/context.c
index 0f9a8b77..bfc7a1cd 100644
--- a/source/fitz/context.c
+++ b/source/fitz/context.c
@@ -76,6 +76,46 @@ const char *fz_user_css(fz_context *ctx)
return ctx->style->user_css;
}
+static void fz_new_tuning_context(fz_context *ctx)
+{
+ if (ctx)
+ {
+ ctx->tuning = fz_malloc_struct(ctx, fz_tuning_context);
+ ctx->tuning->refs = 1;
+ ctx->tuning->image_decode = &fz_default_image_decode;
+ ctx->tuning->image_scale = &fz_default_image_scale;
+ }
+}
+
+static fz_tuning_context *fz_keep_tuning_context(fz_context *ctx)
+{
+ if (!ctx)
+ return NULL;
+ return fz_keep_imp(ctx, ctx->tuning, &ctx->tuning->refs);
+}
+
+static void fz_drop_tuning_context(fz_context *ctx)
+{
+ if (!ctx)
+ return;
+ if (fz_drop_imp(ctx, ctx->tuning, &ctx->tuning->refs))
+ {
+ fz_free(ctx, ctx->tuning);
+ }
+}
+
+void fz_tune_image_decode(fz_context *ctx, fz_tune_image_decode_fn *image_decode, void *arg)
+{
+ ctx->tuning->image_decode = image_decode ? image_decode : fz_default_image_decode;
+ ctx->tuning->image_decode_arg = arg;
+}
+
+void fz_tune_image_scale(fz_context *ctx, fz_tune_image_scale_fn *image_scale, void *arg)
+{
+ ctx->tuning->image_scale = image_scale ? image_scale : fz_default_image_scale;
+ ctx->tuning->image_scale_arg = arg;
+}
+
void
fz_drop_context(fz_context *ctx)
{
@@ -88,6 +128,7 @@ fz_drop_context(fz_context *ctx)
fz_drop_store_context(ctx);
fz_drop_aa_context(ctx);
fz_drop_style_context(ctx);
+ fz_drop_tuning_context(ctx);
fz_drop_colorspace_context(ctx);
fz_drop_font_context(ctx);
fz_drop_id_context(ctx);
@@ -188,6 +229,7 @@ fz_new_context_imp(const fz_alloc_context *alloc, const fz_locks_context *locks,
fz_new_id_context(ctx);
fz_new_document_handler_context(ctx);
fz_new_style_context(ctx);
+ fz_new_tuning_context(ctx);
}
fz_catch(ctx)
{
@@ -237,6 +279,8 @@ fz_clone_context_internal(fz_context *ctx)
new_ctx->style = fz_keep_style_context(new_ctx);
new_ctx->id = ctx->id;
new_ctx->id = fz_keep_id_context(new_ctx);
+ new_ctx->tuning = ctx->tuning;
+ new_ctx->tuning = fz_keep_tuning_context(new_ctx);
new_ctx->handler = ctx->handler;
new_ctx->handler = fz_keep_document_handler_context(new_ctx);
diff --git a/source/fitz/draw-device.c b/source/fitz/draw-device.c
index 4108cf09..c32b8f60 100644
--- a/source/fitz/draw-device.c
+++ b/source/fitz/draw-device.c
@@ -1092,6 +1092,13 @@ fz_transform_pixmap(fz_context *ctx, fz_draw_device *dev, const fz_pixmap *image
return NULL;
}
+int
+fz_default_image_scale(void *arg, int dst_w, int dst_h, int src_w, int src_h)
+{
+ (void)arg;
+ return dst_w < src_w && dst_h < src_h;
+}
+
static void
fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_matrix *ctm, float alpha)
{
@@ -1182,7 +1189,7 @@ fz_draw_fill_image(fz_context *ctx, fz_device *devp, fz_image *image, const fz_m
pixmap = converted;
}
- if (dx < pixmap->w && dy < pixmap->h && !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES))
+ if (!(devp->hints & FZ_DONT_INTERPOLATE_IMAGES) && ctx->tuning->image_scale(ctx->tuning->image_scale_arg, dx, dy, pixmap->w, pixmap->h))
{
int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3);
scaled = fz_transform_pixmap(ctx, dev, pixmap, &local_ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip);
@@ -1300,7 +1307,7 @@ fz_draw_fill_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const
if (state->blendmode & FZ_BLEND_KNOCKOUT)
state = fz_knockout_begin(ctx, dev);
- if (dx < pixmap->w && dy < pixmap->h)
+ if (ctx->tuning->image_scale(ctx->tuning->image_scale_arg, dx, dy, pixmap->w, pixmap->h))
{
int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3);
scaled = fz_transform_pixmap(ctx, dev, pixmap, &local_ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip);
@@ -1409,7 +1416,7 @@ fz_draw_clip_image_mask(fz_context *ctx, fz_device *devp, fz_image *image, const
state[1].blendmode |= FZ_BLEND_ISOLATED;
state[1].scissor = bbox;
- if (dx < pixmap->w && dy < pixmap->h)
+ if (ctx->tuning->image_scale(ctx->tuning->image_scale_arg, dx, dy, pixmap->w, pixmap->h))
{
int gridfit = !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3);
scaled = fz_transform_pixmap(ctx, dev, pixmap, &local_ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip);
diff --git a/source/fitz/image.c b/source/fitz/image.c
index 36026a19..c622c92b 100644
--- a/source/fitz/image.c
+++ b/source/fitz/image.c
@@ -381,6 +381,33 @@ update_ctm_for_subarea(fz_matrix *ctm, const fz_irect *subarea, int w, int h)
fz_concat(ctm, &m, ctm);
}
+void fz_default_image_decode(void *arg, int w, int h, int l2factor, fz_irect *subarea)
+{
+ (void)arg;
+
+ if ((subarea->x1-subarea->x0)*(subarea->y1-subarea->y0) >= (w*h/10)*9)
+ {
+ /* Either no subarea specified, or a subarea 90% or more of the
+ * whole area specified. Use the whole image. */
+ subarea->x0 = 0;
+ subarea->y0 = 0;
+ subarea->x1 = w;
+ subarea->y1 = h;
+ }
+ else
+ {
+ /* Clip to the edges if they are within 1% */
+ if (subarea->x0 <= w/100)
+ subarea->x0 = 0;
+ if (subarea->y0 <= h/100)
+ subarea->y0 = 0;
+ if (subarea->x1 >= w*99/100)
+ subarea->x1 = w;
+ if (subarea->y1 >= h*99/100)
+ subarea->y1 = h;
+ }
+}
+
fz_pixmap *
fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, const fz_irect *subarea, fz_matrix *ctm, int *dw, int *dh)
{
@@ -436,10 +463,8 @@ fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, const fz_irect *subar
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)
+ if (subarea == NULL)
{
- /* 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;
@@ -447,18 +472,11 @@ fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, const fz_irect *subar
}
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;
+ ctx->tuning->image_decode(ctx->tuning->image_decode_arg, image->w, image->h, l2factor, &key.rect);
}
+ /* Based on that subarea, recalculate the extents */
if (ctm)
{
float frac_w = (key.rect.x1 - key.rect.x0) / (float)image->w;