summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-01-20 18:33:48 +0000
committerRobin Watts <robin.watts@artifex.com>2012-01-20 20:00:38 +0000
commitd71ea260f6f9250abc2c358e2c4be0581763a7e3 (patch)
tree76982080b538d8aec300c5f342dc73050aa534dc
parent63cca1e65b6c81a6ff29fac46154b8a6ccaaa058 (diff)
downloadmupdf-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.c37
-rw-r--r--draw/draw_scale.c176
-rw-r--r--draw/draw_simple_scale.c105
-rw-r--r--fitz/fitz.h2
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);