diff options
-rw-r--r-- | source/fitz/draw-scale-simple.c | 305 |
1 files changed, 227 insertions, 78 deletions
diff --git a/source/fitz/draw-scale-simple.c b/source/fitz/draw-scale-simple.c index 5d4c5b98..7e304ed3 100644 --- a/source/fitz/draw-scale-simple.c +++ b/source/fitz/draw-scale-simple.c @@ -492,11 +492,11 @@ make_weights(fz_context *ctx, int src_w, float x, float dst_w, fz_scale_filter * } static void -scale_row_to_temp(unsigned char *dst, unsigned char *src, fz_weights *weights) +scale_row_to_temp(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights) { - int *contrib = &weights->index[weights->index[0]]; + const int *contrib = &weights->index[weights->index[0]]; int len, i, j, n; - unsigned char *min; + const unsigned char *min; int tmp[FZ_MAX_COLORS]; int *t = tmp; @@ -552,27 +552,27 @@ scale_row_to_temp(unsigned char *dst, unsigned char *src, fz_weights *weights) #ifdef ARCH_ARM static void -scale_row_to_temp1(unsigned char *dst, unsigned char *src, fz_weights *weights) +scale_row_to_temp1(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights) __attribute__((naked)); static void -scale_row_to_temp2(unsigned char *dst, unsigned char *src, fz_weights *weights) +scale_row_to_temp2(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights) __attribute__((naked)); static void -scale_row_to_temp3(unsigned char *dst, unsigned char *src, fz_weights *weights) +scale_row_to_temp3(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights) __attribute__((naked)); static void -scale_row_to_temp4(unsigned char *dst, unsigned char *src, fz_weights *weights) +scale_row_to_temp4(unsigned char * restrict dst, const unsigned char * restrict src, fconst z_weights * restrict weights) __attribute__((naked)); static void -scale_row_from_temp(unsigned char *dst, unsigned char *src, fz_weights *weights, int width, int row) +scale_row_from_temp(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights, int width, int row) __attribute__((naked)); static void -scale_row_to_temp1(unsigned char *dst, unsigned char *src, fz_weights *weights) +scale_row_to_temp1(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights) { asm volatile( ENTER_ARM @@ -638,7 +638,7 @@ scale_row_to_temp1(unsigned char *dst, unsigned char *src, fz_weights *weights) } static void -scale_row_to_temp2(unsigned char *dst, unsigned char *src, fz_weights *weights) +scale_row_to_temp2(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights) { asm volatile( ENTER_ARM @@ -708,7 +708,7 @@ scale_row_to_temp2(unsigned char *dst, unsigned char *src, fz_weights *weights) } static void -scale_row_to_temp3(unsigned char *dst, unsigned char *src, fz_weights *weights) +scale_row_to_temp3(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights) { asm volatile( ENTER_ARM @@ -793,7 +793,7 @@ scale_row_to_temp3(unsigned char *dst, unsigned char *src, fz_weights *weights) } static void -scale_row_to_temp4(unsigned char *dst, unsigned char *src, fz_weights *weights) +scale_row_to_temp4(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights) { asm volatile( ENTER_ARM @@ -867,7 +867,7 @@ scale_row_to_temp4(unsigned char *dst, unsigned char *src, fz_weights *weights) } static void -scale_row_from_temp(unsigned char *dst, unsigned char *src, fz_weights *weights, int width, int row) +scale_row_from_temp(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights, int width, int row) { asm volatile( ENTER_ARM @@ -948,11 +948,11 @@ scale_row_from_temp(unsigned char *dst, unsigned char *src, fz_weights *weights, #else static void -scale_row_to_temp1(unsigned char *dst, unsigned char *src, fz_weights *weights) +scale_row_to_temp1(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights) { - int *contrib = &weights->index[weights->index[0]]; + const int *contrib = &weights->index[weights->index[0]]; int len, i; - unsigned char *min; + const unsigned char *min; assert(weights->n == 1); if (weights->flip) @@ -987,11 +987,11 @@ scale_row_to_temp1(unsigned char *dst, unsigned char *src, fz_weights *weights) } static void -scale_row_to_temp2(unsigned char *dst, unsigned char *src, fz_weights *weights) +scale_row_to_temp2(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights) { - int *contrib = &weights->index[weights->index[0]]; + const int *contrib = &weights->index[weights->index[0]]; int len, i; - unsigned char *min; + const unsigned char *min; assert(weights->n == 2); if (weights->flip) @@ -1032,11 +1032,11 @@ scale_row_to_temp2(unsigned char *dst, unsigned char *src, fz_weights *weights) } static void -scale_row_to_temp3(unsigned char *dst, unsigned char *src, fz_weights *weights) +scale_row_to_temp3(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights) { - int *contrib = &weights->index[weights->index[0]]; + const int *contrib = &weights->index[weights->index[0]]; int len, i; - unsigned char *min; + const unsigned char *min; assert(weights->n == 3); if (weights->flip) @@ -1085,11 +1085,11 @@ scale_row_to_temp3(unsigned char *dst, unsigned char *src, fz_weights *weights) } static void -scale_row_to_temp4(unsigned char *dst, unsigned char *src, fz_weights *weights) +scale_row_to_temp4(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights) { - int *contrib = &weights->index[weights->index[0]]; + const int *contrib = &weights->index[weights->index[0]]; int len, i; - unsigned char *min; + const unsigned char *min; assert(weights->n == 4); if (weights->flip) @@ -1142,19 +1142,20 @@ scale_row_to_temp4(unsigned char *dst, unsigned char *src, fz_weights *weights) } static void -scale_row_from_temp(unsigned char *dst, unsigned char *src, fz_weights *weights, int width, int row) +scale_row_from_temp(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights, int w, int n, int row) { - int *contrib = &weights->index[weights->index[row]]; + const int *contrib = &weights->index[weights->index[row]]; int len, x; + int width = w * n; contrib++; /* Skip min */ len = *contrib++; for (x=width; x > 0; x--) { - unsigned char *min = src; + const unsigned char *min = src; int val = 128; int len2 = len; - int *contrib2 = contrib; + const int *contrib2 = contrib; while (len2-- > 0) { @@ -1165,22 +1166,56 @@ scale_row_from_temp(unsigned char *dst, unsigned char *src, fz_weights *weights, src++; } } + +static void +scale_row_from_temp_alpha(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights, int w, int n, int row) +{ + const int *contrib = &weights->index[weights->index[row]]; + int len, x; + int width = w * n; + + contrib++; /* Skip min */ + len = *contrib++; + for (x=w; x > 0; x--) + { + int nn; + for (nn = n; nn > 0; nn--) + { + const unsigned char *min = src; + int val = 128; + int len2 = len; + const int *contrib2 = contrib; + + while (len2-- > 0) + { + val += *min * *contrib2++; + min += width; + } + *dst++ = (unsigned char)(val>>8); + src++; + } + *dst++ = 255; + } +} #endif #ifdef SINGLE_PIXEL_SPECIALS static void -duplicate_single_pixel(unsigned char *dst, unsigned char *src, int n, int w, int h, int stride) +duplicate_single_pixel(unsigned char * restrict dst, const unsigned char * restrict src, int n, int forcealpha, int w, int h, int stride) { int i; - w *= n; for (i = n; i > 0; i--) *dst++ = *src++; - for (i = w-n; i > 0; i--) + if (forcealpha) + *dst++ = 255; + n += forcealpha; + for (i = w-1; i > 0; i--) { - *dst = dst[-n]; - dst++; + memcpy(dst, dst-n, n); + dst += n; } + w *= n; dst -= w; h--; while (h--) @@ -1191,15 +1226,16 @@ duplicate_single_pixel(unsigned char *dst, unsigned char *src, int n, int w, int } static void -scale_single_row(unsigned char *dst, int dstride, unsigned char *src, fz_weights *weights, int src_w, int h) +scale_single_row(unsigned char * restrict dst, int dstride, const unsigned char * restrict src, const fz_weights * restrict weights, int src_w, int h, int forcealpha) { - int *contrib = &weights->index[weights->index[0]]; - int min, len, i, j, n; + const int *contrib = &weights->index[weights->index[0]]; + int min, len, i, j, n, nf; int tmp[FZ_MAX_COLORS]; n = weights->n; + nf = n + forcealpha; /* Scale a single row */ - for (j = 0; j < n; j++) + for (j = 0; j < nf; j++) tmp[j] = 128; if (weights->flip) { @@ -1211,18 +1247,20 @@ scale_single_row(unsigned char *dst, int dstride, unsigned char *src, fz_weights min *= n; while (len-- > 0) { + int c = *contrib++; for (j = 0; j < n; j++) - tmp[j] += src[min++] * *contrib; - contrib++; + tmp[j] += src[min++] * c; + if (forcealpha) + tmp[j] += 255 * c; } - for (j = 0; j < n; j++) + for (j = 0; j < nf; j++) { *dst++ = (unsigned char)(tmp[j]>>8); tmp[j] = 128; } - dst -= 2*n; + dst -= 2*nf; } - dst += n + dstride; + dst += nf + dstride; } else { @@ -1233,37 +1271,40 @@ scale_single_row(unsigned char *dst, int dstride, unsigned char *src, fz_weights min *= n; while (len-- > 0) { + int c = *contrib++; for (j = 0; j < n; j++) - tmp[j] += src[min++] * *contrib; - contrib++; + tmp[j] += src[min++] * c; + if (forcealpha) + tmp[j] += 255 * c; } - for (j = 0; j < n; j++) + for (j = 0; j < nf; j++) { *dst++ = (unsigned char)(tmp[j]>>8); tmp[j] = 128; } } - dst += dstride - weights->count * n; + dst += dstride - weights->count * nf; } /* And then duplicate it h times */ - n *= weights->count; + nf *= weights->count; while (--h > 0) { - memcpy(dst, dst-dstride, n); + memcpy(dst, dst-dstride, nf); dst += dstride; } } static void -scale_single_col(unsigned char *dst, int dstride, unsigned char *src, int sstride, fz_weights *weights, int src_w, int n, int w, int flip_y) +scale_single_col(unsigned char * restrict dst, int dstride, const unsigned char * restrict src, int sstride, const fz_weights * restrict weights, int src_w, int n, int w, int forcealpha) { - int *contrib = &weights->index[weights->index[0]]; + const int *contrib = &weights->index[weights->index[0]]; int min, len, i, j; int tmp[FZ_MAX_COLORS]; + int nf = n + forcealpha; - for (j = 0; j < n; j++) + for (j = 0; j < nf; j++) tmp[j] = 128; - if (flip_y) + if (weights->flip) { src_w = (src_w-1)*sstride; for (i=weights->count; i > 0; i--) @@ -1274,23 +1315,25 @@ scale_single_col(unsigned char *dst, int dstride, unsigned char *src, int sstrid min = src_w-min*sstride; while (len-- > 0) { + int c = *contrib++; for (j = 0; j < n; j++) - tmp[j] += src[min+j] * *contrib; + tmp[j] += src[min+j] * c; + if (forcealpha) + tmp[j] += 255 * c; min -= sstride; - contrib++; } - for (j = 0; j < n; j++) + for (j = 0; j < nf; j++) { *dst++ = (unsigned char)(tmp[j]>>8); tmp[j] = 128; } /* And then duplicate it across the row */ - for (j = (w-1)*n; j > 0; j--) + for (j = (w-1)*nf; j > 0; j--) { - *dst = dst[-n]; + *dst = dst[-nf]; dst++; } - dst += dstride - w*n; + dst += dstride - w*nf; } } else @@ -1303,28 +1346,125 @@ scale_single_col(unsigned char *dst, int dstride, unsigned char *src, int sstrid min *= sstride; while (len-- > 0) { + int c = *contrib++; for (j = 0; j < n; j++) - tmp[j] += src[min+j] * *contrib; + tmp[j] += src[min+j] * c; + if (forcealpha) + tmp[j] += 255 * c; min += sstride; - contrib++; } - for (j = 0; j < n; j++) + for (j = 0; j < nf; j++) { *dst++ = (unsigned char)(tmp[j]>>8); tmp[j] = 128; } /* And then duplicate it across the row */ - for (j = (w-1)*n; j > 0; j--) + for (j = (w-1)*nf; j > 0; j--) { - *dst = dst[-n]; + *dst = dst[-nf]; dst++; } - dst += dstride - w*n; + dst += dstride - w*nf; } } } #endif /* SINGLE_PIXEL_SPECIALS */ +static void +get_alpha_edge_values(const fz_weights * restrict rows, int * restrict tp, int * restrict bp) +{ + const int *contrib = &rows->index[rows->index[0]]; + int len, i, t, b; + + /* Calculate the edge alpha values */ + contrib++; /* Skip min */ + len = *contrib++; + t = 0; + while (len--) + t += *contrib++; + for (i=rows->count-2; i > 0; i--) + { + contrib++; /* Skip min */ + len = *contrib++; + contrib += len; + } + b = 0; + if (i == 0) + { + contrib++; + len = *contrib++; + while (len--) + b += *contrib++; + } + if (rows->flip && i == 0) + { + *tp = b; + *bp = t; + } + else + { + *tp = t; + *bp = b; + } +} + +static void +adjust_alpha_edges(fz_pixmap * restrict pix, const fz_weights * restrict rows, const fz_weights * restrict cols) +{ + int t, l, r, b, tl, tr, bl, br, x, y; + unsigned char *dp = pix->samples; + int w = pix->w; + int n = pix->n; + int span = w >= 2 ? (w-1)*n : 0; + int stride = pix->stride; + + get_alpha_edge_values(rows, &t, &b); + get_alpha_edge_values(cols, &l, &r); + + l = (255 * l + 128)>>8; + r = (255 * r + 128)>>8; + tl = (l * t + 128)>>8; + tr = (r * t + 128)>>8; + bl = (l * b + 128)>>8; + br = (r * b + 128)>>8; + t = (255 * t + 128)>>8; + b = (255 * b + 128)>>8; + dp += n-1; + *dp = tl; + dp += n; + for (x = w-2; x > 0; x--) + { + *dp = t; + dp += n; + } + if (x == 0) + { + *dp = tr; + dp += n; + } + dp += stride - w*n; + for (y = pix->h-2; y > 0; y--) + { + dp[span] = r; + *dp = l; + dp += stride; + } + if (y == 0) + { + *dp = bl; + dp += n; + for (x = w-2; x > 0; x--) + { + *dp = b; + dp += n; + } + if (x == 0) + { + *dp = br; + } + } +} + fz_pixmap * fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_irect *clip) { @@ -1341,7 +1481,7 @@ fz_scale_pixmap_cached(fz_context *ctx, const fz_pixmap *src, float x, float y, unsigned char *temp = NULL; 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; + int flip_x, flip_y, forcealpha; fz_rect patch; fz_var(contrib_cols); @@ -1377,6 +1517,10 @@ fz_scale_pixmap_cached(fz_context *ctx, const fz_pixmap *src, float x, float y, h = 1; } + /* If the src has an alpha, we'll make the dst have an alpha automatically. + * We also need to force the dst to have an alpha if x/y/w/h aren't ints. */ + forcealpha = !src->alpha && (x != (float)(int)x || y != (float)(int)y || w != (float)(int)w || h != (float)(int)h); + /* Find the destination bbox, width/height, and sub pixel offset, * allowing for whether we're flipping or not. */ /* The (x,y) position given describes where the top left corner @@ -1507,7 +1651,7 @@ fz_scale_pixmap_cached(fz_context *ctx, const fz_pixmap *src, float x, float y, #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, cache_y); - output = fz_new_pixmap(ctx, src->colorspace, patch.x1 - patch.x0, patch.y1 - patch.y0, src->alpha); + output = fz_new_pixmap(ctx, src->colorspace, patch.x1 - patch.x0, patch.y1 - patch.y0, src->alpha || forcealpha); } fz_catch(ctx) { @@ -1528,26 +1672,27 @@ fz_scale_pixmap_cached(fz_context *ctx, const fz_pixmap *src, float x, float y, if (!contrib_cols) { /* Only 1 pixel in the entire image! */ - duplicate_single_pixel(output->samples, src->samples, src->n, patch.x1-patch.x0, patch.y1-patch.y0, output->stride); + duplicate_single_pixel(output->samples, src->samples, src->n, forcealpha, patch.x1-patch.x0, patch.y1-patch.y0, output->stride); fz_valgrind_pixmap(output); } else { /* Scale the row once, then copy it. */ - scale_single_row(output->samples, output->stride, src->samples, contrib_cols, src->w, patch.y1-patch.y0); + scale_single_row(output->samples, output->stride, src->samples, contrib_cols, src->w, patch.y1-patch.y0, forcealpha); fz_valgrind_pixmap(output); } } else if (!contrib_cols) { /* Only 1 source pixel wide. Scale the col and duplicate. */ - scale_single_col(output->samples, output->stride, src->samples, src->stride, contrib_rows, src->h, src->n, patch.x1-patch.x0, flip_y); + scale_single_col(output->samples, output->stride, src->samples, src->stride, contrib_rows, src->h, src->n, patch.x1-patch.x0, forcealpha); fz_valgrind_pixmap(output); } else #endif /* SINGLE_PIXEL_SPECIALS */ { - void (*row_scale)(unsigned char *dst, unsigned char *src, fz_weights *weights); + void (*row_scale_in)(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights); + void (*row_scale_out)(unsigned char * restrict dst, const unsigned char * restrict src, const fz_weights * restrict weights, int w, int n, int row); temp_span = contrib_cols->count * src->n; temp_rows = contrib_rows->max_len; @@ -1569,21 +1714,22 @@ fz_scale_pixmap_cached(fz_context *ctx, const fz_pixmap *src, float x, float y, switch (src->n) { default: - row_scale = scale_row_to_temp; + row_scale_in = scale_row_to_temp; break; case 1: /* Image mask case or Greyscale case */ - row_scale = scale_row_to_temp1; + row_scale_in = scale_row_to_temp1; break; case 2: /* Greyscale with alpha case */ - row_scale = scale_row_to_temp2; + row_scale_in = scale_row_to_temp2; break; case 3: /* RGB case */ - row_scale = scale_row_to_temp3; + row_scale_in = scale_row_to_temp3; break; case 4: /* RGBA or CMYK case */ - row_scale = scale_row_to_temp4; + row_scale_in = scale_row_to_temp4; break; } + row_scale_out = forcealpha ? scale_row_from_temp_alpha : scale_row_from_temp; max_row = contrib_rows->index[contrib_rows->index[0]]; for (row = 0; row < contrib_rows->count; row++) { @@ -1599,14 +1745,17 @@ fz_scale_pixmap_cached(fz_context *ctx, const fz_pixmap *src, float x, float y, { /* Scale another row */ assert(max_row < src->h); - (*row_scale)(&temp[temp_span*(max_row % temp_rows)], &src->samples[(flip_y ? (src->h-1-max_row): max_row)*src->stride], contrib_cols); + (*row_scale_in)(&temp[temp_span*(max_row % temp_rows)], &src->samples[(flip_y ? (src->h-1-max_row): max_row)*src->stride], contrib_cols); max_row++; } - scale_row_from_temp(&output->samples[row*output->stride], temp, contrib_rows, temp_span, row); + (*row_scale_out)(&output->samples[row*output->stride], temp, contrib_rows, contrib_cols->count, src->n, row); } fz_free(ctx, temp); + if (forcealpha) + adjust_alpha_edges(output, contrib_rows, contrib_cols); + fz_valgrind_pixmap(output); } |