Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Imaging/libImaging/Antialias.c
diff options
context:
space:
mode:
Diffstat (limited to 'Imaging/libImaging/Antialias.c')
-rw-r--r--Imaging/libImaging/Antialias.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/Imaging/libImaging/Antialias.c b/Imaging/libImaging/Antialias.c
new file mode 100644
index 0000000..089056e
--- /dev/null
+++ b/Imaging/libImaging/Antialias.c
@@ -0,0 +1,307 @@
+/*
+ * The Python Imaging Library
+ * $Id: Antialias.c 2408 2005-05-15 09:31:27Z Fredrik $
+ *
+ * pilopen antialiasing support
+ *
+ * history:
+ * 2002-03-09 fl Created (for PIL 1.1.3)
+ * 2002-03-10 fl Added support for mode "F"
+ *
+ * Copyright (c) 1997-2002 by Secret Labs AB
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#include <math.h>
+
+/* resampling filters (from antialias.py) */
+
+struct filter {
+ float (*filter)(float x);
+ float support;
+};
+
+static inline float sinc_filter(float x)
+{
+ if (x == 0.0)
+ return 1.0;
+ x = x * M_PI;
+ return sin(x) / x;
+}
+
+static inline float antialias_filter(float x)
+{
+ /* lanczos (truncated sinc) */
+ if (-3.0 <= x && x < 3.0)
+ return sinc_filter(x) * sinc_filter(x/3);
+ return 0.0;
+}
+
+static struct filter ANTIALIAS = { antialias_filter, 3.0 };
+
+static inline float nearest_filter(float x)
+{
+ if (-0.5 <= x && x < 0.5)
+ return 1.0;
+ return 0.0;
+}
+
+static struct filter NEAREST = { nearest_filter, 0.5 };
+
+static inline float bilinear_filter(float x)
+{
+ if (x < 0.0)
+ x = -x;
+ if (x < 1.0)
+ return 1.0-x;
+ return 0.0;
+}
+
+static struct filter BILINEAR = { bilinear_filter, 1.0 };
+
+static inline float bicubic_filter(float x)
+{
+ /* FIXME: double-check this algorithm */
+ /* FIXME: for best results, "a" should be -0.5 to -1.0, but we'll
+ set it to zero for now, to match the 1.1 magnifying filter */
+#define a 0.0
+ if (x < 0.0)
+ x = -x;
+ if (x < 1.0)
+ return (((a + 2.0) * x) - (a + 3.0)) * x*x + 1;
+ if (x < 2.0)
+ return (((a * x) - 5*a) * x + 8) * x - 4*a;
+ return 0.0;
+#undef a
+}
+
+static struct filter BICUBIC = { bicubic_filter, 2.0 };
+
+Imaging
+ImagingStretch(Imaging imOut, Imaging imIn, int filter)
+{
+ /* FIXME: this is a quick and straightforward translation from a
+ python prototype. might need some further C-ification... */
+
+ ImagingSectionCookie cookie;
+ struct filter *filterp;
+ float support, scale, filterscale;
+ float center, ww, ss, ymin, ymax, xmin, xmax;
+ int xx, yy, x, y, b;
+ float *k;
+
+ /* check modes */
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
+ return (Imaging) ImagingError_ModeError();
+
+ /* check filter */
+ switch (filter) {
+ case IMAGING_TRANSFORM_NEAREST:
+ filterp = &NEAREST;
+ break;
+ case IMAGING_TRANSFORM_ANTIALIAS:
+ filterp = &ANTIALIAS;
+ break;
+ case IMAGING_TRANSFORM_BILINEAR:
+ filterp = &BILINEAR;
+ break;
+ case IMAGING_TRANSFORM_BICUBIC:
+ filterp = &BICUBIC;
+ break;
+ default:
+ return (Imaging) ImagingError_ValueError(
+ "unsupported resampling filter"
+ );
+ }
+
+ if (imIn->ysize == imOut->ysize) {
+ /* prepare for horizontal stretch */
+ filterscale = scale = (float) imIn->xsize / imOut->xsize;
+ } else if (imIn->xsize == imOut->xsize) {
+ /* prepare for vertical stretch */
+ filterscale = scale = (float) imIn->ysize / imOut->ysize;
+ } else
+ return (Imaging) ImagingError_Mismatch();
+
+ /* determine support size (length of resampling filter) */
+ support = filterp->support;
+
+ if (filterscale < 1.0) {
+ filterscale = 1.0;
+ support = 0.5;
+ }
+
+ support = support * filterscale;
+
+ /* coefficient buffer (with rounding safety margin) */
+ k = malloc(((int) support * 2 + 10) * sizeof(float));
+ if (!k)
+ return (Imaging) ImagingError_MemoryError();
+
+ ImagingSectionEnter(&cookie);
+ if (imIn->xsize == imOut->xsize) {
+ /* vertical stretch */
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ center = (yy + 0.5) * scale;
+ ww = 0.0;
+ ss = 1.0 / filterscale;
+ /* calculate filter weights */
+ ymin = floor(center - support);
+ if (ymin < 0.0)
+ ymin = 0.0;
+ ymax = ceil(center + support);
+ if (ymax > imIn->ysize)
+ ymax = imIn->ysize;
+ for (y = (int) ymin; y < (int) ymax; y++) {
+ float w = filterp->filter((y - center + 0.5) * ss) * ss;
+ k[y - (int) ymin] = w;
+ ww = ww + w;
+ }
+ if (ww == 0.0)
+ ww = 1.0;
+ else
+ ww = 1.0 / ww;
+ if (imIn->image8) {
+ /* 8-bit grayscale */
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ ss = 0.0;
+ for (y = (int) ymin; y < (int) ymax; y++)
+ ss = ss + imIn->image8[y][xx] * k[y - (int) ymin];
+ ss = ss * ww + 0.5;
+ if (ss < 0.5)
+ imOut->image8[yy][xx] = 0;
+ else if (ss >= 255.0)
+ imOut->image8[yy][xx] = 255;
+ else
+ imOut->image8[yy][xx] = (UINT8) ss;
+ }
+ } else
+ switch(imIn->type) {
+ case IMAGING_TYPE_UINT8:
+ /* n-bit grayscale */
+ for (xx = 0; xx < imOut->xsize*4; xx++) {
+ /* FIXME: skip over unused pixels */
+ ss = 0.0;
+ for (y = (int) ymin; y < (int) ymax; y++)
+ ss = ss + (UINT8) imIn->image[y][xx] * k[y-(int) ymin];
+ ss = ss * ww + 0.5;
+ if (ss < 0.5)
+ imOut->image[yy][xx] = (UINT8) 0;
+ else if (ss >= 255.0)
+ imOut->image[yy][xx] = (UINT8) 255;
+ else
+ imOut->image[yy][xx] = (UINT8) ss;
+ }
+ break;
+ case IMAGING_TYPE_INT32:
+ /* 32-bit integer */
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ ss = 0.0;
+ for (y = (int) ymin; y < (int) ymax; y++)
+ ss = ss + IMAGING_PIXEL_I(imIn, xx, y) * k[y - (int) ymin];
+ IMAGING_PIXEL_I(imOut, xx, yy) = ss * ww;
+ }
+ break;
+ case IMAGING_TYPE_FLOAT32:
+ /* 32-bit float */
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ ss = 0.0;
+ for (y = (int) ymin; y < (int) ymax; y++)
+ ss = ss + IMAGING_PIXEL_F(imIn, xx, y) * k[y - (int) ymin];
+ IMAGING_PIXEL_F(imOut, xx, yy) = ss * ww;
+ }
+ break;
+ default:
+ ImagingSectionLeave(&cookie);
+ return (Imaging) ImagingError_ModeError();
+ }
+ }
+ } else {
+ /* horizontal stretch */
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ center = (xx + 0.5) * scale;
+ ww = 0.0;
+ ss = 1.0 / filterscale;
+ xmin = floor(center - support);
+ if (xmin < 0.0)
+ xmin = 0.0;
+ xmax = ceil(center + support);
+ if (xmax > imIn->xsize)
+ xmax = imIn->xsize;
+ for (x = (int) xmin; x < (int) xmax; x++) {
+ float w = filterp->filter((x - center + 0.5) * ss) * ss;
+ k[x - (int) xmin] = w;
+ ww = ww + w;
+ }
+ if (ww == 0.0)
+ ww = 1.0;
+ else
+ ww = 1.0 / ww;
+ if (imIn->image8) {
+ /* 8-bit grayscale */
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ ss = 0.0;
+ for (x = (int) xmin; x < (int) xmax; x++)
+ ss = ss + imIn->image8[yy][x] * k[x - (int) xmin];
+ ss = ss * ww + 0.5;
+ if (ss < 0.5)
+ imOut->image8[yy][xx] = (UINT8) 0;
+ else if (ss >= 255.0)
+ imOut->image8[yy][xx] = (UINT8) 255;
+ else
+ imOut->image8[yy][xx] = (UINT8) ss;
+ }
+ } else
+ switch(imIn->type) {
+ case IMAGING_TYPE_UINT8:
+ /* n-bit grayscale */
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ for (b = 0; b < imIn->bands; b++) {
+ if (imIn->bands == 2 && b)
+ b = 3; /* hack to deal with LA images */
+ ss = 0.0;
+ for (x = (int) xmin; x < (int) xmax; x++)
+ ss = ss + (UINT8) imIn->image[yy][x*4+b] * k[x - (int) xmin];
+ ss = ss * ww + 0.5;
+ if (ss < 0.5)
+ imOut->image[yy][xx*4+b] = (UINT8) 0;
+ else if (ss >= 255.0)
+ imOut->image[yy][xx*4+b] = (UINT8) 255;
+ else
+ imOut->image[yy][xx*4+b] = (UINT8) ss;
+ }
+ }
+ break;
+ case IMAGING_TYPE_INT32:
+ /* 32-bit integer */
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ ss = 0.0;
+ for (x = (int) xmin; x < (int) xmax; x++)
+ ss = ss + IMAGING_PIXEL_I(imIn, x, yy) * k[x - (int) xmin];
+ IMAGING_PIXEL_I(imOut, xx, yy) = ss * ww;
+ }
+ break;
+ case IMAGING_TYPE_FLOAT32:
+ /* 32-bit float */
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ ss = 0.0;
+ for (x = (int) xmin; x < (int) xmax; x++)
+ ss = ss + IMAGING_PIXEL_F(imIn, x, yy) * k[x - (int) xmin];
+ IMAGING_PIXEL_F(imOut, xx, yy) = ss * ww;
+ }
+ break;
+ default:
+ ImagingSectionLeave(&cookie);
+ return (Imaging) ImagingError_ModeError();
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+
+ free(k);
+
+ return imOut;
+}