diff options
author | Robin Watts <robin.watts@artifex.com> | 2012-11-21 15:59:56 +0000 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2012-11-21 17:31:02 +0000 |
commit | 678904ef2e6fb9c449b8bdaeba5802643592d4a4 (patch) | |
tree | c5c5b97fc6a9a62d25a1ce8331feb76683522990 | |
parent | 06fd5ad8a48b0339bb00ef531d84733fb05f19c6 (diff) | |
download | mupdf-678904ef2e6fb9c449b8bdaeba5802643592d4a4.tar.xz |
Add weights caches for pixmap scaling.
This means that repeated scaling of the same pixmap (or scales of
'stacked' pixmaps) will do less needless recalculation.
-rw-r--r-- | draw/draw_device.c | 29 | ||||
-rw-r--r-- | draw/draw_scale.c | 88 | ||||
-rw-r--r-- | draw/draw_simple_scale.c | 88 | ||||
-rw-r--r-- | fitz/fitz-internal.h | 7 |
4 files changed, 184 insertions, 28 deletions
diff --git a/draw/draw_device.c b/draw/draw_device.c index 8d2c4d8b..a52c77ca 100644 --- a/draw/draw_device.c +++ b/draw/draw_device.c @@ -40,6 +40,8 @@ struct fz_draw_device_s fz_context *ctx; int flags; int top; + fz_scale_cache *cache_x; + fz_scale_cache *cache_y; fz_draw_state *stack; int stack_max; fz_draw_state init_stack[STACK_SIZE]; @@ -937,9 +939,10 @@ fz_draw_fill_shade(fz_device *devp, fz_shade *shade, fz_matrix ctm, float alpha) } static fz_pixmap * -fz_transform_pixmap(fz_context *ctx, fz_pixmap *image, fz_matrix *ctm, int x, int y, int dx, int dy, int gridfit, fz_bbox *clip) +fz_transform_pixmap(fz_draw_device *dev, fz_pixmap *image, fz_matrix *ctm, int x, int y, int dx, int dy, int gridfit, fz_bbox *clip) { fz_pixmap *scaled; + fz_context *ctx = dev->ctx; if (ctm->a != 0 && ctm->b == 0 && ctm->c == 0 && ctm->d != 0) { @@ -947,7 +950,7 @@ fz_transform_pixmap(fz_context *ctx, fz_pixmap *image, fz_matrix *ctm, int x, in fz_matrix m = *ctm; if (gridfit) fz_gridfit_matrix(&m); - scaled = fz_scale_pixmap(ctx, image, m.e, m.f, m.a, m.d, clip); + scaled = fz_scale_pixmap_cached(ctx, image, m.e, m.f, m.a, m.d, clip, dev->cache_x, dev->cache_y); if (!scaled) return NULL; ctm->a = scaled->w; @@ -971,7 +974,7 @@ fz_transform_pixmap(fz_context *ctx, fz_pixmap *image, fz_matrix *ctm, int x, in rclip.x1 = clip->y1; rclip.y1 = clip->x1; } - scaled = fz_scale_pixmap(ctx, image, m.f, m.e, m.b, m.c, (clip ? &rclip : 0)); + scaled = fz_scale_pixmap_cached(ctx, image, m.f, m.e, m.b, m.c, (clip ? &rclip : 0), dev->cache_x, dev->cache_y); if (!scaled) return NULL; ctm->b = scaled->w; @@ -984,7 +987,7 @@ fz_transform_pixmap(fz_context *ctx, fz_pixmap *image, fz_matrix *ctm, int x, in /* Downscale, non rectilinear case */ if (dx > 0 && dy > 0) { - scaled = fz_scale_pixmap(ctx, image, 0, 0, (float)dx, (float)dy, NULL); + scaled = fz_scale_pixmap_cached(ctx, image, 0, 0, (float)dx, (float)dy, NULL, dev->cache_x, dev->cache_y); return scaled; } @@ -1048,14 +1051,14 @@ fz_draw_fill_image(fz_device *devp, fz_image *image, fz_matrix ctm, float alpha) if (dx < pixmap->w && dy < pixmap->h) { int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); - scaled = fz_transform_pixmap(ctx, pixmap, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip); + scaled = fz_transform_pixmap(dev, 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, pixmap, pixmap->x, pixmap->y, dx, dy, NULL); + scaled = fz_scale_pixmap_cached(ctx, pixmap, pixmap->x, pixmap->y, dx, dy, NULL, dev->cache_x, dev->cache_y); } if (scaled) pixmap = scaled; @@ -1128,14 +1131,14 @@ fz_draw_fill_image_mask(fz_device *devp, fz_image *image, fz_matrix ctm, if (dx < pixmap->w && dy < pixmap->h) { 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); + scaled = fz_transform_pixmap(dev, 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); + scaled = fz_scale_pixmap_cached(dev->ctx, pixmap, pixmap->x, pixmap->y, dx, dy, NULL, dev->cache_x, dev->cache_y); } if (scaled) pixmap = scaled; @@ -1227,14 +1230,14 @@ fz_draw_clip_image_mask(fz_device *devp, fz_image *image, fz_rect *rect, fz_matr if (dx < pixmap->w && dy < pixmap->h) { int gridfit = !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); - scaled = fz_transform_pixmap(dev->ctx, pixmap, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip); + scaled = fz_transform_pixmap(dev, 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); + scaled = fz_scale_pixmap_cached(dev->ctx, pixmap, pixmap->x, pixmap->y, dx, dy, NULL, dev->cache_x, dev->cache_y); } if (scaled) pixmap = scaled; @@ -1699,6 +1702,8 @@ fz_draw_free_user(fz_device *devp) */ if (dev->stack != &dev->init_stack[0]) fz_free(ctx, dev->stack); + fz_free_scale_cache(ctx, dev->cache_x); + fz_free_scale_cache(ctx, dev->cache_y); fz_free_gel(dev->gel); fz_free(ctx, dev); } @@ -1716,6 +1721,8 @@ fz_new_draw_device(fz_context *ctx, fz_pixmap *dest) ddev->flags = 0; ddev->ctx = ctx; ddev->top = 0; + ddev->cache_x = fz_new_scale_cache(ctx); + ddev->cache_y = fz_new_scale_cache(ctx); ddev->stack = &ddev->init_stack[0]; ddev->stack_max = STACK_SIZE; ddev->stack[0].dest = dest; @@ -1731,6 +1738,8 @@ fz_new_draw_device(fz_context *ctx, fz_pixmap *dest) } fz_catch(ctx) { + fz_free_scale_cache(ctx, ddev->cache_x); + fz_free_scale_cache(ctx, ddev->cache_y); fz_free_gel(ddev->gel); fz_free(ctx, ddev); fz_rethrow(ctx); diff --git a/draw/draw_scale.c b/draw/draw_scale.c index aceec939..34738fab 100644 --- a/draw/draw_scale.c +++ b/draw/draw_scale.c @@ -273,6 +273,21 @@ struct fz_weights_s int index[1]; }; +struct fz_scale_cache_s +{ + int src_w; + float x; + float dst_w; + fz_scale_filter *filter; + int vertical; + int dst_w_int; + int patch_l; + int patch_r; + int n; + int flip; + fz_weights *weights; +}; + static fz_weights * new_weights(fz_context *ctx, fz_scale_filter *filter, int src_w, float dst_w, int patch_w, int n, int flip, int patch_l) { @@ -493,13 +508,37 @@ check_weights(fz_weights *weights, int j, int w, float x, float wf) } static fz_weights * -make_weights(fz_context *ctx, int src_w, float x, float dst_w, fz_scale_filter *filter, int vertical, int dst_w_int, int patch_l, int patch_r, int n, int flip) +make_weights(fz_context *ctx, int src_w, float x, float dst_w, fz_scale_filter *filter, int vertical, int dst_w_int, int patch_l, int patch_r, int n, int flip, fz_scale_cache *cache) { fz_weights *weights; float F, G; float window; int j; + if (cache) + { + if (cache->src_w == src_w && cache->x == x && cache->dst_w == dst_w && + cache->filter == filter && cache->vertical == vertical && + cache->dst_w_int == dst_w_int && + cache->patch_l == patch_l && cache->patch_r == patch_r && + cache->n == n && cache->flip == flip) + { + return cache->weights; + } + cache->src_w = src_w; + cache->x = x; + cache->dst_w = dst_w; + cache->filter = filter; + cache->vertical = vertical; + cache->dst_w_int = dst_w_int; + cache->patch_l = patch_l; + cache->patch_r = patch_r; + cache->n = n; + cache->flip = flip; + fz_free(ctx, cache->weights); + cache->weights = NULL; + } + if (dst_w < src_w) { /* Scaling down */ @@ -537,6 +576,10 @@ make_weights(fz_context *ctx, int src_w, float x, float dst_w, fz_scale_filter * } } weights->count++; /* weights->count = dst_w_int now */ + if (cache) + { + cache->weights = weights; + } return weights; } @@ -1197,6 +1240,12 @@ scale_single_col(unsigned char *dst, unsigned char *src, fz_weights *weights, in fz_pixmap * fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_bbox *clip) { + return fz_scale_pixmap_cached(ctx, src, x, y, w, h, clip, NULL, NULL); +} + +fz_pixmap * +fz_scale_pixmap_cached(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_bbox *clip, fz_scale_cache *cache_x, fz_scale_cache *cache_y) +{ fz_scale_filter *filter = &fz_scale_filter_simple; fz_weights *contrib_rows = NULL; fz_weights *contrib_cols = NULL; @@ -1332,20 +1381,22 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa contrib_cols = NULL; else #endif /* SINGLE_PIXEL_SPECIALS */ - contrib_cols = make_weights(ctx, src->w, x, w, filter, 0, dst_w_int, patch.x0, patch.x1, src->n, flip_x); + contrib_cols = make_weights(ctx, src->w, x, w, filter, 0, dst_w_int, patch.x0, patch.x1, src->n, flip_x, cache_x); #ifdef SINGLE_PIXEL_SPECIALS if (src->h == 1) contrib_rows = NULL; else #endif /* SINGLE_PIXEL_SPECIALS */ - contrib_rows = make_weights(ctx, src->h, y, h, filter, 1, dst_h_int, patch.y0, patch.y1, src->n, flip_y); + contrib_rows = make_weights(ctx, src->h, y, h, filter, 1, dst_h_int, patch.y0, patch.y1, src->n, flip_y, cache_y); output = fz_new_pixmap(ctx, src->colorspace, patch.x1 - patch.x0, patch.y1 - patch.y0); } fz_catch(ctx) { - fz_free(ctx, contrib_cols); - fz_free(ctx, contrib_rows); + if (!cache_x) + fz_free(ctx, contrib_cols); + if (!cache_y) + fz_free(ctx, contrib_rows); fz_rethrow(ctx); } output->x = dst_x_int; @@ -1388,8 +1439,10 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa fz_catch(ctx) { fz_drop_pixmap(ctx, output); - fz_free(ctx, contrib_cols); - fz_free(ctx, contrib_rows); + if (!cache_x) + fz_free(ctx, contrib_cols); + if (!cache_y) + fz_free(ctx, contrib_rows); fz_rethrow(ctx); } switch (src->n) @@ -1434,7 +1487,24 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa } cleanup: - fz_free(ctx, contrib_rows); - fz_free(ctx, contrib_cols); + if (!cache_y) + fz_free(ctx, contrib_rows); + if (!cache_x) + fz_free(ctx, contrib_cols); return output; } + +void +fz_free_scale_cache(fz_context *ctx, fz_scale_cache *sc) +{ + if (!sc) + return; + fz_free(ctx, sc->weights); + fz_free(ctx, sc); +} + +fz_scale_cache * +fz_new_scale_cache(fz_context *ctx) +{ + return fz_malloc_struct(ctx, fz_scale_cache); +} diff --git a/draw/draw_simple_scale.c b/draw/draw_simple_scale.c index af995edc..606ee2bb 100644 --- a/draw/draw_simple_scale.c +++ b/draw/draw_simple_scale.c @@ -214,6 +214,21 @@ struct fz_weights_s int index[1]; }; +struct fz_scale_cache_s +{ + int src_w; + float x; + float dst_w; + fz_scale_filter *filter; + int vertical; + int dst_w_int; + int patch_l; + int patch_r; + int n; + int flip; + fz_weights *weights; +}; + static fz_weights * new_weights(fz_context *ctx, fz_scale_filter *filter, int src_w, float dst_w, int patch_w, int n, int flip, int patch_l) { @@ -442,13 +457,37 @@ check_weights(fz_weights *weights, int j, int w, float x, float wf) } static fz_weights * -make_weights(fz_context *ctx, int src_w, float x, float dst_w, fz_scale_filter *filter, int vertical, int dst_w_int, int patch_l, int patch_r, int n, int flip) +make_weights(fz_context *ctx, int src_w, float x, float dst_w, fz_scale_filter *filter, int vertical, int dst_w_int, int patch_l, int patch_r, int n, int flip, fz_scale_cache *cache) { fz_weights *weights; float F, G; float window; int j; + if (cache) + { + if (cache->src_w == src_w && cache->x == x && cache->dst_w == dst_w && + cache->filter == filter && cache->vertical == vertical && + cache->dst_w_int == dst_w_int && + cache->patch_l == patch_l && cache->patch_r == patch_r && + cache->n == n && cache->flip == flip) + { + return cache->weights; + } + cache->src_w = src_w; + cache->x = x; + cache->dst_w = dst_w; + cache->filter = filter; + cache->vertical = vertical; + cache->dst_w_int = dst_w_int; + cache->patch_l = patch_l; + cache->patch_r = patch_r; + cache->n = n; + cache->flip = flip; + fz_free(ctx, cache->weights); + cache->weights = NULL; + } + if (dst_w < src_w) { /* Scaling down */ @@ -486,6 +525,10 @@ make_weights(fz_context *ctx, int src_w, float x, float dst_w, fz_scale_filter * } } weights->count++; /* weights->count = dst_w_int now */ + if (cache) + { + cache->weights = weights; + } return weights; } @@ -1173,6 +1216,12 @@ scale_single_col(unsigned char *dst, unsigned char *src, fz_weights *weights, in fz_pixmap * fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_bbox *clip) { + return fz_scale_pixmap_cached(ctx, src, x, y, w, h, clip, NULL, NULL); +} + +fz_pixmap * +fz_scale_pixmap_cached(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_bbox *clip, fz_scale_cache *cache_x, fz_scale_cache *cache_y) +{ fz_scale_filter *filter = &fz_scale_filter_simple; fz_weights *contrib_rows = NULL; fz_weights *contrib_cols = NULL; @@ -1310,20 +1359,22 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa contrib_cols = NULL; else #endif /* SINGLE_PIXEL_SPECIALS */ - contrib_cols = make_weights(ctx, src->w, x, w, filter, 0, dst_w_int, patch.x0, patch.x1, src->n, flip_x); + contrib_cols = make_weights(ctx, src->w, x, w, filter, 0, dst_w_int, patch.x0, patch.x1, src->n, flip_x, cache_x); #ifdef SINGLE_PIXEL_SPECIALS if (src->h == 1) contrib_rows = NULL; else #endif /* SINGLE_PIXEL_SPECIALS */ - contrib_rows = make_weights(ctx, src->h, y, h, filter, 1, dst_h_int, patch.y0, patch.y1, src->n, flip_y); + contrib_rows = make_weights(ctx, src->h, y, h, filter, 1, dst_h_int, patch.y0, patch.y1, src->n, flip_y, cache_y); output = fz_new_pixmap(ctx, src->colorspace, patch.x1 - patch.x0, patch.y1 - patch.y0); } fz_catch(ctx) { - fz_free(ctx, contrib_cols); - fz_free(ctx, contrib_rows); + if (!cache_x) + fz_free(ctx, contrib_cols); + if (!cache_y) + fz_free(ctx, contrib_rows); fz_rethrow(ctx); } output->x = dst_x_int; @@ -1366,8 +1417,10 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa fz_catch(ctx) { fz_drop_pixmap(ctx, output); - fz_free(ctx, contrib_cols); - fz_free(ctx, contrib_rows); + if (!cache_x) + fz_free(ctx, contrib_cols); + if (!cache_y) + fz_free(ctx, contrib_rows); fz_rethrow(ctx); } switch (src->n) @@ -1412,7 +1465,24 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa } cleanup: - fz_free(ctx, contrib_rows); - fz_free(ctx, contrib_cols); + if (!cache_y) + fz_free(ctx, contrib_rows); + if (!cache_x) + fz_free(ctx, contrib_cols); return output; } + +void +fz_free_scale_cache(fz_context *ctx, fz_scale_cache *sc) +{ + if (!sc) + return; + fz_free(ctx, sc->weights); + fz_free(ctx, sc); +} + +fz_scale_cache * +fz_new_scale_cache(fz_context *ctx) +{ + return fz_malloc_struct(ctx, fz_scale_cache); +} diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h index d7bbb5cb..914bed68 100644 --- a/fitz/fitz-internal.h +++ b/fitz/fitz-internal.h @@ -860,6 +860,13 @@ fz_pixmap *fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray, int luminosity); unsigned int fz_pixmap_size(fz_context *ctx, fz_pixmap *pix); fz_pixmap *fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_bbox *clip); + +typedef struct fz_scale_cache_s fz_scale_cache; + +fz_scale_cache *fz_new_scale_cache(fz_context *ctx); +void fz_free_scale_cache(fz_context *ctx, fz_scale_cache *cache); +fz_pixmap *fz_scale_pixmap_cached(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_bbox *clip, fz_scale_cache *cache_x, fz_scale_cache *cache_y); + void fz_subsample_pixmap(fz_context *ctx, fz_pixmap *tile, int factor); fz_bbox fz_pixmap_bbox_no_ctx(fz_pixmap *src); |