diff options
author | Robin Watts <robin.watts@artifex.com> | 2012-01-20 18:33:48 +0000 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2012-01-20 20:00:38 +0000 |
commit | d71ea260f6f9250abc2c358e2c4be0581763a7e3 (patch) | |
tree | 76982080b538d8aec300c5f342dc73050aa534dc | |
parent | 63cca1e65b6c81a6ff29fac46154b8a6ccaaa058 (diff) | |
download | mupdf-d71ea260f6f9250abc2c358e2c4be0581763a7e3.tar.xz |
Bitmap 'patch' scaling - second attempt.
When scaling a bitmap, currently we always scale the entire bitmap,
even if we only need a small section of the result.
This patch changes the code to take an optional 'clip' bbox, and
only scales as many pixels as are required to generate the required
output region.
-rw-r--r-- | draw/draw_device.c | 37 | ||||
-rw-r--r-- | draw/draw_scale.c | 176 | ||||
-rw-r--r-- | draw/draw_simple_scale.c | 105 | ||||
-rw-r--r-- | fitz/fitz.h | 2 |
4 files changed, 221 insertions, 99 deletions
diff --git a/draw/draw_device.c b/draw/draw_device.c index 9a238b73..1cb3e4b9 100644 --- a/draw/draw_device.c +++ b/draw/draw_device.c @@ -821,7 +821,7 @@ 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_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_pixmap *scaled; @@ -831,7 +831,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); + scaled = fz_scale_pixmap(ctx, image, m.e, m.f, m.a, m.d, clip); if (!scaled) return NULL; ctm->a = scaled->w; @@ -845,9 +845,17 @@ fz_transform_pixmap(fz_context *ctx, fz_pixmap *image, fz_matrix *ctm, int x, in { /* Other orthogonal flip/rotation cases */ fz_matrix m = *ctm; + fz_bbox rclip; if (gridfit) fz_gridfit_matrix(&m); - scaled = fz_scale_pixmap(ctx, image, m.f, m.e, m.b, m.c); + if (clip) + { + rclip.x0 = clip->y0; + rclip.y0 = clip->x0; + 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)); if (!scaled) return NULL; ctm->b = scaled->w; @@ -860,7 +868,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); + scaled = fz_scale_pixmap(ctx, image, 0, 0, (float)dx, (float)dy, NULL); return scaled; } @@ -878,6 +886,9 @@ fz_draw_fill_image(fz_device *devp, fz_pixmap *image, fz_matrix ctm, float alpha 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); + + clip = fz_intersect_bbox(clip, state->scissor); fz_var(scaled); @@ -915,14 +926,14 @@ fz_draw_fill_image(fz_device *devp, fz_pixmap *image, fz_matrix ctm, float alpha if (dx < image->w && dy < image->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); + scaled = fz_transform_pixmap(ctx, image, &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); + scaled = fz_scale_pixmap(ctx, image, image->x, image->y, dx, dy, NULL); } if (scaled) image = scaled; @@ -973,6 +984,9 @@ fz_draw_fill_image_mask(fz_device *devp, fz_pixmap *image, fz_matrix ctm, int i; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; + fz_bbox clip = fz_bound_pixmap(state->dest); + + clip = fz_intersect_bbox(clip, state->scissor); if (image->w == 0 || image->h == 0) return; @@ -985,14 +999,14 @@ fz_draw_fill_image_mask(fz_device *devp, fz_pixmap *image, fz_matrix ctm, if (dx < image->w && dy < image->h) { 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); + scaled = fz_transform_pixmap(dev->ctx, image, &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); + scaled = fz_scale_pixmap(dev->ctx, image, image->x, image->y, dx, dy, NULL); } if (scaled) image = scaled; @@ -1025,6 +1039,9 @@ fz_draw_clip_image_mask(fz_device *devp, fz_pixmap *image, fz_rect *rect, fz_mat int dx, dy; fz_draw_state *state = push_stack(dev); fz_colorspace *model = state->dest->colorspace; + fz_bbox clip = fz_bound_pixmap(state->dest); + + clip = fz_intersect_bbox(clip, state->scissor); fz_var(mask); fz_var(dest); @@ -1066,14 +1083,14 @@ fz_draw_clip_image_mask(fz_device *devp, fz_pixmap *image, fz_rect *rect, fz_mat if (dx < image->w && dy < image->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); + scaled = fz_transform_pixmap(dev->ctx, image, &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); + scaled = fz_scale_pixmap(dev->ctx, image, image->x, image->y, dx, dy, NULL); } if (scaled) image = scaled; diff --git a/draw/draw_scale.c b/draw/draw_scale.c index e478633c..87d0b334 100644 --- a/draw/draw_scale.c +++ b/draw/draw_scale.c @@ -262,16 +262,17 @@ typedef struct fz_weights_s fz_weights; struct fz_weights_s { - int flip; - int count; - int max_len; - int n; - int new_line; + int flip; /* true if outputting reversed */ + int count; /* number of output pixels we have records for in this table */ + int max_len; /* Maximum number of weights for any one output pixel */ + int n; /* number of components (src->n) */ + int new_line; /* True if no weights for the current output pixel */ + int patch_l; /* How many output pixels we skip over */ int index[1]; }; static fz_weights * -new_weights(fz_context *ctx, fz_scale_filter *filter, int src_w, float dst_w, int dst_w_i, int n, int flip) +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) { int max_len; fz_weights *weights; @@ -293,26 +294,29 @@ new_weights(fz_context *ctx, fz_scale_filter *filter, int src_w, float dst_w, in max_len = 2 * filter->width; } /* We need the size of the struct, - * plus dst_w*sizeof(int) for the index + * plus patch_w*sizeof(int) for the index * plus (2+max_len)*sizeof(int) for the weights * plus room for an extra set of weights for reordering. */ - weights = fz_malloc(ctx, sizeof(*weights)+(max_len+3)*(dst_w_i+1)*sizeof(int)); + weights = fz_malloc(ctx, sizeof(*weights)+(max_len+3)*(patch_w+1)*sizeof(int)); if (!weights) return NULL; weights->count = -1; weights->max_len = max_len; - weights->index[0] = dst_w_i; + weights->index[0] = patch_w; weights->n = n; + weights->patch_l = patch_l; weights->flip = flip; return weights; } +/* j is destination pixel in the patch_l..patch_l+patch_w range */ static void init_weights(fz_weights *weights, int j) { int index; + j -= weights->patch_l; assert(weights->count == j-1); weights->count++; weights->new_line = 1; @@ -344,24 +348,7 @@ add_weight(fz_weights *weights, int j, int i, fz_scale_filter *filter, if (weight == 0) return; - /* wrap i back into range */ -#ifdef MIRROR_WRAP - do - { - if (i < 0) - i = -1-i; - else if (i >= src_w) - i = 2*src_w-1-i; - else - break; - } - while (1); -#elif defined(WRAP) - if (i < 0) - i = 0; - else if (i >= src_w) - i = src_w-1; -#else + /* Ensure i is in range */ if (i < 0) { i = 0; @@ -374,10 +361,11 @@ add_weight(fz_weights *weights, int j, int i, fz_scale_filter *filter, } if (weight == 0) return; -#endif DBUG(("add_weight[%d][%d] = %d(%g) dist=%g\n",j,i,weight,f,dist)); + /* Move j from patch_l...patch_l+patch_w range to 0..patch_w range */ + j -= weights->patch_l; if (weights->new_line) { /* New line */ @@ -428,7 +416,7 @@ add_weight(fz_weights *weights, int j, int i, fz_scale_filter *filter, static void reorder_weights(fz_weights *weights, int j, int src_w) { - int idx = weights->index[j]; + int idx = weights->index[j - weights->patch_l]; int min = weights->index[idx++]; int len = weights->index[idx++]; int max = weights->max_len; @@ -475,7 +463,7 @@ check_weights(fz_weights *weights, int j, int w, float x, float wf) int maxidx = 0; int i; - idx = weights->index[j]; + idx = weights->index[j - weights->patch_l]; idx++; /* min */ len = weights->index[idx++]; @@ -505,7 +493,7 @@ 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 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_weights *weights; float F, G; @@ -525,11 +513,11 @@ make_weights(fz_context *ctx, int src_w, float x, float dst_w, fz_scale_filter * G = src_w / dst_w; } window = filter->width / F; - DBUG(("make_weights src_w=%d x=%g dst_w=%g dst_w_int=%d F=%g window=%g\n", src_w, x, dst_w, dst_w_int, F, window)); - weights = new_weights(ctx, filter, src_w, dst_w, dst_w_int, n, flip); + DBUG(("make_weights src_w=%d x=%g dst_w=%g patch_l=%d patch_r=%d F=%g window=%g\n", src_w, x, dst_w, patch_l, patch_r, F, window)); + weights = new_weights(ctx, filter, src_w, dst_w, patch_r-patch_l, n, flip, patch_l); if (!weights) return NULL; - for (j = 0; j < dst_w_int; j++) + for (j = patch_l; j < patch_r; j++) { /* find the position of the centre of dst[j] in src space */ float centre = (j - x + 0.5f)*src_w/dst_w - 0.5f; @@ -1206,9 +1194,8 @@ scale_single_col(unsigned char *dst, unsigned char *src, fz_weights *weights, in } #endif /* SINGLE_PIXEL_SPECIALS */ - fz_pixmap * -fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h) +fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_bbox *clip) { fz_scale_filter *filter = &fz_scale_filter_simple; fz_weights *contrib_rows = NULL; @@ -1218,6 +1205,10 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa int max_row, temp_span, temp_rows, row; int dst_w_int, dst_h_int, dst_x_int, dst_y_int; int flip_x, flip_y; + fz_bbox patch; + + fz_var(contrib_cols); + fz_var(contrib_rows); DBUG(("Scale: (%d,%d) to (%g,%g) at (%g,%g)\n",src->w,src->h,w,h,x,y)); @@ -1281,35 +1272,82 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa DBUG(("Result image: (%d,%d) at (%d,%d) (subpix=%g,%g)\n", dst_w_int, dst_h_int, dst_x_int, dst_y_int, x, y)); - /* Step 1: Calculate the weights for columns and rows */ -#ifdef SINGLE_PIXEL_SPECIALS - if (src->w == 1) + /* Step 0: Calculate the patch */ + patch.x0 = 0; + patch.y0 = 0; + patch.x1 = dst_w_int; + patch.y1 = dst_h_int; + if (clip) { - contrib_cols = NULL; + if (flip_x) + { + if (dst_x_int + dst_w_int > clip->x1) + patch.x0 = dst_x_int + dst_w_int - clip->x1; + if (clip->x0 > dst_x_int) + { + patch.x1 = dst_w_int - (clip->x0 - dst_x_int); + dst_x_int = clip->x0; + } + } + else + { + if (dst_x_int + dst_w_int > clip->x1) + patch.x1 = clip->x1 - dst_x_int; + if (clip->x0 > dst_x_int) + { + patch.x0 = clip->x0 - dst_x_int; + dst_x_int += patch.x0; + } + } + + if (flip_y) + { + if (dst_y_int + dst_h_int > clip->y1) + patch.y1 = clip->y1 - dst_y_int; + if (clip->y0 > dst_y_int) + { + patch.y0 = clip->y0 - dst_y_int; + dst_y_int = clip->y0; + } + } + else + { + if (dst_y_int + dst_h_int > clip->y1) + patch.y1 = clip->y1 - dst_y_int; + if (clip->y0 > dst_y_int) + { + patch.y0 = clip->y0 - dst_y_int; + dst_y_int += patch.y0; + } + } } - else -#endif /* SINGLE_PIXEL_SPECIALS */ + if (patch.x0 >= patch.x1 || patch.y0 >= patch.y1) + return NULL; + + fz_try(ctx) { - contrib_cols = make_weights(ctx, src->w, x, w, filter, 0, dst_w_int, src->n, flip_x); - if (!contrib_cols) - goto cleanup; - } + /* Step 1: Calculate the weights for columns and rows */ #ifdef SINGLE_PIXEL_SPECIALS - if (src->h == 1) - { - contrib_rows = NULL; - } - else + if (src->w == 1) + 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); +#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); + + output = fz_new_pixmap(ctx, src->colorspace, patch.x1 - patch.x0, patch.y1 - patch.y0); + } + fz_catch(ctx) { - contrib_rows = make_weights(ctx, src->h, y, h, filter, 1, dst_h_int, src->n, flip_y); - if (!contrib_rows) - goto cleanup; + fz_free(ctx, contrib_cols); + fz_free(ctx, contrib_rows); + fz_rethrow(ctx); } - - assert(!contrib_cols || contrib_cols->count == dst_w_int); - assert(!contrib_rows || contrib_rows->count == dst_h_int); - output = fz_new_pixmap(ctx, src->colorspace, dst_w_int, dst_h_int); output->x = dst_x_int; output->y = dst_y_int; @@ -1321,18 +1359,18 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa if (!contrib_cols) { /* Only 1 pixel in the entire image! */ - duplicate_single_pixel(output->samples, src->samples, src->n, dst_w_int, dst_h_int); + duplicate_single_pixel(output->samples, src->samples, src->n, patch.x1-patch.x0, patch.y1-patch.y0); } else { /* Scale the row once, then copy it. */ - scale_single_row(output->samples, src->samples, contrib_cols, src->w, dst_h_int); + scale_single_row(output->samples, src->samples, contrib_cols, src->w, patch.y1-patch.y0); } } else if (!contrib_cols) { /* Only 1 source pixel wide. Scale the col and duplicate. */ - scale_single_col(output->samples, src->samples, contrib_rows, src->h, src->n, dst_w_int, flip_y); + scale_single_col(output->samples, src->samples, contrib_rows, src->h, src->n, patch.x1-patch.x0, flip_y); } else #endif /* SINGLE_PIXEL_SPECIALS */ @@ -1343,9 +1381,17 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa temp_rows = contrib_rows->max_len; if (temp_span <= 0 || temp_rows > INT_MAX / temp_span) goto cleanup; - temp = fz_malloc_array(ctx, temp_span*temp_rows, sizeof(int)); - if (!temp) - goto cleanup; + fz_try(ctx) + { + temp = fz_calloc(ctx, temp_span*temp_rows, sizeof(int)); + } + fz_catch(ctx) + { + fz_drop_pixmap(ctx, output); + fz_free(ctx, contrib_cols); + fz_free(ctx, contrib_rows); + fz_rethrow(ctx); + } switch (src->n) { default: @@ -1361,7 +1407,7 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa row_scale = scale_row_to_temp4; break; } - max_row = 0; + max_row = contrib_rows->index[contrib_rows->index[0]]; for (row = 0; row < contrib_rows->count; row++) { /* diff --git a/draw/draw_simple_scale.c b/draw/draw_simple_scale.c index 178b182f..38b58e96 100644 --- a/draw/draw_simple_scale.c +++ b/draw/draw_simple_scale.c @@ -218,16 +218,17 @@ typedef struct fz_weights_s fz_weights; struct fz_weights_s { - int flip; - int count; - int max_len; - int n; - int new_line; + int flip; /* true if outputting reversed */ + int count; /* number of output pixels we have records for in this table */ + int max_len; /* Maximum number of weights for any one output pixel */ + int n; /* number of components (src->n) */ + int new_line; /* True if no weights for the current output pixel */ + int patch_l; /* How many output pixels we skip over */ int index[1]; }; static fz_weights * -new_weights(fz_context *ctx, fz_scale_filter *filter, int src_w, float dst_w, int dst_w_i, int n, int flip) +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) { int max_len; fz_weights *weights; @@ -249,26 +250,29 @@ new_weights(fz_context *ctx, fz_scale_filter *filter, int src_w, float dst_w, in max_len = 2 * filter->width; } /* We need the size of the struct, - * plus dst_w*sizeof(int) for the index + * plus patch_w*sizeof(int) for the index * plus (2+max_len)*sizeof(int) for the weights * plus room for an extra set of weights for reordering. */ - weights = fz_malloc(ctx, sizeof(*weights)+(max_len+3)*(dst_w_i+1)*sizeof(int)); + weights = fz_malloc(ctx, sizeof(*weights)+(max_len+3)*(patch_w+1)*sizeof(int)); if (!weights) return NULL; weights->count = -1; weights->max_len = max_len; - weights->index[0] = dst_w_i; + weights->index[0] = patch_w; weights->n = n; + weights->patch_l = patch_l; weights->flip = flip; return weights; } +/* j is destination pixel in the patch_l..patch_l+patch_w range */ static void init_weights(fz_weights *weights, int j) { int index; + j -= weights->patch_l; assert(weights->count == j-1); weights->count++; weights->new_line = 1; @@ -316,6 +320,8 @@ add_weight(fz_weights *weights, int j, int i, fz_scale_filter *filter, DBUG(("add_weight[%d][%d] = %d(%g) dist=%g\n",j,i,weight,f,dist)); + /* Move j from patch_l...patch_l+patch_w range to 0..patch_w range */ + j -= weights->patch_l; if (weights->new_line) { /* New line */ @@ -366,7 +372,7 @@ add_weight(fz_weights *weights, int j, int i, fz_scale_filter *filter, static void reorder_weights(fz_weights *weights, int j, int src_w) { - int idx = weights->index[j]; + int idx = weights->index[j - weights->patch_l]; int min = weights->index[idx++]; int len = weights->index[idx++]; int max = weights->max_len; @@ -413,7 +419,7 @@ check_weights(fz_weights *weights, int j, int w, float x, float wf) int maxidx = 0; int i; - idx = weights->index[j]; + idx = weights->index[j - weights->patch_l]; idx++; /* min */ len = weights->index[idx++]; @@ -443,7 +449,7 @@ 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 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_weights *weights; float F, G; @@ -463,11 +469,11 @@ make_weights(fz_context *ctx, int src_w, float x, float dst_w, fz_scale_filter * G = src_w / dst_w; } window = filter->width / F; - DBUG(("make_weights src_w=%d x=%g dst_w=%g dst_w_int=%d F=%g window=%g\n", src_w, x, dst_w, dst_w_int, F, window)); - weights = new_weights(ctx, filter, src_w, dst_w, dst_w_int, n, flip); + DBUG(("make_weights src_w=%d x=%g dst_w=%g patch_l=%d patch_r=%d F=%g window=%g\n", src_w, x, dst_w, patch_l, patch_r, F, window)); + weights = new_weights(ctx, filter, src_w, dst_w, patch_r-patch_l, n, flip, patch_l); if (!weights) return NULL; - for (j = 0; j < dst_w_int; j++) + for (j = patch_l; j < patch_r; j++) { /* find the position of the centre of dst[j] in src space */ float centre = (j - x + 0.5f)*src_w/dst_w - 0.5f; @@ -1167,7 +1173,7 @@ scale_single_col(unsigned char *dst, unsigned char *src, fz_weights *weights, in #endif /* SINGLE_PIXEL_SPECIALS */ fz_pixmap * -fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h) +fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_bbox *clip) { fz_scale_filter *filter = &fz_scale_filter_simple; fz_weights *contrib_rows = NULL; @@ -1177,6 +1183,7 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa int max_row, temp_span, temp_rows, row; int dst_w_int, dst_h_int, dst_x_int, dst_y_int; int flip_x, flip_y; + fz_bbox patch; fz_var(contrib_cols); fz_var(contrib_rows); @@ -1243,6 +1250,58 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa DBUG(("Result image: (%d,%d) at (%d,%d) (subpix=%g,%g)\n", dst_w_int, dst_h_int, dst_x_int, dst_y_int, x, y)); + /* Step 0: Calculate the patch */ + patch.x0 = 0; + patch.y0 = 0; + patch.x1 = dst_w_int; + patch.y1 = dst_h_int; + if (clip) + { + if (flip_x) + { + if (dst_x_int + dst_w_int > clip->x1) + patch.x0 = dst_x_int + dst_w_int - clip->x1; + if (clip->x0 > dst_x_int) + { + patch.x1 = dst_w_int - (clip->x0 - dst_x_int); + dst_x_int = clip->x0; + } + } + else + { + if (dst_x_int + dst_w_int > clip->x1) + patch.x1 = clip->x1 - dst_x_int; + if (clip->x0 > dst_x_int) + { + patch.x0 = clip->x0 - dst_x_int; + dst_x_int += patch.x0; + } + } + + if (flip_y) + { + if (dst_y_int + dst_h_int > clip->y1) + patch.y1 = clip->y1 - dst_y_int; + if (clip->y0 > dst_y_int) + { + patch.y0 = clip->y0 - dst_y_int; + dst_y_int = clip->y0; + } + } + else + { + if (dst_y_int + dst_h_int > clip->y1) + patch.y1 = clip->y1 - dst_y_int; + if (clip->y0 > dst_y_int) + { + patch.y0 = clip->y0 - dst_y_int; + dst_y_int += patch.y0; + } + } + } + if (patch.x0 >= patch.x1 || patch.y0 >= patch.y1) + return NULL; + fz_try(ctx) { /* Step 1: Calculate the weights for columns and rows */ @@ -1251,15 +1310,15 @@ 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, 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); #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, 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); - output = fz_new_pixmap(ctx, src->colorspace, dst_w_int, dst_h_int); + output = fz_new_pixmap(ctx, src->colorspace, patch.x1 - patch.x0, patch.y1 - patch.y0); } fz_catch(ctx) { @@ -1278,18 +1337,18 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa if (!contrib_cols) { /* Only 1 pixel in the entire image! */ - duplicate_single_pixel(output->samples, src->samples, src->n, dst_w_int, dst_h_int); + duplicate_single_pixel(output->samples, src->samples, src->n, patch.x1-patch.x0, patch.y1-patch.y0); } else { /* Scale the row once, then copy it. */ - scale_single_row(output->samples, src->samples, contrib_cols, src->w, dst_h_int); + scale_single_row(output->samples, src->samples, contrib_cols, src->w, patch.y1-patch.y0); } } else if (!contrib_cols) { /* Only 1 source pixel wide. Scale the col and duplicate. */ - scale_single_col(output->samples, src->samples, contrib_rows, src->h, src->n, dst_w_int, flip_y); + scale_single_col(output->samples, src->samples, contrib_rows, src->h, src->n, patch.x1-patch.x0, flip_y); } else #endif /* SINGLE_PIXEL_SPECIALS */ @@ -1326,7 +1385,7 @@ fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, floa row_scale = scale_row_to_temp4; break; } - max_row = 0; + max_row = contrib_rows->index[contrib_rows->index[0]]; for (row = 0; row < contrib_rows->count; row++) { /* diff --git a/fitz/fitz.h b/fitz/fitz.h index 3971f24c..49db7dc2 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -953,7 +953,7 @@ void fz_invert_pixmap(fz_pixmap *pix); void fz_gamma_pixmap(fz_pixmap *pix, float gamma); unsigned int fz_pixmap_size(fz_pixmap *pix); -fz_pixmap *fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h); +fz_pixmap *fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_bbox *clip); 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); |