diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2013-06-19 15:29:44 +0200 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2013-06-20 16:45:35 +0200 |
commit | 0a927854a10e1e6b9770a81e2e1d9f3093631757 (patch) | |
tree | 3d65d820d9fdba2d0d394d99c36290c851b78ca0 /source/fitz/pixmap.c | |
parent | 1ae8f19179c5f0f8c6352b3c7855465325d5449a (diff) | |
download | mupdf-0a927854a10e1e6b9770a81e2e1d9f3093631757.tar.xz |
Rearrange source files.
Diffstat (limited to 'source/fitz/pixmap.c')
-rw-r--r-- | source/fitz/pixmap.c | 1062 |
1 files changed, 1062 insertions, 0 deletions
diff --git a/source/fitz/pixmap.c b/source/fitz/pixmap.c new file mode 100644 index 00000000..7391c17e --- /dev/null +++ b/source/fitz/pixmap.c @@ -0,0 +1,1062 @@ +#include "mupdf/fitz.h" + +fz_pixmap * +fz_keep_pixmap(fz_context *ctx, fz_pixmap *pix) +{ + return (fz_pixmap *)fz_keep_storable(ctx, &pix->storable); +} + +void +fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix) +{ + fz_drop_storable(ctx, &pix->storable); +} + +void +fz_free_pixmap_imp(fz_context *ctx, fz_storable *pix_) +{ + fz_pixmap *pix = (fz_pixmap *)pix_; + + if (pix->colorspace) + fz_drop_colorspace(ctx, pix->colorspace); + if (pix->free_samples) + fz_free(ctx, pix->samples); + fz_free(ctx, pix); +} + +fz_pixmap * +fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h, unsigned char *samples) +{ + fz_pixmap *pix; + + if (w < 0 || h < 0) + fz_throw(ctx, FZ_ERROR_GENERIC, "Illegal dimensions for pixmap %d %d", w, h); + + pix = fz_malloc_struct(ctx, fz_pixmap); + FZ_INIT_STORABLE(pix, 1, fz_free_pixmap_imp); + pix->x = 0; + pix->y = 0; + pix->w = w; + pix->h = h; + pix->interpolate = 1; + pix->xres = 96; + pix->yres = 96; + pix->colorspace = NULL; + pix->n = 1; + + if (colorspace) + { + pix->colorspace = fz_keep_colorspace(ctx, colorspace); + pix->n = 1 + colorspace->n; + } + + pix->samples = samples; + if (samples) + { + pix->free_samples = 0; + } + else + { + fz_try(ctx) + { + if (pix->w + pix->n - 1 > INT_MAX / pix->n) + fz_throw(ctx, FZ_ERROR_GENERIC, "overly wide image"); + pix->samples = fz_malloc_array(ctx, pix->h, pix->w * pix->n); + } + fz_catch(ctx) + { + if (colorspace) + fz_drop_colorspace(ctx, colorspace); + fz_free(ctx, pix); + fz_rethrow(ctx); + } + pix->free_samples = 1; + } + + return pix; +} + +fz_pixmap * +fz_new_pixmap(fz_context *ctx, fz_colorspace *colorspace, int w, int h) +{ + return fz_new_pixmap_with_data(ctx, colorspace, w, h, NULL); +} + +fz_pixmap * +fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, const fz_irect *r) +{ + fz_pixmap *pixmap; + pixmap = fz_new_pixmap(ctx, colorspace, r->x1 - r->x0, r->y1 - r->y0); + pixmap->x = r->x0; + pixmap->y = r->y0; + return pixmap; +} + +fz_pixmap * +fz_new_pixmap_with_bbox_and_data(fz_context *ctx, fz_colorspace *colorspace, const fz_irect *r, unsigned char *samples) +{ + fz_pixmap *pixmap = fz_new_pixmap_with_data(ctx, colorspace, r->x1 - r->x0, r->y1 - r->y0, samples); + pixmap->x = r->x0; + pixmap->y = r->y0; + return pixmap; +} + +fz_irect * +fz_pixmap_bbox(fz_context *ctx, fz_pixmap *pix, fz_irect *bbox) +{ + bbox->x0 = pix->x; + bbox->y0 = pix->y; + bbox->x1 = pix->x + pix->w; + bbox->y1 = pix->y + pix->h; + return bbox; +} + +fz_irect * +fz_pixmap_bbox_no_ctx(fz_pixmap *pix, fz_irect *bbox) +{ + bbox->x0 = pix->x; + bbox->y0 = pix->y; + bbox->x1 = pix->x + pix->w; + bbox->y1 = pix->y + pix->h; + return bbox; +} + +int +fz_pixmap_width(fz_context *ctx, fz_pixmap *pix) +{ + return pix->w; +} + +int +fz_pixmap_height(fz_context *ctx, fz_pixmap *pix) +{ + return pix->h; +} + +void +fz_clear_pixmap(fz_context *ctx, fz_pixmap *pix) +{ + memset(pix->samples, 0, (unsigned int)(pix->w * pix->h * pix->n)); +} + +void +fz_clear_pixmap_with_value(fz_context *ctx, fz_pixmap *pix, int value) +{ + if (value == 255) + { + memset(pix->samples, 255, (unsigned int)(pix->w * pix->h * pix->n)); + } + else + { + int k, x, y; + unsigned char *s = pix->samples; + for (y = 0; y < pix->h; y++) + { + for (x = 0; x < pix->w; x++) + { + for (k = 0; k < pix->n - 1; k++) + *s++ = value; + *s++ = 255; + } + } + } +} + +void +fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, const fz_irect *b) +{ + const unsigned char *srcp; + unsigned char *destp; + int x, y, w, destspan, srcspan; + fz_irect local_b, bb; + + local_b = *b; + fz_intersect_irect(&local_b, fz_pixmap_bbox(ctx, dest, &bb)); + fz_intersect_irect(&local_b, fz_pixmap_bbox(ctx, src, &bb)); + w = local_b.x1 - local_b.x0; + y = local_b.y1 - local_b.y0; + if (w <= 0 || y <= 0) + return; + + srcspan = src->w * src->n; + srcp = src->samples + (unsigned int)(srcspan * (local_b.y0 - src->y) + src->n * (local_b.x0 - src->x)); + destspan = dest->w * dest->n; + destp = dest->samples + (unsigned int)(destspan * (local_b.y0 - dest->y) + dest->n * (local_b.x0 - dest->x)); + + if (src->n == dest->n) + { + w *= src->n; + do + { + memcpy(destp, srcp, w); + srcp += srcspan; + destp += destspan; + } + while (--y); + } + else if (src->n == 2 && dest->n == 4) + { + /* Copy, and convert from grey+alpha to rgb+alpha */ + srcspan -= w*2; + destspan -= w*4; + do + { + for (x = w; x > 0; x--) + { + unsigned char v = *srcp++; + unsigned char a = *srcp++; + *destp++ = v; + *destp++ = v; + *destp++ = v; + *destp++ = a; + } + srcp += srcspan; + destp += destspan; + } + while (--y); + } + else if (src->n == 4 && dest->n == 2) + { + /* Copy, and convert from rgb+alpha to grey+alpha */ + srcspan -= w*4; + destspan -= w*2; + do + { + for (x = w; x > 0; x--) + { + int v; + v = *srcp++; + v += *srcp++; + v += *srcp++; + *destp++ = (unsigned char)((v+1)/3); + *destp++ = *srcp++; + } + srcp += srcspan; + destp += destspan; + } + while (--y); + } + else + { + /* FIXME: Crap conversion */ + int z; + int sn = src->n-1; + int dn = dest->n-1; + + srcspan -= w*src->n; + destspan -= w*dest->n; + do + { + for (x = w; x > 0; x--) + { + int v = 0; + for (z = sn; z > 0; z--) + v += *srcp++; + v = (v * dn + (sn>>1)) / sn; + for (z = dn; z > 0; z--) + *destp++ = (unsigned char)v; + *destp++ = *srcp++; + } + srcp += srcspan; + destp += destspan; + } + while (--y); + } +} + +void +fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *dest, int value, const fz_irect *b) +{ + unsigned char *destp; + int x, y, w, k, destspan; + fz_irect bb; + fz_irect local_b = *b; + + fz_intersect_irect(&local_b, fz_pixmap_bbox(ctx, dest, &bb)); + w = local_b.x1 - local_b.x0; + y = local_b.y1 - local_b.y0; + if (w <= 0 || y <= 0) + return; + + destspan = dest->w * dest->n; + destp = dest->samples + (unsigned int)(destspan * (local_b.y0 - dest->y) + dest->n * (local_b.x0 - dest->x)); + if (value == 255) + do + { + memset(destp, 255, (unsigned int)(w * dest->n)); + destp += destspan; + } + while (--y); + else + do + { + unsigned char *s = destp; + for (x = 0; x < w; x++) + { + for (k = 0; k < dest->n - 1; k++) + *s++ = value; + *s++ = 255; + } + destp += destspan; + } + while (--y); +} + +void +fz_premultiply_pixmap(fz_context *ctx, fz_pixmap *pix) +{ + unsigned char *s = pix->samples; + unsigned char a; + int k, x, y; + + for (y = 0; y < pix->h; y++) + { + for (x = 0; x < pix->w; x++) + { + a = s[pix->n - 1]; + for (k = 0; k < pix->n - 1; k++) + s[k] = fz_mul255(s[k], a); + s += pix->n; + } + } +} + +void +fz_unmultiply_pixmap(fz_context *ctx, fz_pixmap *pix) +{ + unsigned char *s = pix->samples; + int a, inva; + int k, x, y; + + for (y = 0; y < pix->h; y++) + { + for (x = 0; x < pix->w; x++) + { + a = s[pix->n - 1]; + inva = a ? 255 * 256 / a : 0; + for (k = 0; k < pix->n - 1; k++) + s[k] = (s[k] * inva) >> 8; + s += pix->n; + } + } +} + +fz_pixmap * +fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray, int luminosity) +{ + fz_pixmap *alpha; + unsigned char *sp, *dp; + int len; + fz_irect bbox; + + assert(gray->n == 2); + + alpha = fz_new_pixmap_with_bbox(ctx, NULL, fz_pixmap_bbox(ctx, gray, &bbox)); + dp = alpha->samples; + sp = gray->samples; + if (!luminosity) + sp ++; + + len = gray->w * gray->h; + while (len--) + { + *dp++ = sp[0]; + sp += 2; + } + + return alpha; +} + +void +fz_invert_pixmap(fz_context *ctx, fz_pixmap *pix) +{ + unsigned char *s = pix->samples; + int k, x, y; + + for (y = 0; y < pix->h; y++) + { + for (x = 0; x < pix->w; x++) + { + for (k = 0; k < pix->n - 1; k++) + s[k] = 255 - s[k]; + s += pix->n; + } + } +} + +void fz_invert_pixmap_rect(fz_pixmap *image, const fz_irect *rect) +{ + unsigned char *p; + int x, y, n; + + int x0 = fz_clampi(rect->x0 - image->x, 0, image->w - 1); + int x1 = fz_clampi(rect->x1 - image->x, 0, image->w - 1); + int y0 = fz_clampi(rect->y0 - image->y, 0, image->h - 1); + int y1 = fz_clampi(rect->y1 - image->y, 0, image->h - 1); + + for (y = y0; y < y1; y++) + { + p = image->samples + (unsigned int)((y * image->w + x0) * image->n); + for (x = x0; x < x1; x++) + { + for (n = image->n; n > 1; n--, p++) + *p = 255 - *p; + p++; + } + } +} + +void +fz_gamma_pixmap(fz_context *ctx, fz_pixmap *pix, float gamma) +{ + unsigned char gamma_map[256]; + unsigned char *s = pix->samples; + int k, x, y; + + for (k = 0; k < 256; k++) + gamma_map[k] = pow(k / 255.0f, gamma) * 255; + + for (y = 0; y < pix->h; y++) + { + for (x = 0; x < pix->w; x++) + { + for (k = 0; k < pix->n - 1; k++) + s[k] = gamma_map[s[k]]; + s += pix->n; + } + } +} + +/* + * Write pixmap to PNM file (without alpha channel) + */ + +void +fz_write_pnm(fz_context *ctx, fz_pixmap *pixmap, char *filename) +{ + FILE *fp; + unsigned char *p; + int len; + + if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4) + fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be grayscale or rgb to write as pnm"); + + fp = fopen(filename, "wb"); + if (!fp) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); + + if (pixmap->n == 1 || pixmap->n == 2) + fprintf(fp, "P5\n"); + if (pixmap->n == 4) + fprintf(fp, "P6\n"); + fprintf(fp, "%d %d\n", pixmap->w, pixmap->h); + fprintf(fp, "255\n"); + + len = pixmap->w * pixmap->h; + p = pixmap->samples; + + switch (pixmap->n) + { + case 1: + fwrite(p, 1, len, fp); + break; + case 2: + while (len--) + { + putc(p[0], fp); + p += 2; + } + break; + case 4: + while (len--) + { + putc(p[0], fp); + putc(p[1], fp); + putc(p[2], fp); + p += 4; + } + } + + fclose(fp); +} + +/* + * Write pixmap to PAM file (with or without alpha channel) + */ + +void +fz_write_pam(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha) +{ + unsigned char *sp; + int y, w, k; + FILE *fp; + + int sn = pixmap->n; + int dn = pixmap->n; + if (!savealpha && dn > 1) + dn--; + + fp = fopen(filename, "wb"); + if (!fp) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); + + fprintf(fp, "P7\n"); + fprintf(fp, "WIDTH %d\n", pixmap->w); + fprintf(fp, "HEIGHT %d\n", pixmap->h); + fprintf(fp, "DEPTH %d\n", dn); + fprintf(fp, "MAXVAL 255\n"); + if (pixmap->colorspace) + fprintf(fp, "# COLORSPACE %s\n", pixmap->colorspace->name); + switch (dn) + { + case 1: fprintf(fp, "TUPLTYPE GRAYSCALE\n"); break; + case 2: if (sn == 2) fprintf(fp, "TUPLTYPE GRAYSCALE_ALPHA\n"); break; + case 3: if (sn == 4) fprintf(fp, "TUPLTYPE RGB\n"); break; + case 4: if (sn == 4) fprintf(fp, "TUPLTYPE RGB_ALPHA\n"); break; + } + fprintf(fp, "ENDHDR\n"); + + sp = pixmap->samples; + for (y = 0; y < pixmap->h; y++) + { + w = pixmap->w; + while (w--) + { + for (k = 0; k < dn; k++) + putc(sp[k], fp); + sp += sn; + } + } + + fclose(fp); +} + +/* + * Write pixmap to PNG file (with or without alpha channel) + */ + +#include <zlib.h> + +static inline void big32(unsigned char *buf, unsigned int v) +{ + buf[0] = (v >> 24) & 0xff; + buf[1] = (v >> 16) & 0xff; + buf[2] = (v >> 8) & 0xff; + buf[3] = (v) & 0xff; +} + +static void putchunk(char *tag, unsigned char *data, int size, fz_output *out) +{ + unsigned int sum; + fz_write_int32be(out, size); + fz_write(out, tag, 4); + fz_write(out, data, size); + sum = crc32(0, NULL, 0); + sum = crc32(sum, (unsigned char*)tag, 4); + sum = crc32(sum, data, size); + fz_write_int32be(out, sum); +} + +void +fz_write_png(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha) +{ + FILE *fp = fopen(filename, "wb"); + fz_output *out = NULL; + + if (!fp) + { + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); + } + + fz_var(out); + + fz_try(ctx) + { + out = fz_new_output_with_file(ctx, fp); + fz_output_png(out, pixmap, savealpha); + } + fz_always(ctx) + { + fz_close_output(out); + fclose(fp); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } +} + +void +fz_output_png(fz_output *out, const fz_pixmap *pixmap, int savealpha) +{ + static const unsigned char pngsig[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; + unsigned char head[13]; + unsigned char *udata = NULL; + unsigned char *cdata = NULL; + unsigned char *sp, *dp; + uLong usize, csize; + int y, x, k, sn, dn; + int color; + int err; + fz_context *ctx; + + if (!out || !pixmap) + return; + + ctx = out->ctx; + + fz_var(udata); + fz_var(cdata); + + if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4) + fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be grayscale or rgb to write as png"); + + sn = pixmap->n; + dn = pixmap->n; + if (!savealpha && dn > 1) + dn--; + + switch (dn) + { + default: + case 1: color = 0; break; + case 2: color = 4; break; + case 3: color = 2; break; + case 4: color = 6; break; + } + + usize = (pixmap->w * dn + 1) * pixmap->h; + csize = compressBound(usize); + fz_try(ctx) + { + udata = fz_malloc(ctx, usize); + cdata = fz_malloc(ctx, csize); + } + fz_catch(ctx) + { + fz_free(ctx, udata); + fz_rethrow(ctx); + } + + sp = pixmap->samples; + dp = udata; + for (y = 0; y < pixmap->h; y++) + { + *dp++ = 1; /* sub prediction filter */ + for (x = 0; x < pixmap->w; x++) + { + for (k = 0; k < dn; k++) + { + if (x == 0) + dp[k] = sp[k]; + else + dp[k] = sp[k] - sp[k-sn]; + } + sp += sn; + dp += dn; + } + } + + err = compress(cdata, &csize, udata, usize); + if (err != Z_OK) + { + fz_free(ctx, udata); + fz_free(ctx, cdata); + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot compress image data"); + } + + big32(head+0, pixmap->w); + big32(head+4, pixmap->h); + head[8] = 8; /* depth */ + head[9] = color; + head[10] = 0; /* compression */ + head[11] = 0; /* filter */ + head[12] = 0; /* interlace */ + + fz_write(out, pngsig, 8); + putchunk("IHDR", head, 13, out); + putchunk("IDAT", cdata, csize, out); + putchunk("IEND", head, 0, out); + + fz_free(ctx, udata); + fz_free(ctx, cdata); +} + +fz_buffer * +fz_image_as_png(fz_context *ctx, fz_image *image, int w, int h) +{ + fz_pixmap *pix = fz_image_get_pixmap(ctx, image, image->w, image->h); + fz_buffer *buf = NULL; + fz_output *out; + + fz_var(buf); + fz_var(out); + + fz_try(ctx) + { + if (pix->colorspace != fz_device_gray(ctx) || pix->colorspace != fz_device_rgb(ctx)) + { + fz_pixmap *pix2 = fz_new_pixmap(ctx, fz_device_rgb(ctx), pix->w, pix->h); + fz_convert_pixmap(ctx, pix2, pix); + fz_drop_pixmap(ctx, pix); + pix = pix2; + } + buf = fz_new_buffer(ctx, 1024); + out = fz_new_output_with_buffer(ctx, buf); + fz_output_png(out, pix, 0); + } + fz_always(ctx) + { + fz_close_output(out); + fz_drop_pixmap(ctx, pix); + } + fz_catch(ctx) + { + fz_drop_buffer(ctx, buf); + fz_rethrow(ctx); + } + return buf; +} + +unsigned int +fz_pixmap_size(fz_context *ctx, fz_pixmap * pix) +{ + if (pix == NULL) + return 0; + return sizeof(*pix) + pix->n * pix->w * pix->h; +} + +#ifdef ARCH_ARM +static void +fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor, + int n, int fwd, int back, int back2, int fwd2, + int divX, int back4, int fwd4, int fwd3, + int divY, int back5, int divXY) +__attribute__((naked)); + +static void +fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor, + int n, int fwd, int back, int back2, int fwd2, + int divX, int back4, int fwd4, int fwd3, + int divY, int back5, int divXY) +{ + asm volatile( + ENTER_ARM + "stmfd r13!,{r1,r4-r11,r14} \n" + "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n" + "@ r0 = src = ptr \n" + "@ r1 = w \n" + "@ r2 = h \n" + "@ r3 = f \n" + "mov r9, r0 @ r9 = dst = ptr \n" + "ldr r6, [r13,#4*12] @ r6 = fwd \n" + "ldr r7, [r13,#4*13] @ r7 = back \n" + "subs r2, r2, r3 @ r2 = h -= f \n" + "blt 11f @ Skip if less than a full row \n" + "1: @ for (y = h; y > 0; y--) { \n" + "ldr r1, [r13] @ r1 = w \n" + "subs r1, r1, r3 @ r1 = w -= f \n" + "blt 6f @ Skip if less than a full col \n" + "ldr r4, [r13,#4*10] @ r4 = factor \n" + "ldr r8, [r13,#4*14] @ r8 = back2 \n" + "ldr r12,[r13,#4*15] @ r12= fwd2 \n" + "2: @ for (x = w; x > 0; x--) { \n" + "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n" + "3: @ \n" + "mov r14,#0 @ r14= v = 0 \n" + "sub r5, r5, r3, LSL #8 @ for (xx = f; xx > 0; x--) { \n" + "4: @ \n" + "add r5, r5, r3, LSL #16 @ for (yy = f; yy > 0; y--) { \n" + "5: @ \n" + "ldrb r11,[r0], r6 @ r11= *src src += fwd \n" + "subs r5, r5, #1<<16 @ xx-- \n" + "add r14,r14,r11 @ v += r11 \n" + "bgt 5b @ } \n" + "sub r0, r0, r7 @ src -= back \n" + "adds r5, r5, #1<<8 @ yy-- \n" + "blt 4b @ } \n" + "mov r14,r14,LSR r4 @ r14 = v >>= factor \n" + "strb r14,[r9], #1 @ *d++ = r14 \n" + "sub r0, r0, r8 @ s -= back2 \n" + "subs r5, r5, #1 @ n-- \n" + "bgt 3b @ } \n" + "add r0, r0, r12 @ s += fwd2 \n" + "subs r1, r1, r3 @ x -= f \n" + "bge 2b @ } \n" + "6: @ Less than a full column left \n" + "adds r1, r1, r3 @ x += f \n" + "beq 11f @ if (x == 0) next row \n" + "@ r0 = src \n" + "@ r1 = x \n" + "@ r2 = y \n" + "@ r3 = f \n" + "@ r4 = factor \n" + "@ r6 = fwd \n" + "@ r7 = back \n" + "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n" + "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n" + "ldr r4, [r13,#4*16] @ r4 = divX \n" + "ldr r8, [r13,#4*17] @ r8 = back4 \n" + "ldr r12,[r13,#4*18] @ r12= fwd4 \n" + "8: @ \n" + "mov r14,#0 @ r14= v = 0 \n" + "sub r5, r5, r1, LSL #8 @ for (xx = x; xx > 0; x--) { \n" + "9: @ \n" + "add r5, r5, r3, LSL #16 @ for (yy = f; yy > 0; y--) { \n" + "10: @ \n" + "ldrb r11,[r0], r6 @ r11= *src src += fwd \n" + "subs r5, r5, #1<<16 @ xx-- \n" + "add r14,r14,r11 @ v += r11 \n" + "bgt 10b @ } \n" + "sub r0, r0, r7 @ src -= back \n" + "adds r5, r5, #1<<8 @ yy-- \n" + "blt 9b @ } \n" + "mul r14,r4, r14 @ r14= v *= divX \n" + "mov r14,r14,LSR #16 @ r14= v >>= 16 \n" + "strb r14,[r9], #1 @ *d++ = r14 \n" + "sub r0, r0, r8 @ s -= back4 \n" + "subs r5, r5, #1 @ n-- \n" + "bgt 8b @ } \n" + "add r0, r0, r12 @ s += fwd4 \n" + "11: @ \n" + "ldr r14,[r13,#4*19] @ r14 = fwd3 \n" + "subs r2, r2, r3 @ h -= f \n" + "add r0, r0, r14 @ s += fwd3 \n" + "bge 1b @ } \n" + "adds r2, r2, r3 @ h += f \n" + "beq 21f @ if no stray row, end \n" + "@ So doing one last (partial) row \n" + "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n" + "@ r0 = src = ptr \n" + "@ r1 = w \n" + "@ r2 = h \n" + "@ r3 = f \n" + "@ r4 = factor \n" + "@ r5 = n \n" + "@ r6 = fwd \n" + "12: @ for (y = h; y > 0; y--) { \n" + "ldr r1, [r13] @ r1 = w \n" + "ldr r7, [r13,#4*21] @ r7 = back5 \n" + "ldr r8, [r13,#4*14] @ r8 = back2 \n" + "subs r1, r1, r3 @ r1 = w -= f \n" + "blt 17f @ Skip if less than a full col \n" + "ldr r4, [r13,#4*20] @ r4 = divY \n" + "ldr r12,[r13,#4*15] @ r12= fwd2 \n" + "13: @ for (x = w; x > 0; x--) { \n" + "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n" + "14: @ \n" + "mov r14,#0 @ r14= v = 0 \n" + "sub r5, r5, r3, LSL #8 @ for (xx = f; xx > 0; x--) { \n" + "15: @ \n" + "add r5, r5, r2, LSL #16 @ for (yy = y; yy > 0; y--) { \n" + "16: @ \n" + "ldrb r11,[r0], r6 @ r11= *src src += fwd \n" + "subs r5, r5, #1<<16 @ xx-- \n" + "add r14,r14,r11 @ v += r11 \n" + "bgt 16b @ } \n" + "sub r0, r0, r7 @ src -= back5 \n" + "adds r5, r5, #1<<8 @ yy-- \n" + "blt 15b @ } \n" + "mul r14,r4, r14 @ r14 = x *= divY \n" + "mov r14,r14,LSR #16 @ r14 = v >>= 16 \n" + "strb r14,[r9], #1 @ *d++ = r14 \n" + "sub r0, r0, r8 @ s -= back2 \n" + "subs r5, r5, #1 @ n-- \n" + "bgt 14b @ } \n" + "add r0, r0, r12 @ s += fwd2 \n" + "subs r1, r1, r3 @ x -= f \n" + "bge 13b @ } \n" + "17: @ Less than a full column left \n" + "adds r1, r1, r3 @ x += f \n" + "beq 21f @ if (x == 0) end \n" + "@ r0 = src \n" + "@ r1 = x \n" + "@ r2 = y \n" + "@ r3 = f \n" + "@ r4 = factor \n" + "@ r6 = fwd \n" + "@ r7 = back5 \n" + "@ r8 = back2 \n" + "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n" + "ldr r4, [r13,#4*22] @ r4 = divXY \n" + "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n" + "18: @ \n" + "mov r14,#0 @ r14= v = 0 \n" + "sub r5, r5, r1, LSL #8 @ for (xx = x; xx > 0; x--) { \n" + "19: @ \n" + "add r5, r5, r2, LSL #16 @ for (yy = y; yy > 0; y--) { \n" + "20: @ \n" + "ldrb r11,[r0],r6 @ r11= *src src += fwd \n" + "subs r5, r5, #1<<16 @ xx-- \n" + "add r14,r14,r11 @ v += r11 \n" + "bgt 20b @ } \n" + "sub r0, r0, r7 @ src -= back5 \n" + "adds r5, r5, #1<<8 @ yy-- \n" + "blt 19b @ } \n" + "mul r14,r4, r14 @ r14= v *= divX \n" + "mov r14,r14,LSR #16 @ r14= v >>= 16 \n" + "strb r14,[r9], #1 @ *d++ = r14 \n" + "sub r0, r0, r8 @ s -= back2 \n" + "subs r5, r5, #1 @ n-- \n" + "bgt 18b @ } \n" + "21: @ \n" + "ldmfd r13!,{r1,r4-r11,PC} @ pop, return to thumb \n" + ENTER_THUMB + ); +} + +#endif + +void +fz_subsample_pixmap(fz_context *ctx, fz_pixmap *tile, int factor) +{ + int dst_w, dst_h, w, h, fwd, fwd2, fwd3, back, back2, x, y, n, xx, yy, nn, f; + unsigned char *s, *d; + + if (!tile) + return; + s = d = tile->samples; + f = 1<<factor; + w = tile->w; + h = tile->h; + n = tile->n; + dst_w = (w + f-1)>>factor; + dst_h = (h + f-1)>>factor; + fwd = w*n; + back = f*fwd-n; + back2 = f*n-1; + fwd2 = (f-1)*n; + fwd3 = (f-1)*fwd; + factor *= 2; +#ifdef ARCH_ARM + { + int strayX = w%f; + int divX = (strayX ? 65536/(strayX*f) : 0); + int fwd4 = (strayX-1) * n; + int back4 = strayX*n-1; + int strayY = h%f; + int divY = (strayY ? 65536/(strayY*f) : 0); + int back5 = fwd * strayY - n; + int divXY = (strayY*strayX ? 65536/(strayX*strayY) : 0); + fz_subsample_pixmap_ARM(s, w, h, f, factor, n, fwd, back, + back2, fwd2, divX, back4, fwd4, fwd3, + divY, back5, divXY); + } +#else + for (y = h - f; y >= 0; y -= f) + { + for (x = w - f; x >= 0; x -= f) + { + for (nn = n; nn > 0; nn--) + { + int v = 0; + for (xx = f; xx > 0; xx--) + { + for (yy = f; yy > 0; yy--) + { + v += *s; + s += fwd; + } + s -= back; + } + *d++ = v >> factor; + s -= back2; + } + s += fwd2; + } + /* Do any strays */ + x += f; + if (x > 0) + { + int div = x * f; + int fwd4 = (x-1) * n; + int back4 = x*n-1; + for (nn = n; nn > 0; nn--) + { + int v = 0; + for (xx = x; xx > 0; xx--) + { + for (yy = f; yy > 0; yy--) + { + v += *s; + s += fwd; + } + s -= back; + } + *d++ = v / div; + s -= back4; + } + s += fwd4; + } + s += fwd3; + } + /* Do any stray line */ + y += f; + if (y > 0) + { + int div = y * f; + int back5 = fwd * y - n; + for (x = w - f; x >= 0; x -= f) + { + for (nn = n; nn > 0; nn--) + { + int v = 0; + for (xx = f; xx > 0; xx--) + { + for (yy = y; yy > 0; yy--) + { + v += *s; + s += fwd; + } + s -= back5; + } + *d++ = v / div; + s -= back2; + } + s += fwd2; + } + /* Do any stray at the end of the stray line */ + x += f; + if (x > 0) + { + div = x * y; + for (nn = n; nn > 0; nn--) + { + int v = 0; + for (xx = x; xx > 0; xx--) + { + for (yy = y; yy > 0; yy--) + { + v += *s; + s += fwd; + } + s -= back5; + } + *d++ = v / div; + s -= back2; + } + } + } +#endif + tile->w = dst_w; + tile->h = dst_h; + tile->samples = fz_resize_array(ctx, tile->samples, dst_w * n, dst_h); +} + +void +fz_pixmap_set_resolution(fz_pixmap *pix, int res) +{ + pix->xres = res; + pix->yres = res; +} + +void +fz_md5_pixmap(fz_pixmap *pix, unsigned char digest[16]) +{ + fz_md5 md5; + + fz_md5_init(&md5); + if (pix) + fz_md5_update(&md5, pix->samples, pix->w * pix->h * pix->n); + fz_md5_final(&md5, digest); +} |