summaryrefslogtreecommitdiff
path: root/fitzdraw/imagescale.c
diff options
context:
space:
mode:
Diffstat (limited to 'fitzdraw/imagescale.c')
-rw-r--r--fitzdraw/imagescale.c358
1 files changed, 358 insertions, 0 deletions
diff --git a/fitzdraw/imagescale.c b/fitzdraw/imagescale.c
new file mode 100644
index 00000000..f25d4d5a
--- /dev/null
+++ b/fitzdraw/imagescale.c
@@ -0,0 +1,358 @@
+#include "fitz-base.h"
+#include "fitz-world.h"
+#include "fitz-draw.h"
+
+typedef unsigned char byte;
+
+static inline void srown(byte * restrict src, byte * restrict dst, int w, int denom, int n)
+{
+ int invdenom = (1<<16) / denom;
+ int x, left, k;
+ unsigned sum[FZ_MAXCOLORS];
+
+ left = 0;
+ for (k = 0; k < n; k++)
+ sum[k] = 0;
+
+ for (x = 0; x < w; x++)
+ {
+ for (k = 0; k < n; k++)
+ sum[k] += src[x * n + k];
+ if (++left == denom)
+ {
+ left = 0;
+ for (k = 0; k < n; k++)
+ {
+ dst[k] = (sum[k] * invdenom + (1<<15)) >> 16;
+ sum[k] = 0;
+ }
+ dst += n;
+ }
+ }
+
+ /* left overs */
+ if (left)
+ for (k = 0; k < n; k++)
+ dst[k] = sum[k] / left;
+}
+
+/* special-case common 1-5 components - the compiler optimizes this */
+static inline void srowc(byte * restrict src, byte * restrict dst, int w, int denom, int n)
+{
+ int invdenom = (1<<16) / denom;
+ int x, left;
+ unsigned sum1 = 0;
+ unsigned sum2 = 0;
+ unsigned sum3 = 0;
+ unsigned sum4 = 0;
+ unsigned sum5 = 0;
+
+ assert(n <= 5);
+
+ left = 0;
+
+ for (x = 0; x < w; x++)
+ {
+ sum1 += src[x * n + 0];
+ /* the compiler eliminates these if-tests */
+ if (n >= 2)
+ sum2 += src[x * n + 1];
+ if (n >= 3)
+ sum3 += src[x * n + 2];
+ if (n >= 4)
+ sum4 += src[x * n + 3];
+ if (n >= 5)
+ sum5 += src[x * n + 4];
+
+ if (++left == denom)
+ {
+ left = 0;
+
+ dst[0] = (sum1 * invdenom + (1<<15)) >> 16;
+ sum1 = 0;
+ if (n >= 2) {
+ dst[1] = (sum2 * invdenom + (1<<15)) >> 16;
+ sum2 = 0;
+ }
+ if (n >= 3) {
+ dst[2] = (sum3 * invdenom + (1<<15)) >> 16;
+ sum3 = 0;
+ }
+ if (n >= 4) {
+ dst[3] = (sum4 * invdenom + (1<<15)) >> 16;
+ sum4 = 0;
+ }
+ if (n >= 5) {
+ dst[4] = (sum5 * invdenom + (1<<15)) >> 16;
+ sum5 = 0;
+ }
+
+
+ dst += n;
+ }
+ }
+
+ /* left overs */
+ if (left) {
+ dst[0] = sum1 / left;
+ if (n >=2)
+ dst[1] = sum2 / left;
+ if (n >=3)
+ dst[2] = sum3 / left;
+ if (n >=4)
+ dst[3] = sum4 / left;
+ if (n >=5)
+ dst[4] = sum5 / left;
+ }
+}
+
+static void srow1(byte *src, byte *dst, int w, int denom)
+{
+ srowc(src, dst, w, denom, 1);
+}
+
+static void srow2(byte *src, byte *dst, int w, int denom)
+{
+ srowc(src, dst, w, denom, 2);
+}
+
+static void srow4(byte *src, byte *dst, int w, int denom)
+{
+ srowc(src, dst, w, denom, 4);
+}
+
+static void srow5(byte *src, byte *dst, int w, int denom)
+{
+ srowc(src, dst, w, denom, 5);
+}
+
+static inline void scoln(byte * restrict src, byte * restrict dst, int w, int denom, int n)
+{
+ int invdenom = (1<<16) / denom;
+ int x, y, k;
+ byte *s;
+ int sum[FZ_MAXCOLORS];
+
+ for (x = 0; x < w; x++)
+ {
+ s = src + (x * n);
+ for (k = 0; k < n; k++)
+ sum[k] = 0;
+ for (y = 0; y < denom; y++)
+ for (k = 0; k < n; k++)
+ sum[k] += s[y * w * n + k];
+ for (k = 0; k < n; k++)
+ dst[k] = (sum[k] * invdenom + (1<<15)) >> 16;
+ dst += n;
+ }
+}
+
+static void scol1(byte *src, byte *dst, int w, int denom)
+{
+ scoln(src, dst, w, denom, 1);
+}
+
+static void scol2(byte *src, byte *dst, int w, int denom)
+{
+ scoln(src, dst, w, denom, 2);
+}
+
+static void scol4(byte *src, byte *dst, int w, int denom)
+{
+ scoln(src, dst, w, denom, 4);
+}
+
+static void scol5(byte *src, byte *dst, int w, int denom)
+{
+ scoln(src, dst, w, denom, 5);
+}
+
+void (*fz_srown)(byte *src, byte *dst, int w, int denom, int n) = srown;
+void (*fz_srow1)(byte *src, byte *dst, int w, int denom) = srow1;
+void (*fz_srow2)(byte *src, byte *dst, int w, int denom) = srow2;
+void (*fz_srow4)(byte *src, byte *dst, int w, int denom) = srow4;
+void (*fz_srow5)(byte *src, byte *dst, int w, int denom) = srow5;
+
+void (*fz_scoln)(byte *src, byte *dst, int w, int denom, int n) = scoln;
+void (*fz_scol1)(byte *src, byte *dst, int w, int denom) = scol1;
+void (*fz_scol2)(byte *src, byte *dst, int w, int denom) = scol2;
+void (*fz_scol4)(byte *src, byte *dst, int w, int denom) = scol4;
+void (*fz_scol5)(byte *src, byte *dst, int w, int denom) = scol5;
+
+fz_error *
+fz_newscaledpixmap(fz_pixmap **dstp, int w, int h, int n, int xdenom, int ydenom)
+{
+ int ow = (w + xdenom - 1) / xdenom;
+ int oh = (h + ydenom - 1) / ydenom;
+ return fz_newpixmap(dstp, 0, 0, ow, oh, n);
+}
+
+/* TODO: refactor */
+fz_error *
+fz_scalepixmaptile(fz_pixmap *dst, int xoffs, int yoffs, fz_pixmap *src, int xdenom, int ydenom)
+{
+ unsigned char *buf;
+ unsigned char *dstsamples;
+ int y, iy, oy;
+ int ow, oh, n;
+ int remaining;
+
+ void (*srowx)(byte *src, byte *dst, int w, int denom) = nil;
+ void (*scolx)(byte *src, byte *dst, int w, int denom) = nil;
+
+ ow = (src->w + xdenom - 1) / xdenom;
+ oh = (src->h + ydenom - 1) / ydenom;
+ xoffs /= xdenom;
+ yoffs /= ydenom;
+ n = src->n;
+
+ assert(xoffs == 0); /* don't handle stride properly yet */
+ assert(dst->n == n);
+ assert(dst->w >= xoffs + ow && dst->h >= yoffs + oh);
+
+ buf = fz_malloc(ow * n * ydenom);
+ if (!buf)
+ return fz_outofmem;
+
+ switch (n)
+ {
+ case 1: srowx = fz_srow1; scolx = fz_scol1; break;
+ case 2: srowx = fz_srow2; scolx = fz_scol2; break;
+ case 4: srowx = fz_srow4; scolx = fz_scol4; break;
+ case 5: srowx = fz_srow5; scolx = fz_scol5; break;
+ }
+
+ dstsamples = dst->samples + (yoffs * dst->w + xoffs)*dst->n;
+ if (srowx && scolx)
+ {
+ for (y = 0, oy = 0; y < (src->h / ydenom) * ydenom; y += ydenom, oy++)
+ {
+ for (iy = 0; iy < ydenom; iy++)
+ srowx(src->samples + (y + iy) * src->w * n,
+ buf + iy * ow * n,
+ src->w, xdenom);
+ scolx(buf, dstsamples + oy * dst->w * n, ow, ydenom);
+ }
+
+ remaining = src->h - y;
+ if (remaining)
+ {
+ for (iy = 0; iy < remaining; iy++)
+ srowx(src->samples + (y + iy) * src->w * n,
+ buf + iy * ow * n,
+ src->w, xdenom);
+ scolx(buf, dstsamples + oy * dst->w * n, ow, ydenom);
+ }
+ }
+
+ else
+ {
+ for (y = 0, oy = 0; y < (src->h / ydenom) * ydenom; y += ydenom, oy++)
+ {
+ for (iy = 0; iy < ydenom; iy++)
+ fz_srown(src->samples + (y + iy) * src->w * n,
+ buf + iy * ow * n,
+ src->w, xdenom, n);
+ fz_scoln(buf, dstsamples + oy * dst->w * n, ow, ydenom, n);
+ }
+
+ remaining = src->h - y;
+ if (remaining)
+ {
+ for (iy = 0; iy < remaining; iy++)
+ fz_srown(src->samples + (y + iy) * src->w * n,
+ buf + iy * ow * n,
+ src->w, xdenom, n);
+ fz_scoln(buf, dstsamples + oy * dst->w * n, ow, ydenom, n);
+ }
+ }
+
+ fz_free(buf);
+ return fz_okay;
+}
+
+fz_error *
+fz_scalepixmap(fz_pixmap **dstp, fz_pixmap *src, int xdenom, int ydenom)
+{
+ fz_error *error;
+ fz_pixmap *dst;
+ unsigned char *buf;
+ int y, iy, oy;
+ int ow, oh, n;
+ int remaining;
+
+ void (*srowx)(byte *src, byte *dst, int w, int denom) = nil;
+ void (*scolx)(byte *src, byte *dst, int w, int denom) = nil;
+
+ ow = (src->w + xdenom - 1) / xdenom;
+ oh = (src->h + ydenom - 1) / ydenom;
+ n = src->n;
+
+ buf = fz_malloc(ow * n * ydenom);
+ if (!buf)
+ return fz_outofmem;
+
+ error = fz_newpixmap(&dst, 0, 0, ow, oh, src->n);
+ if (error)
+ {
+ fz_free(buf);
+ return error;
+ }
+
+ switch (n)
+ {
+ case 1: srowx = fz_srow1; scolx = fz_scol1; break;
+ case 2: srowx = fz_srow2; scolx = fz_scol2; break;
+ case 4: srowx = fz_srow4; scolx = fz_scol4; break;
+ case 5: srowx = fz_srow5; scolx = fz_scol5; break;
+ }
+
+ if (srowx && scolx)
+ {
+ for (y = 0, oy = 0; y < (src->h / ydenom) * ydenom; y += ydenom, oy++)
+ {
+ for (iy = 0; iy < ydenom; iy++)
+ srowx(src->samples + (y + iy) * src->w * n,
+ buf + iy * ow * n,
+ src->w, xdenom);
+ scolx(buf, dst->samples + oy * dst->w * n, dst->w, ydenom);
+ }
+
+ remaining = src->h - y;
+ if (remaining)
+ {
+ for (iy = 0; iy < remaining; iy++)
+ srowx(src->samples + (y + iy) * src->w * n,
+ buf + iy * ow * n,
+ src->w, xdenom);
+ scolx(buf, dst->samples + oy * dst->w * n, dst->w, ydenom);
+ }
+ }
+
+ else
+ {
+ for (y = 0, oy = 0; y < (src->h / ydenom) * ydenom; y += ydenom, oy++)
+ {
+ for (iy = 0; iy < ydenom; iy++)
+ fz_srown(src->samples + (y + iy) * src->w * n,
+ buf + iy * ow * n,
+ src->w, xdenom, n);
+ fz_scoln(buf, dst->samples + oy * dst->w * n, dst->w, ydenom, n);
+ }
+
+ remaining = src->h - y;
+ if (remaining)
+ {
+ for (iy = 0; iy < remaining; iy++)
+ fz_srown(src->samples + (y + iy) * src->w * n,
+ buf + iy * ow * n,
+ src->w, xdenom, n);
+ fz_scoln(buf, dst->samples + oy * dst->w * n, dst->w, ydenom, n);
+ }
+ }
+
+ fz_free(buf);
+ *dstp = dst;
+ return fz_okay;
+}
+