summaryrefslogtreecommitdiffstats
path: root/contrib/python/Pillow/py3/libImaging
diff options
context:
space:
mode:
authorshumkovnd <[email protected]>2023-11-10 14:39:34 +0300
committershumkovnd <[email protected]>2023-11-10 16:42:24 +0300
commit77eb2d3fdcec5c978c64e025ced2764c57c00285 (patch)
treec51edb0748ca8d4a08d7c7323312c27ba1a8b79a /contrib/python/Pillow/py3/libImaging
parentdd6d20cadb65582270ac23f4b3b14ae189704b9d (diff)
KIKIMR-19287: add task_stats_drawing script
Diffstat (limited to 'contrib/python/Pillow/py3/libImaging')
-rw-r--r--contrib/python/Pillow/py3/libImaging/Access.c239
-rw-r--r--contrib/python/Pillow/py3/libImaging/AlphaComposite.c85
-rw-r--r--contrib/python/Pillow/py3/libImaging/Bands.c315
-rw-r--r--contrib/python/Pillow/py3/libImaging/Bcn.h3
-rw-r--r--contrib/python/Pillow/py3/libImaging/BcnDecode.c897
-rw-r--r--contrib/python/Pillow/py3/libImaging/Bit.h29
-rw-r--r--contrib/python/Pillow/py3/libImaging/BitDecode.c138
-rw-r--r--contrib/python/Pillow/py3/libImaging/Blend.c79
-rw-r--r--contrib/python/Pillow/py3/libImaging/BoxBlur.c324
-rw-r--r--contrib/python/Pillow/py3/libImaging/Chops.c162
-rw-r--r--contrib/python/Pillow/py3/libImaging/ColorLUT.c187
-rw-r--r--contrib/python/Pillow/py3/libImaging/Convert.c1742
-rw-r--r--contrib/python/Pillow/py3/libImaging/Convert.h2
-rw-r--r--contrib/python/Pillow/py3/libImaging/ConvertYCbCr.c363
-rw-r--r--contrib/python/Pillow/py3/libImaging/Copy.c57
-rw-r--r--contrib/python/Pillow/py3/libImaging/Crop.c63
-rw-r--r--contrib/python/Pillow/py3/libImaging/Dib.c313
-rw-r--r--contrib/python/Pillow/py3/libImaging/Draw.c1948
-rw-r--r--contrib/python/Pillow/py3/libImaging/Effects.c160
-rw-r--r--contrib/python/Pillow/py3/libImaging/EpsEncode.c77
-rw-r--r--contrib/python/Pillow/py3/libImaging/File.c78
-rw-r--r--contrib/python/Pillow/py3/libImaging/Fill.c139
-rw-r--r--contrib/python/Pillow/py3/libImaging/Filter.c412
-rw-r--r--contrib/python/Pillow/py3/libImaging/FliDecode.c268
-rw-r--r--contrib/python/Pillow/py3/libImaging/Geometry.c1157
-rw-r--r--contrib/python/Pillow/py3/libImaging/GetBBox.c356
-rw-r--r--contrib/python/Pillow/py3/libImaging/Gif.h100
-rw-r--r--contrib/python/Pillow/py3/libImaging/GifDecode.c285
-rw-r--r--contrib/python/Pillow/py3/libImaging/GifEncode.c361
-rw-r--r--contrib/python/Pillow/py3/libImaging/HexDecode.c63
-rw-r--r--contrib/python/Pillow/py3/libImaging/Histo.c201
-rw-r--r--contrib/python/Pillow/py3/libImaging/ImDib.h64
-rw-r--r--contrib/python/Pillow/py3/libImaging/ImPlatform.h98
-rw-r--r--contrib/python/Pillow/py3/libImaging/Imaging.h693
-rw-r--r--contrib/python/Pillow/py3/libImaging/ImagingUtils.h42
-rw-r--r--contrib/python/Pillow/py3/libImaging/Jpeg.h116
-rw-r--r--contrib/python/Pillow/py3/libImaging/Jpeg2K.h113
-rw-r--r--contrib/python/Pillow/py3/libImaging/Jpeg2KDecode.c999
-rw-r--r--contrib/python/Pillow/py3/libImaging/Jpeg2KEncode.c659
-rw-r--r--contrib/python/Pillow/py3/libImaging/JpegDecode.c304
-rw-r--r--contrib/python/Pillow/py3/libImaging/JpegEncode.c354
-rw-r--r--contrib/python/Pillow/py3/libImaging/Matrix.c78
-rw-r--r--contrib/python/Pillow/py3/libImaging/ModeFilter.c81
-rw-r--r--contrib/python/Pillow/py3/libImaging/Negative.c42
-rw-r--r--contrib/python/Pillow/py3/libImaging/Offset.c64
-rw-r--r--contrib/python/Pillow/py3/libImaging/Pack.c693
-rw-r--r--contrib/python/Pillow/py3/libImaging/PackDecode.c92
-rw-r--r--contrib/python/Pillow/py3/libImaging/Palette.c307
-rw-r--r--contrib/python/Pillow/py3/libImaging/Paste.c628
-rw-r--r--contrib/python/Pillow/py3/libImaging/PcdDecode.c74
-rw-r--r--contrib/python/Pillow/py3/libImaging/PcxDecode.c89
-rw-r--r--contrib/python/Pillow/py3/libImaging/PcxEncode.c187
-rw-r--r--contrib/python/Pillow/py3/libImaging/Point.c270
-rw-r--r--contrib/python/Pillow/py3/libImaging/Quant.c1859
-rw-r--r--contrib/python/Pillow/py3/libImaging/QuantHash.c336
-rw-r--r--contrib/python/Pillow/py3/libImaging/QuantHash.h55
-rw-r--r--contrib/python/Pillow/py3/libImaging/QuantHeap.c176
-rw-r--r--contrib/python/Pillow/py3/libImaging/QuantHeap.h31
-rw-r--r--contrib/python/Pillow/py3/libImaging/QuantOctree.c538
-rw-r--r--contrib/python/Pillow/py3/libImaging/QuantOctree.h9
-rw-r--r--contrib/python/Pillow/py3/libImaging/QuantPngQuant.c132
-rw-r--r--contrib/python/Pillow/py3/libImaging/QuantPngQuant.h17
-rw-r--r--contrib/python/Pillow/py3/libImaging/QuantTypes.h32
-rw-r--r--contrib/python/Pillow/py3/libImaging/RankFilter.c132
-rw-r--r--contrib/python/Pillow/py3/libImaging/Raw.h14
-rw-r--r--contrib/python/Pillow/py3/libImaging/RawDecode.c91
-rw-r--r--contrib/python/Pillow/py3/libImaging/RawEncode.c87
-rw-r--r--contrib/python/Pillow/py3/libImaging/Reduce.c1483
-rw-r--r--contrib/python/Pillow/py3/libImaging/Resample.c708
-rw-r--r--contrib/python/Pillow/py3/libImaging/Sgi.h39
-rw-r--r--contrib/python/Pillow/py3/libImaging/SgiRleDecode.c288
-rw-r--r--contrib/python/Pillow/py3/libImaging/Storage.c577
-rw-r--r--contrib/python/Pillow/py3/libImaging/SunRleDecode.c139
-rw-r--r--contrib/python/Pillow/py3/libImaging/TgaRleDecode.c129
-rw-r--r--contrib/python/Pillow/py3/libImaging/TgaRleEncode.c157
-rw-r--r--contrib/python/Pillow/py3/libImaging/TiffDecode.c997
-rw-r--r--contrib/python/Pillow/py3/libImaging/TiffDecode.h66
-rw-r--r--contrib/python/Pillow/py3/libImaging/Unpack.c1821
-rw-r--r--contrib/python/Pillow/py3/libImaging/UnpackYCC.c163
-rw-r--r--contrib/python/Pillow/py3/libImaging/UnsharpMask.c97
-rw-r--r--contrib/python/Pillow/py3/libImaging/XbmDecode.c78
-rw-r--r--contrib/python/Pillow/py3/libImaging/XbmEncode.c96
-rw-r--r--contrib/python/Pillow/py3/libImaging/ZipCodecs.h58
-rw-r--r--contrib/python/Pillow/py3/libImaging/ZipDecode.c299
-rw-r--r--contrib/python/Pillow/py3/libImaging/ZipEncode.c367
-rw-r--r--contrib/python/Pillow/py3/libImaging/codec_fd.c69
86 files changed, 27790 insertions, 0 deletions
diff --git a/contrib/python/Pillow/py3/libImaging/Access.c b/contrib/python/Pillow/py3/libImaging/Access.c
new file mode 100644
index 00000000000..091c84e18fa
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Access.c
@@ -0,0 +1,239 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * imaging access objects
+ *
+ * Copyright (c) Fredrik Lundh 2009.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+/* use make_hash.py from the pillow-scripts repository to calculate these values */
+#define ACCESS_TABLE_SIZE 35
+#define ACCESS_TABLE_HASH 8940
+
+static struct ImagingAccessInstance access_table[ACCESS_TABLE_SIZE];
+
+static inline UINT32
+hash(const char *mode) {
+ UINT32 i = ACCESS_TABLE_HASH;
+ while (*mode) {
+ i = ((i << 5) + i) ^ (UINT8)*mode++;
+ }
+ return i % ACCESS_TABLE_SIZE;
+}
+
+static ImagingAccess
+add_item(const char *mode) {
+ UINT32 i = hash(mode);
+ /* printf("hash %s => %d\n", mode, i); */
+ if (access_table[i].mode && strcmp(access_table[i].mode, mode) != 0) {
+ fprintf(
+ stderr,
+ "AccessInit: hash collision: %d for both %s and %s\n",
+ i,
+ mode,
+ access_table[i].mode);
+ exit(1);
+ }
+ access_table[i].mode = mode;
+ return &access_table[i];
+}
+
+/* fetch individual pixel */
+
+static void
+get_pixel_32_2bands(Imaging im, int x, int y, void *color) {
+ char *out = color;
+ UINT8 *p = (UINT8 *)&im->image32[y][x];
+ out[0] = p[0];
+ out[1] = p[3];
+}
+
+static void
+get_pixel_8(Imaging im, int x, int y, void *color) {
+ char *out = color;
+ out[0] = im->image8[y][x];
+}
+
+static void
+get_pixel_16L(Imaging im, int x, int y, void *color) {
+ UINT8 *in = (UINT8 *)&im->image[y][x + x];
+#ifdef WORDS_BIGENDIAN
+ UINT16 out = in[0] + (in[1] << 8);
+ memcpy(color, &out, sizeof(out));
+#else
+ memcpy(color, in, sizeof(UINT16));
+#endif
+}
+
+static void
+get_pixel_16B(Imaging im, int x, int y, void *color) {
+ UINT8 *in = (UINT8 *)&im->image[y][x + x];
+#ifdef WORDS_BIGENDIAN
+ memcpy(color, in, sizeof(UINT16));
+#else
+ UINT16 out = in[1] + (in[0] << 8);
+ memcpy(color, &out, sizeof(out));
+#endif
+}
+
+static void
+get_pixel_16(Imaging im, int x, int y, void *color) {
+ UINT8 *in = (UINT8 *)&im->image[y][x + x];
+ memcpy(color, in, sizeof(UINT16));
+}
+
+static void
+get_pixel_BGR15(Imaging im, int x, int y, void *color) {
+ UINT8 *in = (UINT8 *)&im->image8[y][x * 2];
+ UINT16 pixel = in[0] + (in[1] << 8);
+ char *out = color;
+ out[0] = (pixel & 31) * 255 / 31;
+ out[1] = ((pixel >> 5) & 31) * 255 / 31;
+ out[2] = ((pixel >> 10) & 31) * 255 / 31;
+}
+
+static void
+get_pixel_BGR16(Imaging im, int x, int y, void *color) {
+ UINT8 *in = (UINT8 *)&im->image8[y][x * 2];
+ UINT16 pixel = in[0] + (in[1] << 8);
+ char *out = color;
+ out[0] = (pixel & 31) * 255 / 31;
+ out[1] = ((pixel >> 5) & 63) * 255 / 63;
+ out[2] = ((pixel >> 11) & 31) * 255 / 31;
+}
+
+static void
+get_pixel_BGR24(Imaging im, int x, int y, void *color) {
+ memcpy(color, &im->image8[y][x * 3], sizeof(UINT8) * 3);
+}
+
+static void
+get_pixel_32(Imaging im, int x, int y, void *color) {
+ memcpy(color, &im->image32[y][x], sizeof(INT32));
+}
+
+static void
+get_pixel_32L(Imaging im, int x, int y, void *color) {
+ UINT8 *in = (UINT8 *)&im->image[y][x * 4];
+#ifdef WORDS_BIGENDIAN
+ INT32 out = in[0] + (in[1] << 8) + (in[2] << 16) + (in[3] << 24);
+ memcpy(color, &out, sizeof(out));
+#else
+ memcpy(color, in, sizeof(INT32));
+#endif
+}
+
+static void
+get_pixel_32B(Imaging im, int x, int y, void *color) {
+ UINT8 *in = (UINT8 *)&im->image[y][x * 4];
+#ifdef WORDS_BIGENDIAN
+ memcpy(color, in, sizeof(INT32));
+#else
+ INT32 out = in[3] + (in[2] << 8) + (in[1] << 16) + (in[0] << 24);
+ memcpy(color, &out, sizeof(out));
+#endif
+}
+
+/* store individual pixel */
+
+static void
+put_pixel_8(Imaging im, int x, int y, const void *color) {
+ im->image8[y][x] = *((UINT8 *)color);
+}
+
+static void
+put_pixel_16L(Imaging im, int x, int y, const void *color) {
+ memcpy(&im->image8[y][x + x], color, 2);
+}
+
+static void
+put_pixel_16B(Imaging im, int x, int y, const void *color) {
+ const char *in = color;
+ UINT8 *out = (UINT8 *)&im->image8[y][x + x];
+ out[0] = in[1];
+ out[1] = in[0];
+}
+
+static void
+put_pixel_BGR1516(Imaging im, int x, int y, const void *color) {
+ memcpy(&im->image8[y][x * 2], color, 2);
+}
+
+static void
+put_pixel_BGR24(Imaging im, int x, int y, const void *color) {
+ memcpy(&im->image8[y][x * 3], color, 3);
+}
+
+static void
+put_pixel_32L(Imaging im, int x, int y, const void *color) {
+ memcpy(&im->image8[y][x * 4], color, 4);
+}
+
+static void
+put_pixel_32B(Imaging im, int x, int y, const void *color) {
+ const char *in = color;
+ UINT8 *out = (UINT8 *)&im->image8[y][x * 4];
+ out[0] = in[3];
+ out[1] = in[2];
+ out[2] = in[1];
+ out[3] = in[0];
+}
+
+static void
+put_pixel_32(Imaging im, int x, int y, const void *color) {
+ memcpy(&im->image32[y][x], color, sizeof(INT32));
+}
+
+void
+ImagingAccessInit() {
+#define ADD(mode_, get_pixel_, put_pixel_) \
+ { \
+ ImagingAccess access = add_item(mode_); \
+ access->get_pixel = get_pixel_; \
+ access->put_pixel = put_pixel_; \
+ }
+
+ /* populate access table */
+ ADD("1", get_pixel_8, put_pixel_8);
+ ADD("L", get_pixel_8, put_pixel_8);
+ ADD("LA", get_pixel_32_2bands, put_pixel_32);
+ ADD("La", get_pixel_32_2bands, put_pixel_32);
+ ADD("I", get_pixel_32, put_pixel_32);
+ ADD("I;16", get_pixel_16L, put_pixel_16L);
+ ADD("I;16L", get_pixel_16L, put_pixel_16L);
+ ADD("I;16B", get_pixel_16B, put_pixel_16B);
+ ADD("I;16N", get_pixel_16, put_pixel_16L);
+ ADD("I;32L", get_pixel_32L, put_pixel_32L);
+ ADD("I;32B", get_pixel_32B, put_pixel_32B);
+ ADD("F", get_pixel_32, put_pixel_32);
+ ADD("P", get_pixel_8, put_pixel_8);
+ ADD("PA", get_pixel_32_2bands, put_pixel_32);
+ ADD("BGR;15", get_pixel_BGR15, put_pixel_BGR1516);
+ ADD("BGR;16", get_pixel_BGR16, put_pixel_BGR1516);
+ ADD("BGR;24", get_pixel_BGR24, put_pixel_BGR24);
+ ADD("RGB", get_pixel_32, put_pixel_32);
+ ADD("RGBA", get_pixel_32, put_pixel_32);
+ ADD("RGBa", get_pixel_32, put_pixel_32);
+ ADD("RGBX", get_pixel_32, put_pixel_32);
+ ADD("CMYK", get_pixel_32, put_pixel_32);
+ ADD("YCbCr", get_pixel_32, put_pixel_32);
+ ADD("LAB", get_pixel_32, put_pixel_32);
+ ADD("HSV", get_pixel_32, put_pixel_32);
+}
+
+ImagingAccess
+ImagingAccessNew(Imaging im) {
+ ImagingAccess access = &access_table[hash(im->mode)];
+ if (im->mode[0] != access->mode[0] || strcmp(im->mode, access->mode) != 0) {
+ return NULL;
+ }
+ return access;
+}
+
+void
+_ImagingAccessDelete(Imaging im, ImagingAccess access) {}
diff --git a/contrib/python/Pillow/py3/libImaging/AlphaComposite.c b/contrib/python/Pillow/py3/libImaging/AlphaComposite.c
new file mode 100644
index 00000000000..6d728f9088b
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/AlphaComposite.c
@@ -0,0 +1,85 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * Alpha composite imSrc over imDst.
+ * https://en.wikipedia.org/wiki/Alpha_compositing
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#define PRECISION_BITS 7
+
+typedef struct {
+ UINT8 r;
+ UINT8 g;
+ UINT8 b;
+ UINT8 a;
+} rgba8;
+
+Imaging
+ImagingAlphaComposite(Imaging imDst, Imaging imSrc) {
+ Imaging imOut;
+ int x, y;
+
+ /* Check arguments */
+ if (!imDst || !imSrc || strcmp(imDst->mode, "RGBA") ||
+ imDst->type != IMAGING_TYPE_UINT8 || imDst->bands != 4) {
+ return ImagingError_ModeError();
+ }
+
+ if (strcmp(imDst->mode, imSrc->mode) || imDst->type != imSrc->type ||
+ imDst->bands != imSrc->bands || imDst->xsize != imSrc->xsize ||
+ imDst->ysize != imSrc->ysize) {
+ return ImagingError_Mismatch();
+ }
+
+ imOut = ImagingNewDirty(imDst->mode, imDst->xsize, imDst->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ for (y = 0; y < imDst->ysize; y++) {
+ rgba8 *dst = (rgba8 *)imDst->image[y];
+ rgba8 *src = (rgba8 *)imSrc->image[y];
+ rgba8 *out = (rgba8 *)imOut->image[y];
+
+ for (x = 0; x < imDst->xsize; x++) {
+ if (src->a == 0) {
+ // Copy 4 bytes at once.
+ *out = *dst;
+ } else {
+ // Integer implementation with increased precision.
+ // Each variable has extra meaningful bits.
+ // Divisions are rounded.
+
+ UINT32 tmpr, tmpg, tmpb;
+ UINT32 blend = dst->a * (255 - src->a);
+ UINT32 outa255 = src->a * 255 + blend;
+ // There we use 7 bits for precision.
+ // We could use more, but we go beyond 32 bits.
+ UINT32 coef1 = src->a * 255 * 255 * (1 << PRECISION_BITS) / outa255;
+ UINT32 coef2 = 255 * (1 << PRECISION_BITS) - coef1;
+
+ tmpr = src->r * coef1 + dst->r * coef2;
+ tmpg = src->g * coef1 + dst->g * coef2;
+ tmpb = src->b * coef1 + dst->b * coef2;
+ out->r =
+ SHIFTFORDIV255(tmpr + (0x80 << PRECISION_BITS)) >> PRECISION_BITS;
+ out->g =
+ SHIFTFORDIV255(tmpg + (0x80 << PRECISION_BITS)) >> PRECISION_BITS;
+ out->b =
+ SHIFTFORDIV255(tmpb + (0x80 << PRECISION_BITS)) >> PRECISION_BITS;
+ out->a = SHIFTFORDIV255(outa255 + 0x80);
+ }
+
+ dst++;
+ src++;
+ out++;
+ }
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Bands.c b/contrib/python/Pillow/py3/libImaging/Bands.c
new file mode 100644
index 00000000000..e1b16b34ac0
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Bands.c
@@ -0,0 +1,315 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * stuff to extract and paste back individual bands
+ *
+ * history:
+ * 1996-03-20 fl Created
+ * 1997-08-27 fl Fixed putband for single band targets.
+ * 2003-09-26 fl Fixed getband/putband for 2-band images (LA, PA).
+ *
+ * Copyright (c) 1997-2003 by Secret Labs AB.
+ * Copyright (c) 1996-1997 by Fredrik Lundh.
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+Imaging
+ImagingGetBand(Imaging imIn, int band) {
+ Imaging imOut;
+ int x, y;
+
+ /* Check arguments */
+ if (!imIn || imIn->type != IMAGING_TYPE_UINT8) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ if (band < 0 || band >= imIn->bands) {
+ return (Imaging)ImagingError_ValueError("band index out of range");
+ }
+
+ /* Shortcuts */
+ if (imIn->bands == 1) {
+ return ImagingCopy(imIn);
+ }
+
+ /* Special case for LXXA etc */
+ if (imIn->bands == 2 && band == 1) {
+ band = 3;
+ }
+
+ imOut = ImagingNewDirty("L", imIn->xsize, imIn->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ /* Extract band from image */
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8 *in = (UINT8 *)imIn->image[y] + band;
+ UINT8 *out = imOut->image8[y];
+ x = 0;
+ for (; x < imIn->xsize - 3; x += 4) {
+ UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]);
+ memcpy(out + x, &v, sizeof(v));
+ in += 16;
+ }
+ for (; x < imIn->xsize; x++) {
+ out[x] = *in;
+ in += 4;
+ }
+ }
+
+ return imOut;
+}
+
+int
+ImagingSplit(Imaging imIn, Imaging bands[4]) {
+ int i, j, x, y;
+
+ /* Check arguments */
+ if (!imIn || imIn->type != IMAGING_TYPE_UINT8) {
+ (void)ImagingError_ModeError();
+ return 0;
+ }
+
+ /* Shortcuts */
+ if (imIn->bands == 1) {
+ bands[0] = ImagingCopy(imIn);
+ return imIn->bands;
+ }
+
+ for (i = 0; i < imIn->bands; i++) {
+ bands[i] = ImagingNewDirty("L", imIn->xsize, imIn->ysize);
+ if (!bands[i]) {
+ for (j = 0; j < i; ++j) {
+ ImagingDelete(bands[j]);
+ }
+ return 0;
+ }
+ }
+
+ /* Extract bands from image */
+ if (imIn->bands == 2) {
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8 *in = (UINT8 *)imIn->image[y];
+ UINT8 *out0 = bands[0]->image8[y];
+ UINT8 *out1 = bands[1]->image8[y];
+ x = 0;
+ for (; x < imIn->xsize - 3; x += 4) {
+ UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]);
+ memcpy(out0 + x, &v, sizeof(v));
+ v = MAKE_UINT32(in[0 + 3], in[4 + 3], in[8 + 3], in[12 + 3]);
+ memcpy(out1 + x, &v, sizeof(v));
+ in += 16;
+ }
+ for (; x < imIn->xsize; x++) {
+ out0[x] = in[0];
+ out1[x] = in[3];
+ in += 4;
+ }
+ }
+ } else if (imIn->bands == 3) {
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8 *in = (UINT8 *)imIn->image[y];
+ UINT8 *out0 = bands[0]->image8[y];
+ UINT8 *out1 = bands[1]->image8[y];
+ UINT8 *out2 = bands[2]->image8[y];
+ x = 0;
+ for (; x < imIn->xsize - 3; x += 4) {
+ UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]);
+ memcpy(out0 + x, &v, sizeof(v));
+ v = MAKE_UINT32(in[0 + 1], in[4 + 1], in[8 + 1], in[12 + 1]);
+ memcpy(out1 + x, &v, sizeof(v));
+ v = MAKE_UINT32(in[0 + 2], in[4 + 2], in[8 + 2], in[12 + 2]);
+ memcpy(out2 + x, &v, sizeof(v));
+ in += 16;
+ }
+ for (; x < imIn->xsize; x++) {
+ out0[x] = in[0];
+ out1[x] = in[1];
+ out2[x] = in[2];
+ in += 4;
+ }
+ }
+ } else {
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8 *in = (UINT8 *)imIn->image[y];
+ UINT8 *out0 = bands[0]->image8[y];
+ UINT8 *out1 = bands[1]->image8[y];
+ UINT8 *out2 = bands[2]->image8[y];
+ UINT8 *out3 = bands[3]->image8[y];
+ x = 0;
+ for (; x < imIn->xsize - 3; x += 4) {
+ UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]);
+ memcpy(out0 + x, &v, sizeof(v));
+ v = MAKE_UINT32(in[0 + 1], in[4 + 1], in[8 + 1], in[12 + 1]);
+ memcpy(out1 + x, &v, sizeof(v));
+ v = MAKE_UINT32(in[0 + 2], in[4 + 2], in[8 + 2], in[12 + 2]);
+ memcpy(out2 + x, &v, sizeof(v));
+ v = MAKE_UINT32(in[0 + 3], in[4 + 3], in[8 + 3], in[12 + 3]);
+ memcpy(out3 + x, &v, sizeof(v));
+ in += 16;
+ }
+ for (; x < imIn->xsize; x++) {
+ out0[x] = in[0];
+ out1[x] = in[1];
+ out2[x] = in[2];
+ out3[x] = in[3];
+ in += 4;
+ }
+ }
+ }
+
+ return imIn->bands;
+}
+
+Imaging
+ImagingPutBand(Imaging imOut, Imaging imIn, int band) {
+ int x, y;
+
+ /* Check arguments */
+ if (!imIn || imIn->bands != 1 || !imOut) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ if (band < 0 || band >= imOut->bands) {
+ return (Imaging)ImagingError_ValueError("band index out of range");
+ }
+
+ if (imIn->type != imOut->type || imIn->xsize != imOut->xsize ||
+ imIn->ysize != imOut->ysize) {
+ return (Imaging)ImagingError_Mismatch();
+ }
+
+ /* Shortcuts */
+ if (imOut->bands == 1) {
+ return ImagingCopy2(imOut, imIn);
+ }
+
+ /* Special case for LXXA etc */
+ if (imOut->bands == 2 && band == 1) {
+ band = 3;
+ }
+
+ /* Insert band into image */
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8 *in = imIn->image8[y];
+ UINT8 *out = (UINT8 *)imOut->image[y] + band;
+ for (x = 0; x < imIn->xsize; x++) {
+ *out = in[x];
+ out += 4;
+ }
+ }
+
+ return imOut;
+}
+
+Imaging
+ImagingFillBand(Imaging imOut, int band, int color) {
+ int x, y;
+
+ /* Check arguments */
+ if (!imOut || imOut->type != IMAGING_TYPE_UINT8) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ if (band < 0 || band >= imOut->bands) {
+ return (Imaging)ImagingError_ValueError("band index out of range");
+ }
+
+ /* Special case for LXXA etc */
+ if (imOut->bands == 2 && band == 1) {
+ band = 3;
+ }
+
+ color = CLIP8(color);
+
+ /* Insert color into image */
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8 *out = (UINT8 *)imOut->image[y] + band;
+ for (x = 0; x < imOut->xsize; x++) {
+ *out = (UINT8)color;
+ out += 4;
+ }
+ }
+
+ return imOut;
+}
+
+Imaging
+ImagingMerge(const char *mode, Imaging bands[4]) {
+ int i, x, y;
+ int bandsCount = 0;
+ Imaging imOut;
+ Imaging firstBand;
+
+ firstBand = bands[0];
+ if (!firstBand) {
+ return (Imaging)ImagingError_ValueError("wrong number of bands");
+ }
+
+ for (i = 0; i < 4; ++i) {
+ if (!bands[i]) {
+ break;
+ }
+ if (bands[i]->bands != 1) {
+ return (Imaging)ImagingError_ModeError();
+ }
+ if (bands[i]->xsize != firstBand->xsize ||
+ bands[i]->ysize != firstBand->ysize) {
+ return (Imaging)ImagingError_Mismatch();
+ }
+ }
+ bandsCount = i;
+
+ imOut = ImagingNewDirty(mode, firstBand->xsize, firstBand->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ if (imOut->bands != bandsCount) {
+ ImagingDelete(imOut);
+ return (Imaging)ImagingError_ValueError("wrong number of bands");
+ }
+
+ if (imOut->bands == 1) {
+ return ImagingCopy2(imOut, firstBand);
+ }
+
+ if (imOut->bands == 2) {
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8 *in0 = bands[0]->image8[y];
+ UINT8 *in1 = bands[1]->image8[y];
+ UINT32 *out = (UINT32 *)imOut->image32[y];
+ for (x = 0; x < imOut->xsize; x++) {
+ out[x] = MAKE_UINT32(in0[x], 0, 0, in1[x]);
+ }
+ }
+ } else if (imOut->bands == 3) {
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8 *in0 = bands[0]->image8[y];
+ UINT8 *in1 = bands[1]->image8[y];
+ UINT8 *in2 = bands[2]->image8[y];
+ UINT32 *out = (UINT32 *)imOut->image32[y];
+ for (x = 0; x < imOut->xsize; x++) {
+ out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], 0);
+ }
+ }
+ } else if (imOut->bands == 4) {
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8 *in0 = bands[0]->image8[y];
+ UINT8 *in1 = bands[1]->image8[y];
+ UINT8 *in2 = bands[2]->image8[y];
+ UINT8 *in3 = bands[3]->image8[y];
+ UINT32 *out = (UINT32 *)imOut->image32[y];
+ for (x = 0; x < imOut->xsize; x++) {
+ out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], in3[x]);
+ }
+ }
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Bcn.h b/contrib/python/Pillow/py3/libImaging/Bcn.h
new file mode 100644
index 00000000000..1a6fbee4576
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Bcn.h
@@ -0,0 +1,3 @@
+typedef struct {
+ char *pixel_format;
+} BCNSTATE;
diff --git a/contrib/python/Pillow/py3/libImaging/BcnDecode.c b/contrib/python/Pillow/py3/libImaging/BcnDecode.c
new file mode 100644
index 00000000000..5e4296eeba1
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/BcnDecode.c
@@ -0,0 +1,897 @@
+/*
+ * The Python Imaging Library
+ *
+ * decoder for DXTn-compressed data
+ *
+ * Format documentation:
+ * https://web.archive.org/web/20170802060935/http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_compression_s3tc.txt
+ *
+ * The contents of this file are in the public domain (CC0)
+ * Full text of the CC0 license:
+ * https://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+#include "Imaging.h"
+
+#include "Bcn.h"
+
+typedef struct {
+ UINT8 r, g, b, a;
+} rgba;
+
+typedef struct {
+ UINT8 l;
+} lum;
+
+typedef struct {
+ UINT16 c0, c1;
+ UINT32 lut;
+} bc1_color;
+
+typedef struct {
+ UINT8 a0, a1;
+ UINT8 lut[6];
+} bc3_alpha;
+
+typedef struct {
+ INT8 a0, a1;
+ UINT8 lut[6];
+} bc5s_alpha;
+
+#define LOAD16(p) (p)[0] | ((p)[1] << 8)
+
+#define LOAD32(p) (p)[0] | ((p)[1] << 8) | ((p)[2] << 16) | ((p)[3] << 24)
+
+static void
+bc1_color_load(bc1_color *dst, const UINT8 *src) {
+ dst->c0 = LOAD16(src);
+ dst->c1 = LOAD16(src + 2);
+ dst->lut = LOAD32(src + 4);
+}
+
+static rgba
+decode_565(UINT16 x) {
+ rgba c;
+ int r, g, b;
+ r = (x & 0xf800) >> 8;
+ r |= r >> 5;
+ c.r = r;
+ g = (x & 0x7e0) >> 3;
+ g |= g >> 6;
+ c.g = g;
+ b = (x & 0x1f) << 3;
+ b |= b >> 5;
+ c.b = b;
+ c.a = 0xff;
+ return c;
+}
+
+static void
+decode_bc1_color(rgba *dst, const UINT8 *src, int separate_alpha) {
+ bc1_color col;
+ rgba p[4];
+ int n, cw;
+ UINT16 r0, g0, b0, r1, g1, b1;
+ bc1_color_load(&col, src);
+
+ p[0] = decode_565(col.c0);
+ r0 = p[0].r;
+ g0 = p[0].g;
+ b0 = p[0].b;
+ p[1] = decode_565(col.c1);
+ r1 = p[1].r;
+ g1 = p[1].g;
+ b1 = p[1].b;
+
+
+ /* NOTE: BC2 and BC3 reuse BC1 color blocks but always act like c0 > c1 */
+ if (col.c0 > col.c1 || separate_alpha) {
+ p[2].r = (2 * r0 + 1 * r1) / 3;
+ p[2].g = (2 * g0 + 1 * g1) / 3;
+ p[2].b = (2 * b0 + 1 * b1) / 3;
+ p[2].a = 0xff;
+ p[3].r = (1 * r0 + 2 * r1) / 3;
+ p[3].g = (1 * g0 + 2 * g1) / 3;
+ p[3].b = (1 * b0 + 2 * b1) / 3;
+ p[3].a = 0xff;
+ } else {
+ p[2].r = (r0 + r1) / 2;
+ p[2].g = (g0 + g1) / 2;
+ p[2].b = (b0 + b1) / 2;
+ p[2].a = 0xff;
+ p[3].r = 0;
+ p[3].g = 0;
+ p[3].b = 0;
+ p[3].a = 0;
+ }
+ for (n = 0; n < 16; n++) {
+ cw = 3 & (col.lut >> (2 * n));
+ dst[n] = p[cw];
+ }
+}
+
+static void
+decode_bc3_alpha(char *dst, const UINT8 *src, int stride, int o, int sign) {
+ UINT16 a0, a1;
+ UINT8 a[8];
+ int n, lut1, lut2, aw;
+ if (sign == 1) {
+ bc5s_alpha b;
+ memcpy(&b, src, sizeof(bc5s_alpha));
+ a0 = b.a0 + 128;
+ a1 = b.a1 + 128;
+ lut1 = b.lut[0] | (b.lut[1] << 8) | (b.lut[2] << 16);
+ lut2 = b.lut[3] | (b.lut[4] << 8) | (b.lut[5] << 16);
+ } else {
+ bc3_alpha b;
+ memcpy(&b, src, sizeof(bc3_alpha));
+ a0 = b.a0;
+ a1 = b.a1;
+ lut1 = b.lut[0] | (b.lut[1] << 8) | (b.lut[2] << 16);
+ lut2 = b.lut[3] | (b.lut[4] << 8) | (b.lut[5] << 16);
+ }
+
+ a[0] = (UINT8)a0;
+ a[1] = (UINT8)a1;
+ if (a0 > a1) {
+ a[2] = (6 * a0 + 1 * a1) / 7;
+ a[3] = (5 * a0 + 2 * a1) / 7;
+ a[4] = (4 * a0 + 3 * a1) / 7;
+ a[5] = (3 * a0 + 4 * a1) / 7;
+ a[6] = (2 * a0 + 5 * a1) / 7;
+ a[7] = (1 * a0 + 6 * a1) / 7;
+ } else {
+ a[2] = (4 * a0 + 1 * a1) / 5;
+ a[3] = (3 * a0 + 2 * a1) / 5;
+ a[4] = (2 * a0 + 3 * a1) / 5;
+ a[5] = (1 * a0 + 4 * a1) / 5;
+ a[6] = 0;
+ a[7] = 0xff;
+ }
+ for (n = 0; n < 8; n++) {
+ aw = 7 & (lut1 >> (3 * n));
+ dst[stride * n + o] = a[aw];
+ }
+ for (n = 0; n < 8; n++) {
+ aw = 7 & (lut2 >> (3 * n));
+ dst[stride * (8 + n) + o] = a[aw];
+ }
+}
+
+static void
+decode_bc1_block(rgba *col, const UINT8 *src) {
+ decode_bc1_color(col, src, 0);
+}
+
+static void
+decode_bc2_block(rgba *col, const UINT8 *src) {
+ int n, bitI, byI, av;
+ decode_bc1_color(col, src + 8, 1);
+ for (n = 0; n < 16; n++) {
+ bitI = n * 4;
+ byI = bitI >> 3;
+ av = 0xf & (src[byI] >> (bitI & 7));
+ av = (av << 4) | av;
+ col[n].a = av;
+ }
+}
+
+static void
+decode_bc3_block(rgba *col, const UINT8 *src) {
+ decode_bc1_color(col, src + 8, 1);
+ decode_bc3_alpha((char *)col, src, sizeof(col[0]), 3, 0);
+}
+
+static void
+decode_bc4_block(lum *col, const UINT8 *src) {
+ decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0, 0);
+}
+
+static void
+decode_bc5_block(rgba *col, const UINT8 *src, int sign) {
+ decode_bc3_alpha((char *)col, src, sizeof(col[0]), 0, sign);
+ decode_bc3_alpha((char *)col, src + 8, sizeof(col[0]), 1, sign);
+}
+
+/* BC6 and BC7 are described here:
+ https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt
+ */
+
+static UINT8
+get_bit(const UINT8 *src, int bit) {
+ int by = bit >> 3;
+ bit &= 7;
+ return (src[by] >> bit) & 1;
+}
+
+static UINT8
+get_bits(const UINT8 *src, int bit, int count) {
+ UINT8 v;
+ int x;
+ int by = bit >> 3;
+ bit &= 7;
+ if (!count) {
+ return 0;
+ }
+ if (bit + count <= 8) {
+ v = (src[by] >> bit) & ((1 << count) - 1);
+ } else {
+ x = src[by] | (src[by + 1] << 8);
+ v = (x >> bit) & ((1 << count) - 1);
+ }
+ return v;
+}
+
+/* BC7 */
+typedef struct {
+ char ns;
+ char pb;
+ char rb;
+ char isb;
+ char cb;
+ char ab;
+ char epb;
+ char spb;
+ char ib;
+ char ib2;
+} bc7_mode_info;
+
+static const bc7_mode_info bc7_modes[] = {
+ {3, 4, 0, 0, 4, 0, 1, 0, 3, 0},
+ {2, 6, 0, 0, 6, 0, 0, 1, 3, 0},
+ {3, 6, 0, 0, 5, 0, 0, 0, 2, 0},
+ {2, 6, 0, 0, 7, 0, 1, 0, 2, 0},
+ {1, 0, 2, 1, 5, 6, 0, 0, 2, 3},
+ {1, 0, 2, 0, 7, 8, 0, 0, 2, 2},
+ {1, 0, 0, 0, 7, 7, 1, 0, 4, 0},
+ {2, 6, 0, 0, 5, 5, 1, 0, 2, 0}};
+
+/* Subset indices:
+ Table.P2, 1 bit per index */
+static const UINT16 bc7_si2[] = {
+ 0xcccc, 0x8888, 0xeeee, 0xecc8, 0xc880, 0xfeec, 0xfec8, 0xec80, 0xc800, 0xffec,
+ 0xfe80, 0xe800, 0xffe8, 0xff00, 0xfff0, 0xf000, 0xf710, 0x008e, 0x7100, 0x08ce,
+ 0x008c, 0x7310, 0x3100, 0x8cce, 0x088c, 0x3110, 0x6666, 0x366c, 0x17e8, 0x0ff0,
+ 0x718e, 0x399c, 0xaaaa, 0xf0f0, 0x5a5a, 0x33cc, 0x3c3c, 0x55aa, 0x9696, 0xa55a,
+ 0x73ce, 0x13c8, 0x324c, 0x3bdc, 0x6996, 0xc33c, 0x9966, 0x0660, 0x0272, 0x04e4,
+ 0x4e40, 0x2720, 0xc936, 0x936c, 0x39c6, 0x639c, 0x9336, 0x9cc6, 0x817e, 0xe718,
+ 0xccf0, 0x0fcc, 0x7744, 0xee22};
+
+/* Table.P3, 2 bits per index */
+static const UINT32 bc7_si3[] = {
+ 0xaa685050, 0x6a5a5040, 0x5a5a4200, 0x5450a0a8, 0xa5a50000, 0xa0a05050, 0x5555a0a0,
+ 0x5a5a5050, 0xaa550000, 0xaa555500, 0xaaaa5500, 0x90909090, 0x94949494, 0xa4a4a4a4,
+ 0xa9a59450, 0x2a0a4250, 0xa5945040, 0x0a425054, 0xa5a5a500, 0x55a0a0a0, 0xa8a85454,
+ 0x6a6a4040, 0xa4a45000, 0x1a1a0500, 0x0050a4a4, 0xaaa59090, 0x14696914, 0x69691400,
+ 0xa08585a0, 0xaa821414, 0x50a4a450, 0x6a5a0200, 0xa9a58000, 0x5090a0a8, 0xa8a09050,
+ 0x24242424, 0x00aa5500, 0x24924924, 0x24499224, 0x50a50a50, 0x500aa550, 0xaaaa4444,
+ 0x66660000, 0xa5a0a5a0, 0x50a050a0, 0x69286928, 0x44aaaa44, 0x66666600, 0xaa444444,
+ 0x54a854a8, 0x95809580, 0x96969600, 0xa85454a8, 0x80959580, 0xaa141414, 0x96960000,
+ 0xaaaa1414, 0xa05050a0, 0xa0a5a5a0, 0x96000000, 0x40804080, 0xa9a8a9a8, 0xaaaaaa44,
+ 0x2a4a5254};
+
+/* Anchor indices:
+ Table.A2 */
+static const char bc7_ai0[] = {
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 8, 2, 2, 8,
+ 8, 15, 2, 8, 2, 2, 8, 8, 2, 2, 15, 15, 6, 8, 2, 8, 15, 15, 2, 8, 2, 2,
+ 2, 15, 15, 6, 6, 2, 6, 8, 15, 15, 2, 2, 15, 15, 15, 15, 15, 2, 2, 15};
+
+/* Table.A3a */
+static const char bc7_ai1[] = {
+ 3, 3, 15, 15, 8, 3, 15, 15, 8, 8, 6, 6, 6, 5, 3, 3, 3, 3, 8, 15, 3, 3,
+ 6, 10, 5, 8, 8, 6, 8, 5, 15, 15, 8, 15, 3, 5, 6, 10, 8, 15, 15, 3, 15, 5,
+ 15, 15, 15, 15, 3, 15, 5, 5, 5, 8, 5, 10, 5, 10, 8, 13, 15, 12, 3, 3};
+
+/* Table.A3b */
+static const char bc7_ai2[] = {15, 8, 8, 3, 15, 15, 3, 8, 15, 15, 15, 15, 15,
+ 15, 15, 8, 15, 8, 15, 3, 15, 8, 15, 8, 3, 15,
+ 6, 10, 15, 15, 10, 8, 15, 3, 15, 10, 10, 8, 9,
+ 10, 6, 15, 8, 15, 3, 6, 6, 8, 15, 3, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 3, 15, 15, 8};
+
+/* Interpolation weights */
+static const char bc7_weights2[] = {0, 21, 43, 64};
+static const char bc7_weights3[] = {0, 9, 18, 27, 37, 46, 55, 64};
+static const char bc7_weights4[] = {
+ 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64};
+
+static const char *
+bc7_get_weights(int n) {
+ if (n == 2) {
+ return bc7_weights2;
+ }
+ if (n == 3) {
+ return bc7_weights3;
+ }
+ return bc7_weights4;
+}
+
+static int
+bc7_get_subset(int ns, int partition, int n) {
+ if (ns == 2) {
+ return 1 & (bc7_si2[partition] >> n);
+ }
+ if (ns == 3) {
+ return 3 & (bc7_si3[partition] >> (2 * n));
+ }
+ return 0;
+}
+
+static UINT8
+expand_quantized(UINT8 v, int bits) {
+ v = v << (8 - bits);
+ return v | (v >> bits);
+}
+
+static void
+bc7_lerp(rgba *dst, const rgba *e, int s0, int s1) {
+ int t0 = 64 - s0;
+ int t1 = 64 - s1;
+ dst->r = (UINT8)((t0 * e[0].r + s0 * e[1].r + 32) >> 6);
+ dst->g = (UINT8)((t0 * e[0].g + s0 * e[1].g + 32) >> 6);
+ dst->b = (UINT8)((t0 * e[0].b + s0 * e[1].b + 32) >> 6);
+ dst->a = (UINT8)((t1 * e[0].a + s1 * e[1].a + 32) >> 6);
+}
+
+static void
+decode_bc7_block(rgba *col, const UINT8 *src) {
+ rgba endpoints[6];
+ int bit = 0, cibit, aibit;
+ int mode = src[0];
+ int i, j;
+ int numep, cb, ab, ib, ib2, i0, i1, s;
+ UINT8 index_sel, partition, rotation, val;
+ const char *cw, *aw;
+ const bc7_mode_info *info;
+
+ /* mode is the number of unset bits before the first set bit: */
+ if (!mode) {
+ /* degenerate case when no bits set */
+ for (i = 0; i < 16; i++) {
+ col[i].r = col[i].g = col[i].b = 0;
+ col[i].a = 255;
+ }
+ return;
+ }
+ while (!(mode & (1 << bit++)))
+ ;
+ mode = bit - 1;
+ info = &bc7_modes[mode];
+ /* color selection bits: {subset}{endpoint} */
+ cb = info->cb;
+ ab = info->ab;
+ cw = bc7_get_weights(info->ib);
+ aw = bc7_get_weights((ab && info->ib2) ? info->ib2 : info->ib);
+
+#define LOAD(DST, N) \
+ DST = get_bits(src, bit, N); \
+ bit += N;
+ LOAD(partition, info->pb);
+ LOAD(rotation, info->rb);
+ LOAD(index_sel, info->isb);
+ numep = info->ns << 1;
+
+ /* red */
+ for (i = 0; i < numep; i++) {
+ LOAD(val, cb);
+ endpoints[i].r = val;
+ }
+
+ /* green */
+ for (i = 0; i < numep; i++) {
+ LOAD(val, cb);
+ endpoints[i].g = val;
+ }
+
+ /* blue */
+ for (i = 0; i < numep; i++) {
+ LOAD(val, cb);
+ endpoints[i].b = val;
+ }
+
+ /* alpha */
+ for (i = 0; i < numep; i++) {
+ if (ab) {
+ LOAD(val, ab);
+ } else {
+ val = 255;
+ }
+ endpoints[i].a = val;
+ }
+
+ /* p-bits */
+#define ASSIGN_P(x) x = (x << 1) | val
+ if (info->epb) {
+ /* per endpoint */
+ cb++;
+ if (ab) {
+ ab++;
+ }
+ for (i = 0; i < numep; i++) {
+ LOAD(val, 1);
+ ASSIGN_P(endpoints[i].r);
+ ASSIGN_P(endpoints[i].g);
+ ASSIGN_P(endpoints[i].b);
+ if (ab) {
+ ASSIGN_P(endpoints[i].a);
+ }
+ }
+ }
+ if (info->spb) {
+ /* per subset */
+ cb++;
+ if (ab) {
+ ab++;
+ }
+ for (i = 0; i < numep; i += 2) {
+ LOAD(val, 1);
+ for (j = 0; j < 2; j++) {
+ ASSIGN_P(endpoints[i + j].r);
+ ASSIGN_P(endpoints[i + j].g);
+ ASSIGN_P(endpoints[i + j].b);
+ if (ab) {
+ ASSIGN_P(endpoints[i + j].a);
+ }
+ }
+ }
+ }
+#undef ASSIGN_P
+#define EXPAND(x, b) x = expand_quantized(x, b)
+ for (i = 0; i < numep; i++) {
+ EXPAND(endpoints[i].r, cb);
+ EXPAND(endpoints[i].g, cb);
+ EXPAND(endpoints[i].b, cb);
+ if (ab) {
+ EXPAND(endpoints[i].a, ab);
+ }
+ }
+#undef EXPAND
+#undef LOAD
+ cibit = bit;
+ aibit = cibit + 16 * info->ib - info->ns;
+ for (i = 0; i < 16; i++) {
+ s = bc7_get_subset(info->ns, partition, i) << 1;
+ ib = info->ib;
+ if (i == 0) {
+ ib--;
+ } else if (info->ns == 2) {
+ if (i == bc7_ai0[partition]) {
+ ib--;
+ }
+ } else if (info->ns == 3) {
+ if (i == bc7_ai1[partition]) {
+ ib--;
+ } else if (i == bc7_ai2[partition]) {
+ ib--;
+ }
+ }
+ i0 = get_bits(src, cibit, ib);
+ cibit += ib;
+
+ if (ab && info->ib2) {
+ ib2 = info->ib2;
+ if (ib2 && i == 0) {
+ ib2--;
+ }
+ i1 = get_bits(src, aibit, ib2);
+ aibit += ib2;
+ if (index_sel) {
+ bc7_lerp(&col[i], &endpoints[s], aw[i1], cw[i0]);
+ } else {
+ bc7_lerp(&col[i], &endpoints[s], cw[i0], aw[i1]);
+ }
+ } else {
+ bc7_lerp(&col[i], &endpoints[s], cw[i0], cw[i0]);
+ }
+#define ROTATE(x, y) \
+ val = x; \
+ x = y; \
+ y = val
+ if (rotation == 1) {
+ ROTATE(col[i].r, col[i].a);
+ } else if (rotation == 2) {
+ ROTATE(col[i].g, col[i].a);
+ } else if (rotation == 3) {
+ ROTATE(col[i].b, col[i].a);
+ }
+#undef ROTATE
+ }
+}
+
+/* BC6 */
+typedef struct {
+ char ns; /* number of subsets (also called regions) */
+ char tr; /* whether endpoints are delta-compressed */
+ char pb; /* partition bits */
+ char epb; /* endpoint bits */
+ char rb; /* red bits (delta) */
+ char gb; /* green bits (delta) */
+ char bb; /* blue bits (delta) */
+} bc6_mode_info;
+
+static const bc6_mode_info bc6_modes[] = {
+ // 00
+ {2, 1, 5, 10, 5, 5, 5},
+ // 01
+ {2, 1, 5, 7, 6, 6, 6},
+ // 10
+ {2, 1, 5, 11, 5, 4, 4},
+ {2, 1, 5, 11, 4, 5, 4},
+ {2, 1, 5, 11, 4, 4, 5},
+ {2, 1, 5, 9, 5, 5, 5},
+ {2, 1, 5, 8, 6, 5, 5},
+ {2, 1, 5, 8, 5, 6, 5},
+ {2, 1, 5, 8, 5, 5, 6},
+ {2, 0, 5, 6, 6, 6, 6},
+ // 11
+ {1, 0, 0, 10, 10, 10, 10},
+ {1, 1, 0, 11, 9, 9, 9},
+ {1, 1, 0, 12, 8, 8, 8},
+ {1, 1, 0, 16, 4, 4, 4}};
+
+/* Table.F, encoded as a sequence of bit indices */
+static const UINT8 bc6_bit_packings[][75] = {
+ {116, 132, 180, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 48, 49, 50, 51, 52, 164, 112, 113, 114, 115, 64, 65,
+ 66, 67, 68, 176, 160, 161, 162, 163, 80, 81, 82, 83, 84, 177, 128,
+ 129, 130, 131, 96, 97, 98, 99, 100, 178, 144, 145, 146, 147, 148, 179},
+ {117, 164, 165, 0, 1, 2, 3, 4, 5, 6, 176, 177, 132, 16, 17,
+ 18, 19, 20, 21, 22, 133, 178, 116, 32, 33, 34, 35, 36, 37, 38,
+ 179, 181, 180, 48, 49, 50, 51, 52, 53, 112, 113, 114, 115, 64, 65,
+ 66, 67, 68, 69, 160, 161, 162, 163, 80, 81, 82, 83, 84, 85, 128,
+ 129, 130, 131, 96, 97, 98, 99, 100, 101, 144, 145, 146, 147, 148, 149},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 48, 49, 50, 51, 52, 10, 112, 113, 114, 115, 64, 65, 66, 67, 26,
+ 176, 160, 161, 162, 163, 80, 81, 82, 83, 42, 177, 128, 129, 130, 131,
+ 96, 97, 98, 99, 100, 178, 144, 145, 146, 147, 148, 179},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 48, 49, 50, 51, 10, 164, 112, 113, 114, 115, 64, 65, 66, 67, 68,
+ 26, 160, 161, 162, 163, 80, 81, 82, 83, 42, 177, 128, 129, 130, 131,
+ 96, 97, 98, 99, 176, 178, 144, 145, 146, 147, 116, 179},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 48, 49, 50, 51, 10, 132, 112, 113, 114, 115, 64, 65, 66, 67, 26,
+ 176, 160, 161, 162, 163, 80, 81, 82, 83, 84, 42, 128, 129, 130, 131,
+ 96, 97, 98, 99, 177, 178, 144, 145, 146, 147, 180, 179},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 132, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 116, 32, 33, 34, 35, 36, 37, 38, 39, 40, 180,
+ 48, 49, 50, 51, 52, 164, 112, 113, 114, 115, 64, 65, 66, 67, 68,
+ 176, 160, 161, 162, 163, 80, 81, 82, 83, 84, 177, 128, 129, 130, 131,
+ 96, 97, 98, 99, 100, 178, 144, 145, 146, 147, 148, 179},
+ {0, 1, 2, 3, 4, 5, 6, 7, 164, 132, 16, 17, 18, 19, 20,
+ 21, 22, 23, 178, 116, 32, 33, 34, 35, 36, 37, 38, 39, 179, 180,
+ 48, 49, 50, 51, 52, 53, 112, 113, 114, 115, 64, 65, 66, 67, 68,
+ 176, 160, 161, 162, 163, 80, 81, 82, 83, 84, 177, 128, 129, 130, 131,
+ 96, 97, 98, 99, 100, 101, 144, 145, 146, 147, 148, 149},
+ {0, 1, 2, 3, 4, 5, 6, 7, 176, 132, 16, 17, 18, 19, 20,
+ 21, 22, 23, 117, 116, 32, 33, 34, 35, 36, 37, 38, 39, 165, 180,
+ 48, 49, 50, 51, 52, 164, 112, 113, 114, 115, 64, 65, 66, 67, 68,
+ 69, 160, 161, 162, 163, 80, 81, 82, 83, 84, 177, 128, 129, 130, 131,
+ 96, 97, 98, 99, 100, 178, 144, 145, 146, 147, 148, 179},
+ {0, 1, 2, 3, 4, 5, 6, 7, 177, 132, 16, 17, 18, 19, 20,
+ 21, 22, 23, 133, 116, 32, 33, 34, 35, 36, 37, 38, 39, 181, 180,
+ 48, 49, 50, 51, 52, 164, 112, 113, 114, 115, 64, 65, 66, 67, 68,
+ 176, 160, 161, 162, 163, 80, 81, 82, 83, 84, 85, 128, 129, 130, 131,
+ 96, 97, 98, 99, 100, 178, 144, 145, 146, 147, 148, 179},
+ {0, 1, 2, 3, 4, 5, 164, 176, 177, 132, 16, 17, 18, 19, 20,
+ 21, 117, 133, 178, 116, 32, 33, 34, 35, 36, 37, 165, 179, 181, 180,
+ 48, 49, 50, 51, 52, 53, 112, 113, 114, 115, 64, 65, 66, 67, 68,
+ 69, 160, 161, 162, 163, 80, 81, 82, 83, 84, 85, 128, 129, 130, 131,
+ 96, 97, 98, 99, 100, 101, 144, 145, 146, 147, 148, 149},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 56, 10,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 26, 80, 81, 82, 83, 84, 85, 86, 87, 88, 42},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 11, 10,
+ 64, 65, 66, 67, 68, 69, 70, 71, 27, 26, 80, 81, 82, 83, 84, 85, 86, 87, 43, 42},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 15, 14, 13, 12, 11, 10,
+ 64, 65, 66, 67, 31, 30, 29, 28, 27, 26, 80, 81, 82, 83, 47, 46, 45, 44, 43, 42}};
+
+static void
+bc6_sign_extend(UINT16 *v, int prec) {
+ int x = *v;
+ if (x & (1 << (prec - 1))) {
+ x |= -1 << prec;
+ }
+ *v = (UINT16)x;
+}
+
+static int
+bc6_unquantize(UINT16 v, int prec, int sign) {
+ int s = 0;
+ int x;
+ if (!sign) {
+ x = v;
+ if (prec >= 15) {
+ return x;
+ }
+ if (x == 0) {
+ return 0;
+ }
+ if (x == ((1 << prec) - 1)) {
+ return 0xffff;
+ }
+ return ((x << 15) + 0x4000) >> (prec - 1);
+ } else {
+ x = (INT16)v;
+ if (prec >= 16) {
+ return x;
+ }
+ if (x < 0) {
+ s = 1;
+ x = -x;
+ }
+
+ if (x != 0) {
+ if (x >= ((1 << (prec - 1)) - 1)) {
+ x = 0x7fff;
+ } else {
+ x = ((x << 15) + 0x4000) >> (prec - 1);
+ }
+ }
+
+ if (s) {
+ return -x;
+ }
+ return x;
+ }
+}
+
+static float
+half_to_float(UINT16 h) {
+ /* https://gist.github.com/rygorous/2144712 */
+ union {
+ UINT32 u;
+ float f;
+ } o, m;
+ m.u = 0x77800000;
+ o.u = (h & 0x7fff) << 13;
+ o.f *= m.f;
+ m.u = 0x47800000;
+ if (o.f >= m.f) {
+ o.u |= 255 << 23;
+ }
+ o.u |= (h & 0x8000) << 16;
+ return o.f;
+}
+
+static float
+bc6_finalize(int v, int sign) {
+ if (sign) {
+ if (v < 0) {
+ v = ((-v) * 31) / 32;
+ return half_to_float((UINT16)(0x8000 | v));
+ } else {
+ return half_to_float((UINT16)((v * 31) / 32));
+ }
+ } else {
+ return half_to_float((UINT16)((v * 31) / 64));
+ }
+}
+
+static UINT8
+bc6_clamp(float value) {
+ if (value < 0.0f) {
+ return 0;
+ } else if (value > 1.0f) {
+ return 255;
+ } else {
+ return (UINT8) (value * 255.0f);
+ }
+}
+
+static void
+bc6_lerp(rgba *col, int *e0, int *e1, int s, int sign) {
+ int r, g, b;
+ int t = 64 - s;
+ r = (e0[0] * t + e1[0] * s) >> 6;
+ g = (e0[1] * t + e1[1] * s) >> 6;
+ b = (e0[2] * t + e1[2] * s) >> 6;
+ col->r = bc6_clamp(bc6_finalize(r, sign));
+ col->g = bc6_clamp(bc6_finalize(g, sign));
+ col->b = bc6_clamp(bc6_finalize(b, sign));
+}
+
+static void
+decode_bc6_block(rgba *col, const UINT8 *src, int sign) {
+ UINT16 endpoints[12]; /* storage for r0, g0, b0, r1, ... */
+ int ueps[12];
+ int i, i0, ib2, di, dw, mask, numep, s;
+ UINT8 partition;
+ const bc6_mode_info *info;
+ const char *cw;
+ int bit = 5;
+ int epbits = 75;
+ int ib = 3;
+ int mode = src[0] & 0x1f;
+ if ((mode & 3) == 0 || (mode & 3) == 1) {
+ mode &= 3;
+ bit = 2;
+ } else if ((mode & 3) == 2) {
+ mode = 2 + (mode >> 2);
+ epbits = 72;
+ } else {
+ mode = 10 + (mode >> 2);
+ epbits = 60;
+ ib = 4;
+ }
+ if (mode >= 14) {
+ /* invalid block */
+ memset(col, 0, 16 * sizeof(col[0]));
+ return;
+ }
+ info = &bc6_modes[mode];
+ cw = bc7_get_weights(ib);
+ numep = info->ns == 2 ? 12 : 6;
+ for (i = 0; i < 12; i++) {
+ endpoints[i] = 0;
+ }
+ for (i = 0; i < epbits; i++) {
+ di = bc6_bit_packings[mode][i];
+ dw = di >> 4;
+ di &= 15;
+ endpoints[dw] |= (UINT16)get_bit(src, bit + i) << di;
+ }
+ bit += epbits;
+ partition = get_bits(src, bit, info->pb);
+ bit += info->pb;
+ mask = (1 << info->epb) - 1;
+ if (sign) { /* sign-extend e0 if signed */
+ bc6_sign_extend(&endpoints[0], info->epb);
+ bc6_sign_extend(&endpoints[1], info->epb);
+ bc6_sign_extend(&endpoints[2], info->epb);
+ }
+ if (sign || info->tr) { /* sign-extend e1,2,3 if signed or deltas */
+ for (i = 3; i < numep; i += 3) {
+ bc6_sign_extend(&endpoints[i], info->rb);
+ bc6_sign_extend(&endpoints[i + 1], info->gb);
+ bc6_sign_extend(&endpoints[i + 2], info->bb);
+ }
+ }
+ if (info->tr) { /* apply deltas */
+ for (i = 3; i < numep; i += 3) {
+ endpoints[i] = (endpoints[i] + endpoints[0]) & mask;
+ endpoints[i + 1] = (endpoints[i + 1] + endpoints[1]) & mask;
+ endpoints[i + 2] = (endpoints[i + 2] + endpoints[2]) & mask;
+ }
+ }
+ for (i = 0; i < numep; i++) {
+ ueps[i] = bc6_unquantize(endpoints[i], info->epb, sign);
+ }
+ for (i = 0; i < 16; i++) {
+ s = bc7_get_subset(info->ns, partition, i) * 6;
+ ib2 = ib;
+ if (i == 0) {
+ ib2--;
+ } else if (info->ns == 2) {
+ if (i == bc7_ai0[partition]) {
+ ib2--;
+ }
+ }
+ i0 = get_bits(src, bit, ib2);
+ bit += ib2;
+
+ bc6_lerp(&col[i], &ueps[s], &ueps[s + 3], cw[i0], sign);
+ }
+}
+
+static void
+put_block(Imaging im, ImagingCodecState state, const char *col, int sz, int C) {
+ int width = state->xsize;
+ int height = state->ysize;
+ int xmax = width + state->xoff;
+ int ymax = height + state->yoff;
+ int j, i, y, x;
+ char *dst;
+ for (j = 0; j < 4; j++) {
+ y = state->y + j;
+ if (C) {
+ if (y >= height) {
+ continue;
+ }
+ if (state->ystep < 0) {
+ y = state->yoff + ymax - y - 1;
+ }
+ dst = im->image[y];
+ for (i = 0; i < 4; i++) {
+ x = state->x + i;
+ if (x >= width) {
+ continue;
+ }
+ memcpy(dst + sz * x, col + sz * (j * 4 + i), sz);
+ }
+ } else {
+ if (state->ystep < 0) {
+ y = state->yoff + ymax - y - 1;
+ }
+ x = state->x;
+ dst = im->image[y] + sz * x;
+ memcpy(dst, col + sz * (j * 4), 4 * sz);
+ }
+ }
+ state->x += 4;
+ if (state->x >= xmax) {
+ state->y += 4;
+ state->x = state->xoff;
+ }
+}
+
+static int
+decode_bcn(
+ Imaging im, ImagingCodecState state, const UINT8 *src, int bytes, int N, int C, char *pixel_format) {
+ int ymax = state->ysize + state->yoff;
+ const UINT8 *ptr = src;
+ switch (N) {
+#define DECODE_LOOP(NN, SZ, TY, ...) \
+ case NN: \
+ while (bytes >= SZ) { \
+ TY col[16]; \
+ memset(col, 0, 16 * sizeof(col[0])); \
+ decode_bc##NN##_block(col, ptr); \
+ put_block(im, state, (const char *)col, sizeof(col[0]), C); \
+ ptr += SZ; \
+ bytes -= SZ; \
+ if (state->y >= ymax) { \
+ return -1; \
+ } \
+ } \
+ break
+
+ DECODE_LOOP(1, 8, rgba);
+ DECODE_LOOP(2, 16, rgba);
+ DECODE_LOOP(3, 16, rgba);
+ DECODE_LOOP(4, 8, lum);
+ case 5:
+ {
+ int sign = strcmp(pixel_format, "BC5S") == 0 ? 1 : 0;
+ while (bytes >= 16) {
+ rgba col[16];
+ memset(col, sign ? 128 : 0, 16 * sizeof(col[0]));
+ decode_bc5_block(col, ptr, sign);
+ put_block(im, state, (const char *)col, sizeof(col[0]), C);
+ ptr += 16;
+ bytes -= 16;
+ if (state->y >= ymax) {
+ return -1;
+ }
+ }
+ break;
+ }
+ case 6:
+ {
+ int sign = strcmp(pixel_format, "BC6HS") == 0 ? 1 : 0;
+ while (bytes >= 16) {
+ rgba col[16];
+ decode_bc6_block(col, ptr, sign);
+ put_block(im, state, (const char *)col, sizeof(col[0]), C);
+ ptr += 16;
+ bytes -= 16;
+ if (state->y >= ymax) {
+ return -1;
+ }
+ }
+ break;
+ }
+ DECODE_LOOP(7, 16, rgba);
+#undef DECODE_LOOP
+ }
+ return (int)(ptr - src);
+}
+
+int
+ImagingBcnDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ int N = state->state & 0xf;
+ int width = state->xsize;
+ int height = state->ysize;
+ int C = (width & 3) | (height & 3) ? 1 : 0;
+ char *pixel_format = ((BCNSTATE *)state->context)->pixel_format;
+ return decode_bcn(im, state, buf, bytes, N, C, pixel_format);
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Bit.h b/contrib/python/Pillow/py3/libImaging/Bit.h
new file mode 100644
index 00000000000..f64bfb46990
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Bit.h
@@ -0,0 +1,29 @@
+/* Bit.h */
+
+typedef struct {
+ /* CONFIGURATION */
+
+ /* Number of bits per pixel */
+ int bits;
+
+ /* Line padding (0 or 8) */
+ int pad;
+
+ /* Fill order */
+ /* 0=msb/msb, 1=msbfill/lsbshift, 2=lsbfill/msbshift, 3=lsb/lsb */
+ int fill;
+
+ /* Signed integers (0=unsigned, 1=signed) */
+ int sign;
+
+ /* Lookup table (not implemented) */
+ unsigned long lutsize;
+ FLOAT32 *lut;
+
+ /* INTERNAL */
+ unsigned long mask;
+ unsigned long signmask;
+ unsigned long bitbuffer;
+ int bitcount;
+
+} BITSTATE;
diff --git a/contrib/python/Pillow/py3/libImaging/BitDecode.c b/contrib/python/Pillow/py3/libImaging/BitDecode.c
new file mode 100644
index 00000000000..28baa8b7ea8
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/BitDecode.c
@@ -0,0 +1,138 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for packed bitfields (converts to floating point)
+ *
+ * history:
+ * 97-05-31 fl created (much more than originally intended)
+ *
+ * Copyright (c) Fredrik Lundh 1997.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#include "Bit.h"
+
+int
+ImagingBitDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ BITSTATE *bitstate = state->context;
+ UINT8 *ptr;
+
+ if (state->state == 0) {
+ /* Initialize context variables */
+
+ /* this decoder only works for float32 image buffers */
+ if (im->type != IMAGING_TYPE_FLOAT32) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+
+ /* sanity check */
+ if (bitstate->bits < 1 || bitstate->bits >= 32) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+
+ bitstate->mask = (1 << bitstate->bits) - 1;
+
+ if (bitstate->sign) {
+ bitstate->signmask = (1 << (bitstate->bits - 1));
+ }
+
+ /* check image orientation */
+ if (state->ystep < 0) {
+ state->y = state->ysize - 1;
+ state->ystep = -1;
+ } else {
+ state->ystep = 1;
+ }
+
+ state->state = 1;
+ }
+
+ ptr = buf;
+
+ while (bytes > 0) {
+ UINT8 byte = *ptr;
+
+ ptr++;
+ bytes--;
+
+ /* get a byte from the input stream and insert in the bit buffer */
+ if (bitstate->fill & 1) {
+ /* fill MSB first */
+ bitstate->bitbuffer |= (unsigned long)byte << bitstate->bitcount;
+ } else {
+ /* fill LSB first */
+ bitstate->bitbuffer = (bitstate->bitbuffer << 8) | byte;
+ }
+
+ bitstate->bitcount += 8;
+
+ while (bitstate->bitcount >= bitstate->bits) {
+ /* get a pixel from the bit buffer */
+ unsigned long data;
+ FLOAT32 pixel;
+
+ if (bitstate->fill & 2) {
+ /* store LSB first */
+ data = bitstate->bitbuffer & bitstate->mask;
+ if (bitstate->bitcount > 32) {
+ /* bitbuffer overflow; restore it from last input byte */
+ bitstate->bitbuffer =
+ byte >> (8 - (bitstate->bitcount - bitstate->bits));
+ } else {
+ bitstate->bitbuffer >>= bitstate->bits;
+ }
+ } else {
+ /* store MSB first */
+ data = (bitstate->bitbuffer >> (bitstate->bitcount - bitstate->bits)) &
+ bitstate->mask;
+ }
+
+ bitstate->bitcount -= bitstate->bits;
+
+ if (bitstate->lutsize > 0) {
+ /* map through lookup table */
+ if (data <= 0) {
+ pixel = bitstate->lut[0];
+ } else if (data >= bitstate->lutsize) {
+ pixel = bitstate->lut[bitstate->lutsize - 1];
+ } else {
+ pixel = bitstate->lut[data];
+ }
+ } else {
+ /* convert */
+ if (data & bitstate->signmask) {
+ /* image memory contains signed data */
+ pixel = (FLOAT32)(INT32)(data | ~bitstate->mask);
+ } else {
+ pixel = (FLOAT32)data;
+ }
+ }
+
+ *(FLOAT32 *)(&im->image32[state->y][state->x]) = pixel;
+
+ /* step forward */
+ if (++state->x >= state->xsize) {
+ /* new line */
+ state->y += state->ystep;
+ if (state->y < 0 || state->y >= state->ysize) {
+ /* end of file (errcode = 0) */
+ return -1;
+ }
+ state->x = 0;
+ /* reset bit buffer */
+ if (bitstate->pad > 0) {
+ bitstate->bitcount = 0;
+ }
+ }
+ }
+ }
+
+ return ptr - buf;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Blend.c b/contrib/python/Pillow/py3/libImaging/Blend.c
new file mode 100644
index 00000000000..a53ae0fad53
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Blend.c
@@ -0,0 +1,79 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * interpolate between two existing images
+ *
+ * history:
+ * 96-03-20 fl Created
+ * 96-05-18 fl Simplified blend expression
+ * 96-10-05 fl Fixed expression bug, special case for interpolation
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+Imaging
+ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha) {
+ Imaging imOut;
+ int x, y;
+
+ /* Check arguments */
+ if (!imIn1 || !imIn2 || imIn1->type != IMAGING_TYPE_UINT8 || imIn1->palette ||
+ strcmp(imIn1->mode, "1") == 0 || imIn2->palette ||
+ strcmp(imIn2->mode, "1") == 0) {
+ return ImagingError_ModeError();
+ }
+
+ if (imIn1->type != imIn2->type || imIn1->bands != imIn2->bands ||
+ imIn1->xsize != imIn2->xsize || imIn1->ysize != imIn2->ysize) {
+ return ImagingError_Mismatch();
+ }
+
+ /* Shortcuts */
+ if (alpha == 0.0) {
+ return ImagingCopy(imIn1);
+ } else if (alpha == 1.0) {
+ return ImagingCopy(imIn2);
+ }
+
+ imOut = ImagingNewDirty(imIn1->mode, imIn1->xsize, imIn1->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ if (alpha >= 0 && alpha <= 1.0) {
+ /* Interpolate between bands */
+ for (y = 0; y < imIn1->ysize; y++) {
+ UINT8 *in1 = (UINT8 *)imIn1->image[y];
+ UINT8 *in2 = (UINT8 *)imIn2->image[y];
+ UINT8 *out = (UINT8 *)imOut->image[y];
+ for (x = 0; x < imIn1->linesize; x++) {
+ out[x] = (UINT8)((int)in1[x] + alpha * ((int)in2[x] - (int)in1[x]));
+ }
+ }
+ } else {
+ /* Extrapolation; must make sure to clip resulting values */
+ for (y = 0; y < imIn1->ysize; y++) {
+ UINT8 *in1 = (UINT8 *)imIn1->image[y];
+ UINT8 *in2 = (UINT8 *)imIn2->image[y];
+ UINT8 *out = (UINT8 *)imOut->image[y];
+ for (x = 0; x < imIn1->linesize; x++) {
+ float temp = (float)((int)in1[x] + alpha * ((int)in2[x] - (int)in1[x]));
+ if (temp <= 0.0) {
+ out[x] = 0;
+ } else if (temp >= 255.0) {
+ out[x] = 255;
+ } else {
+ out[x] = (UINT8)temp;
+ }
+ }
+ }
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/BoxBlur.c b/contrib/python/Pillow/py3/libImaging/BoxBlur.c
new file mode 100644
index 00000000000..adf425d0dbd
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/BoxBlur.c
@@ -0,0 +1,324 @@
+#include "Imaging.h"
+
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+
+typedef UINT8 pixel[4];
+
+void static inline ImagingLineBoxBlur32(
+ pixel *lineOut,
+ pixel *lineIn,
+ int lastx,
+ int radius,
+ int edgeA,
+ int edgeB,
+ UINT32 ww,
+ UINT32 fw) {
+ int x;
+ UINT32 acc[4];
+ UINT32 bulk[4];
+
+#define MOVE_ACC(acc, subtract, add) \
+ acc[0] += lineIn[add][0] - lineIn[subtract][0]; \
+ acc[1] += lineIn[add][1] - lineIn[subtract][1]; \
+ acc[2] += lineIn[add][2] - lineIn[subtract][2]; \
+ acc[3] += lineIn[add][3] - lineIn[subtract][3];
+
+#define ADD_FAR(bulk, acc, left, right) \
+ bulk[0] = (acc[0] * ww) + (lineIn[left][0] + lineIn[right][0]) * fw; \
+ bulk[1] = (acc[1] * ww) + (lineIn[left][1] + lineIn[right][1]) * fw; \
+ bulk[2] = (acc[2] * ww) + (lineIn[left][2] + lineIn[right][2]) * fw; \
+ bulk[3] = (acc[3] * ww) + (lineIn[left][3] + lineIn[right][3]) * fw;
+
+#define SAVE(x, bulk) \
+ lineOut[x][0] = (UINT8)((bulk[0] + (1 << 23)) >> 24); \
+ lineOut[x][1] = (UINT8)((bulk[1] + (1 << 23)) >> 24); \
+ lineOut[x][2] = (UINT8)((bulk[2] + (1 << 23)) >> 24); \
+ lineOut[x][3] = (UINT8)((bulk[3] + (1 << 23)) >> 24);
+
+ /* Compute acc for -1 pixel (outside of image):
+ From "-radius-1" to "-1" get first pixel,
+ then from "0" to "radius-1". */
+ acc[0] = lineIn[0][0] * (radius + 1);
+ acc[1] = lineIn[0][1] * (radius + 1);
+ acc[2] = lineIn[0][2] * (radius + 1);
+ acc[3] = lineIn[0][3] * (radius + 1);
+ /* As radius can be bigger than xsize, iterate to edgeA -1. */
+ for (x = 0; x < edgeA - 1; x++) {
+ acc[0] += lineIn[x][0];
+ acc[1] += lineIn[x][1];
+ acc[2] += lineIn[x][2];
+ acc[3] += lineIn[x][3];
+ }
+ /* Then multiply remainder to last x. */
+ acc[0] += lineIn[lastx][0] * (radius - edgeA + 1);
+ acc[1] += lineIn[lastx][1] * (radius - edgeA + 1);
+ acc[2] += lineIn[lastx][2] * (radius - edgeA + 1);
+ acc[3] += lineIn[lastx][3] * (radius - edgeA + 1);
+
+ if (edgeA <= edgeB) {
+ /* Subtract pixel from left ("0").
+ Add pixels from radius. */
+ for (x = 0; x < edgeA; x++) {
+ MOVE_ACC(acc, 0, x + radius);
+ ADD_FAR(bulk, acc, 0, x + radius + 1);
+ SAVE(x, bulk);
+ }
+ /* Subtract previous pixel from "-radius".
+ Add pixels from radius. */
+ for (x = edgeA; x < edgeB; x++) {
+ MOVE_ACC(acc, x - radius - 1, x + radius);
+ ADD_FAR(bulk, acc, x - radius - 1, x + radius + 1);
+ SAVE(x, bulk);
+ }
+ /* Subtract previous pixel from "-radius".
+ Add last pixel. */
+ for (x = edgeB; x <= lastx; x++) {
+ MOVE_ACC(acc, x - radius - 1, lastx);
+ ADD_FAR(bulk, acc, x - radius - 1, lastx);
+ SAVE(x, bulk);
+ }
+ } else {
+ for (x = 0; x < edgeB; x++) {
+ MOVE_ACC(acc, 0, x + radius);
+ ADD_FAR(bulk, acc, 0, x + radius + 1);
+ SAVE(x, bulk);
+ }
+ for (x = edgeB; x < edgeA; x++) {
+ MOVE_ACC(acc, 0, lastx);
+ ADD_FAR(bulk, acc, 0, lastx);
+ SAVE(x, bulk);
+ }
+ for (x = edgeA; x <= lastx; x++) {
+ MOVE_ACC(acc, x - radius - 1, lastx);
+ ADD_FAR(bulk, acc, x - radius - 1, lastx);
+ SAVE(x, bulk);
+ }
+ }
+
+#undef MOVE_ACC
+#undef ADD_FAR
+#undef SAVE
+}
+
+void static inline ImagingLineBoxBlur8(
+ UINT8 *lineOut,
+ UINT8 *lineIn,
+ int lastx,
+ int radius,
+ int edgeA,
+ int edgeB,
+ UINT32 ww,
+ UINT32 fw) {
+ int x;
+ UINT32 acc;
+ UINT32 bulk;
+
+#define MOVE_ACC(acc, subtract, add) acc += lineIn[add] - lineIn[subtract];
+
+#define ADD_FAR(bulk, acc, left, right) \
+ bulk = (acc * ww) + (lineIn[left] + lineIn[right]) * fw;
+
+#define SAVE(x, bulk) lineOut[x] = (UINT8)((bulk + (1 << 23)) >> 24)
+
+ acc = lineIn[0] * (radius + 1);
+ for (x = 0; x < edgeA - 1; x++) {
+ acc += lineIn[x];
+ }
+ acc += lineIn[lastx] * (radius - edgeA + 1);
+
+ if (edgeA <= edgeB) {
+ for (x = 0; x < edgeA; x++) {
+ MOVE_ACC(acc, 0, x + radius);
+ ADD_FAR(bulk, acc, 0, x + radius + 1);
+ SAVE(x, bulk);
+ }
+ for (x = edgeA; x < edgeB; x++) {
+ MOVE_ACC(acc, x - radius - 1, x + radius);
+ ADD_FAR(bulk, acc, x - radius - 1, x + radius + 1);
+ SAVE(x, bulk);
+ }
+ for (x = edgeB; x <= lastx; x++) {
+ MOVE_ACC(acc, x - radius - 1, lastx);
+ ADD_FAR(bulk, acc, x - radius - 1, lastx);
+ SAVE(x, bulk);
+ }
+ } else {
+ for (x = 0; x < edgeB; x++) {
+ MOVE_ACC(acc, 0, x + radius);
+ ADD_FAR(bulk, acc, 0, x + radius + 1);
+ SAVE(x, bulk);
+ }
+ for (x = edgeB; x < edgeA; x++) {
+ MOVE_ACC(acc, 0, lastx);
+ ADD_FAR(bulk, acc, 0, lastx);
+ SAVE(x, bulk);
+ }
+ for (x = edgeA; x <= lastx; x++) {
+ MOVE_ACC(acc, x - radius - 1, lastx);
+ ADD_FAR(bulk, acc, x - radius - 1, lastx);
+ SAVE(x, bulk);
+ }
+ }
+
+#undef MOVE_ACC
+#undef ADD_FAR
+#undef SAVE
+}
+
+Imaging
+ImagingHorizontalBoxBlur(Imaging imOut, Imaging imIn, float floatRadius) {
+ ImagingSectionCookie cookie;
+
+ int y;
+
+ int radius = (int)floatRadius;
+ UINT32 ww = (UINT32)(1 << 24) / (floatRadius * 2 + 1);
+ UINT32 fw = ((1 << 24) - (radius * 2 + 1) * ww) / 2;
+
+ int edgeA = MIN(radius + 1, imIn->xsize);
+ int edgeB = MAX(imIn->xsize - radius - 1, 0);
+
+ UINT32 *lineOut = calloc(imIn->xsize, sizeof(UINT32));
+ if (lineOut == NULL) {
+ return ImagingError_MemoryError();
+ }
+
+ // printf(">>> %d %d %d\n", radius, ww, fw);
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ for (y = 0; y < imIn->ysize; y++) {
+ ImagingLineBoxBlur8(
+ (imIn == imOut ? (UINT8 *)lineOut : imOut->image8[y]),
+ imIn->image8[y],
+ imIn->xsize - 1,
+ radius,
+ edgeA,
+ edgeB,
+ ww,
+ fw);
+ if (imIn == imOut) {
+ // Commit.
+ memcpy(imOut->image8[y], lineOut, imIn->xsize);
+ }
+ }
+ } else {
+ for (y = 0; y < imIn->ysize; y++) {
+ ImagingLineBoxBlur32(
+ imIn == imOut ? (pixel *)lineOut : (pixel *)imOut->image32[y],
+ (pixel *)imIn->image32[y],
+ imIn->xsize - 1,
+ radius,
+ edgeA,
+ edgeB,
+ ww,
+ fw);
+ if (imIn == imOut) {
+ // Commit.
+ memcpy(imOut->image32[y], lineOut, imIn->xsize * 4);
+ }
+ }
+ }
+
+ ImagingSectionLeave(&cookie);
+
+ free(lineOut);
+
+ return imOut;
+}
+
+Imaging
+ImagingBoxBlur(Imaging imOut, Imaging imIn, float xradius, float yradius, int n) {
+ int i;
+ Imaging imTransposed;
+
+ if (n < 1) {
+ return ImagingError_ValueError("number of passes must be greater than zero");
+ }
+ if (xradius < 0 || yradius < 0) {
+ return ImagingError_ValueError("radius must be >= 0");
+ }
+
+ if (strcmp(imIn->mode, imOut->mode) || imIn->type != imOut->type ||
+ imIn->bands != imOut->bands || imIn->xsize != imOut->xsize ||
+ imIn->ysize != imOut->ysize) {
+ return ImagingError_Mismatch();
+ }
+
+ if (imIn->type != IMAGING_TYPE_UINT8) {
+ return ImagingError_ModeError();
+ }
+
+ if (!(strcmp(imIn->mode, "RGB") == 0 || strcmp(imIn->mode, "RGBA") == 0 ||
+ strcmp(imIn->mode, "RGBa") == 0 || strcmp(imIn->mode, "RGBX") == 0 ||
+ strcmp(imIn->mode, "CMYK") == 0 || strcmp(imIn->mode, "L") == 0 ||
+ strcmp(imIn->mode, "LA") == 0 || strcmp(imIn->mode, "La") == 0)) {
+ return ImagingError_ModeError();
+ }
+
+ /* Apply blur in one dimension.
+ Use imOut as a destination at first pass,
+ then use imOut as a source too. */
+
+ if (xradius != 0) {
+ ImagingHorizontalBoxBlur(imOut, imIn, xradius);
+ for (i = 1; i < n; i++) {
+ ImagingHorizontalBoxBlur(imOut, imOut, xradius);
+ }
+ }
+ if (yradius != 0) {
+ imTransposed = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize);
+ if (!imTransposed) {
+ return NULL;
+ }
+
+ /* Transpose result for blur in another direction. */
+ ImagingTranspose(imTransposed, xradius == 0 ? imIn : imOut);
+
+ /* Reuse imTransposed as a source and destination there. */
+ for (i = 0; i < n; i++) {
+ ImagingHorizontalBoxBlur(imTransposed, imTransposed, yradius);
+ }
+ /* Restore original orientation. */
+ ImagingTranspose(imOut, imTransposed);
+
+ ImagingDelete(imTransposed);
+ }
+ if (xradius == 0 && yradius == 0) {
+ if (!ImagingCopy2(imOut, imIn)) {
+ return NULL;
+ }
+ }
+
+ return imOut;
+}
+
+static float
+_gaussian_blur_radius(float radius, int passes) {
+ float sigma2, L, l, a;
+
+ sigma2 = radius * radius / passes;
+ // from https://www.mia.uni-saarland.de/Publications/gwosdek-ssvm11.pdf
+ // [7] Box length.
+ L = sqrt(12.0 * sigma2 + 1.0);
+ // [11] Integer part of box radius.
+ l = floor((L - 1.0) / 2.0);
+ // [14], [Fig. 2] Fractional part of box radius.
+ a = (2 * l + 1) * (l * (l + 1) - 3 * sigma2);
+ a /= 6 * (sigma2 - (l + 1) * (l + 1));
+
+ return l + a;
+}
+
+Imaging
+ImagingGaussianBlur(Imaging imOut, Imaging imIn, float xradius, float yradius, int passes) {
+ return ImagingBoxBlur(
+ imOut,
+ imIn,
+ _gaussian_blur_radius(xradius, passes),
+ _gaussian_blur_radius(yradius, passes),
+ passes
+ );
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Chops.c b/contrib/python/Pillow/py3/libImaging/Chops.c
new file mode 100644
index 00000000000..f9c005efe3a
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Chops.c
@@ -0,0 +1,162 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * basic channel operations
+ *
+ * history:
+ * 1996-03-28 fl Created
+ * 1996-08-13 fl Added and/or/xor for "1" images
+ * 1996-12-14 fl Added add_modulo, sub_modulo
+ * 2005-09-10 fl Fixed output values from and/or/xor
+ *
+ * Copyright (c) 1996 by Fredrik Lundh.
+ * Copyright (c) 1997 by Secret Labs AB.
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#define CHOP(operation) \
+ int x, y; \
+ Imaging imOut; \
+ imOut = create(imIn1, imIn2, NULL); \
+ if (!imOut) { \
+ return NULL; \
+ } \
+ for (y = 0; y < imOut->ysize; y++) { \
+ UINT8 *out = (UINT8 *)imOut->image[y]; \
+ UINT8 *in1 = (UINT8 *)imIn1->image[y]; \
+ UINT8 *in2 = (UINT8 *)imIn2->image[y]; \
+ for (x = 0; x < imOut->linesize; x++) { \
+ int temp = operation; \
+ if (temp <= 0) { \
+ out[x] = 0; \
+ } else if (temp >= 255) { \
+ out[x] = 255; \
+ } else { \
+ out[x] = temp; \
+ } \
+ } \
+ } \
+ return imOut;
+
+#define CHOP2(operation, mode) \
+ int x, y; \
+ Imaging imOut; \
+ imOut = create(imIn1, imIn2, mode); \
+ if (!imOut) { \
+ return NULL; \
+ } \
+ for (y = 0; y < imOut->ysize; y++) { \
+ UINT8 *out = (UINT8 *)imOut->image[y]; \
+ UINT8 *in1 = (UINT8 *)imIn1->image[y]; \
+ UINT8 *in2 = (UINT8 *)imIn2->image[y]; \
+ for (x = 0; x < imOut->linesize; x++) { \
+ out[x] = operation; \
+ } \
+ } \
+ return imOut;
+
+static Imaging
+create(Imaging im1, Imaging im2, char *mode) {
+ int xsize, ysize;
+
+ if (!im1 || !im2 || im1->type != IMAGING_TYPE_UINT8 ||
+ (mode != NULL && (strcmp(im1->mode, "1") || strcmp(im2->mode, "1")))) {
+ return (Imaging)ImagingError_ModeError();
+ }
+ if (im1->type != im2->type || im1->bands != im2->bands) {
+ return (Imaging)ImagingError_Mismatch();
+ }
+
+ xsize = (im1->xsize < im2->xsize) ? im1->xsize : im2->xsize;
+ ysize = (im1->ysize < im2->ysize) ? im1->ysize : im2->ysize;
+
+ return ImagingNewDirty(im1->mode, xsize, ysize);
+}
+
+Imaging
+ImagingChopLighter(Imaging imIn1, Imaging imIn2) {
+ CHOP((in1[x] > in2[x]) ? in1[x] : in2[x]);
+}
+
+Imaging
+ImagingChopDarker(Imaging imIn1, Imaging imIn2) {
+ CHOP((in1[x] < in2[x]) ? in1[x] : in2[x]);
+}
+
+Imaging
+ImagingChopDifference(Imaging imIn1, Imaging imIn2) {
+ CHOP(abs((int)in1[x] - (int)in2[x]));
+}
+
+Imaging
+ImagingChopMultiply(Imaging imIn1, Imaging imIn2) {
+ CHOP((int)in1[x] * (int)in2[x] / 255);
+}
+
+Imaging
+ImagingChopScreen(Imaging imIn1, Imaging imIn2) {
+ CHOP(255 - ((int)(255 - in1[x]) * (int)(255 - in2[x])) / 255);
+}
+
+Imaging
+ImagingChopAdd(Imaging imIn1, Imaging imIn2, float scale, int offset) {
+ CHOP(((int)in1[x] + (int)in2[x]) / scale + offset);
+}
+
+Imaging
+ImagingChopSubtract(Imaging imIn1, Imaging imIn2, float scale, int offset) {
+ CHOP(((int)in1[x] - (int)in2[x]) / scale + offset);
+}
+
+Imaging
+ImagingChopAnd(Imaging imIn1, Imaging imIn2) {
+ CHOP2((in1[x] && in2[x]) ? 255 : 0, "1");
+}
+
+Imaging
+ImagingChopOr(Imaging imIn1, Imaging imIn2) {
+ CHOP2((in1[x] || in2[x]) ? 255 : 0, "1");
+}
+
+Imaging
+ImagingChopXor(Imaging imIn1, Imaging imIn2) {
+ CHOP2(((in1[x] != 0) ^ (in2[x] != 0)) ? 255 : 0, "1");
+}
+
+Imaging
+ImagingChopAddModulo(Imaging imIn1, Imaging imIn2) {
+ CHOP2(in1[x] + in2[x], NULL);
+}
+
+Imaging
+ImagingChopSubtractModulo(Imaging imIn1, Imaging imIn2) {
+ CHOP2(in1[x] - in2[x], NULL);
+}
+
+Imaging
+ImagingChopSoftLight(Imaging imIn1, Imaging imIn2) {
+ CHOP2(
+ (((255 - in1[x]) * (in1[x] * in2[x])) / 65536) +
+ (in1[x] * (255 - ((255 - in1[x]) * (255 - in2[x]) / 255))) / 255,
+ NULL);
+}
+
+Imaging
+ImagingChopHardLight(Imaging imIn1, Imaging imIn2) {
+ CHOP2(
+ (in2[x] < 128) ? ((in1[x] * in2[x]) / 127)
+ : 255 - (((255 - in2[x]) * (255 - in1[x])) / 127),
+ NULL);
+}
+
+Imaging
+ImagingOverlay(Imaging imIn1, Imaging imIn2) {
+ CHOP2(
+ (in1[x] < 128) ? ((in1[x] * in2[x]) / 127)
+ : 255 - (((255 - in1[x]) * (255 - in2[x])) / 127),
+ NULL);
+}
diff --git a/contrib/python/Pillow/py3/libImaging/ColorLUT.c b/contrib/python/Pillow/py3/libImaging/ColorLUT.c
new file mode 100644
index 00000000000..aee7cda067d
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/ColorLUT.c
@@ -0,0 +1,187 @@
+#include "Imaging.h"
+#include <math.h>
+
+/* 8 bits for result. Table can overflow [0, 1.0] range,
+ so we need extra bits for overflow and negative values.
+ NOTE: This value should be the same as in _imaging/_prepare_lut_table() */
+#define PRECISION_BITS (16 - 8 - 2)
+#define PRECISION_ROUNDING (1 << (PRECISION_BITS - 1))
+
+/* 8 - scales are multiplied on byte.
+ 6 - max index in the table
+ (max size is 65, but index 64 is not reachable) */
+#define SCALE_BITS (32 - 8 - 6)
+#define SCALE_MASK ((1 << SCALE_BITS) - 1)
+
+#define SHIFT_BITS (16 - 1)
+
+static inline UINT8
+clip8(int in) {
+ return clip8_lookups[(in + PRECISION_ROUNDING) >> PRECISION_BITS];
+}
+
+static inline void
+interpolate3(INT16 out[3], const INT16 a[3], const INT16 b[3], INT16 shift) {
+ out[0] = (a[0] * ((1 << SHIFT_BITS) - shift) + b[0] * shift) >> SHIFT_BITS;
+ out[1] = (a[1] * ((1 << SHIFT_BITS) - shift) + b[1] * shift) >> SHIFT_BITS;
+ out[2] = (a[2] * ((1 << SHIFT_BITS) - shift) + b[2] * shift) >> SHIFT_BITS;
+}
+
+static inline void
+interpolate4(INT16 out[4], const INT16 a[4], const INT16 b[4], INT16 shift) {
+ out[0] = (a[0] * ((1 << SHIFT_BITS) - shift) + b[0] * shift) >> SHIFT_BITS;
+ out[1] = (a[1] * ((1 << SHIFT_BITS) - shift) + b[1] * shift) >> SHIFT_BITS;
+ out[2] = (a[2] * ((1 << SHIFT_BITS) - shift) + b[2] * shift) >> SHIFT_BITS;
+ out[3] = (a[3] * ((1 << SHIFT_BITS) - shift) + b[3] * shift) >> SHIFT_BITS;
+}
+
+static inline int
+table_index3D(int index1D, int index2D, int index3D, int size1D, int size1D_2D) {
+ return index1D + index2D * size1D + index3D * size1D_2D;
+}
+
+/*
+ Transforms colors of imIn using provided 3D lookup table
+ and puts the result in imOut. Returns imOut on success or 0 on error.
+
+ imOut, imIn - images, should be the same size and may be the same image.
+ Should have 3 or 4 channels.
+ table_channels - number of channels in the lookup table, 3 or 4.
+ Should be less or equal than number of channels in imOut image;
+ size1D, size_2D and size3D - dimensions of provided table;
+ table - flat table,
+ array with table_channels * size1D * size2D * size3D elements,
+ where channels are changed first, then 1D, then 2D, then 3D.
+ Each element is signed 16-bit int where 0 is lowest output value
+ and 255 << PRECISION_BITS (16320) is highest value.
+*/
+Imaging
+ImagingColorLUT3D_linear(
+ Imaging imOut,
+ Imaging imIn,
+ int table_channels,
+ int size1D,
+ int size2D,
+ int size3D,
+ INT16 *table) {
+ /* This float to int conversion doesn't have rounding
+ error compensation (+0.5) for two reasons:
+ 1. As we don't hit the highest value,
+ we can use one extra bit for precision.
+ 2. For every pixel, we interpolate 8 elements from the table:
+ current and +1 for every dimension and their combinations.
+ If we hit the upper cells from the table,
+ +1 cells will be outside of the table.
+ With this compensation we never hit the upper cells
+ but this also doesn't introduce any noticeable difference. */
+ UINT32 scale1D = (size1D - 1) / 255.0 * (1 << SCALE_BITS);
+ UINT32 scale2D = (size2D - 1) / 255.0 * (1 << SCALE_BITS);
+ UINT32 scale3D = (size3D - 1) / 255.0 * (1 << SCALE_BITS);
+ int size1D_2D = size1D * size2D;
+ int x, y;
+ ImagingSectionCookie cookie;
+
+ if (table_channels < 3 || table_channels > 4) {
+ PyErr_SetString(PyExc_ValueError, "table_channels could be 3 or 4");
+ return NULL;
+ }
+
+ if (imIn->type != IMAGING_TYPE_UINT8 || imOut->type != IMAGING_TYPE_UINT8 ||
+ imIn->bands < 3 || imOut->bands < table_channels) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ /* In case we have one extra band in imOut and don't have in imIn.*/
+ if (imOut->bands > table_channels && imOut->bands > imIn->bands) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8 *rowIn = (UINT8 *)imIn->image[y];
+ char *rowOut = (char *)imOut->image[y];
+ for (x = 0; x < imOut->xsize; x++) {
+ UINT32 index1D = rowIn[x * 4 + 0] * scale1D;
+ UINT32 index2D = rowIn[x * 4 + 1] * scale2D;
+ UINT32 index3D = rowIn[x * 4 + 2] * scale3D;
+ INT16 shift1D = (SCALE_MASK & index1D) >> (SCALE_BITS - SHIFT_BITS);
+ INT16 shift2D = (SCALE_MASK & index2D) >> (SCALE_BITS - SHIFT_BITS);
+ INT16 shift3D = (SCALE_MASK & index3D) >> (SCALE_BITS - SHIFT_BITS);
+ int idx = table_channels * table_index3D(
+ index1D >> SCALE_BITS,
+ index2D >> SCALE_BITS,
+ index3D >> SCALE_BITS,
+ size1D,
+ size1D_2D);
+ INT16 result[4], left[4], right[4];
+ INT16 leftleft[4], leftright[4], rightleft[4], rightright[4];
+
+ if (table_channels == 3) {
+ UINT32 v;
+ interpolate3(leftleft, &table[idx + 0], &table[idx + 3], shift1D);
+ interpolate3(
+ leftright,
+ &table[idx + size1D * 3],
+ &table[idx + size1D * 3 + 3],
+ shift1D);
+ interpolate3(left, leftleft, leftright, shift2D);
+
+ interpolate3(
+ rightleft,
+ &table[idx + size1D_2D * 3],
+ &table[idx + size1D_2D * 3 + 3],
+ shift1D);
+ interpolate3(
+ rightright,
+ &table[idx + size1D_2D * 3 + size1D * 3],
+ &table[idx + size1D_2D * 3 + size1D * 3 + 3],
+ shift1D);
+ interpolate3(right, rightleft, rightright, shift2D);
+
+ interpolate3(result, left, right, shift3D);
+
+ v = MAKE_UINT32(
+ clip8(result[0]),
+ clip8(result[1]),
+ clip8(result[2]),
+ rowIn[x * 4 + 3]);
+ memcpy(rowOut + x * sizeof(v), &v, sizeof(v));
+ }
+
+ if (table_channels == 4) {
+ UINT32 v;
+ interpolate4(leftleft, &table[idx + 0], &table[idx + 4], shift1D);
+ interpolate4(
+ leftright,
+ &table[idx + size1D * 4],
+ &table[idx + size1D * 4 + 4],
+ shift1D);
+ interpolate4(left, leftleft, leftright, shift2D);
+
+ interpolate4(
+ rightleft,
+ &table[idx + size1D_2D * 4],
+ &table[idx + size1D_2D * 4 + 4],
+ shift1D);
+ interpolate4(
+ rightright,
+ &table[idx + size1D_2D * 4 + size1D * 4],
+ &table[idx + size1D_2D * 4 + size1D * 4 + 4],
+ shift1D);
+ interpolate4(right, rightleft, rightright, shift2D);
+
+ interpolate4(result, left, right, shift3D);
+
+ v = MAKE_UINT32(
+ clip8(result[0]),
+ clip8(result[1]),
+ clip8(result[2]),
+ clip8(result[3]));
+ memcpy(rowOut + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Convert.c b/contrib/python/Pillow/py3/libImaging/Convert.c
new file mode 100644
index 00000000000..b08519d3045
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Convert.c
@@ -0,0 +1,1742 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * convert images
+ *
+ * history:
+ * 1995-06-15 fl created
+ * 1995-11-28 fl added some "RGBA" and "CMYK" conversions
+ * 1996-04-22 fl added "1" conversions (same as "L")
+ * 1996-05-05 fl added palette conversions (hack)
+ * 1996-07-23 fl fixed "1" conversions to zero/non-zero convention
+ * 1996-11-01 fl fixed "P" to "L" and "RGB" to "1" conversions
+ * 1996-12-29 fl set alpha byte in RGB converters
+ * 1997-05-12 fl added ImagingConvert2
+ * 1997-05-30 fl added floating point support
+ * 1997-08-27 fl added "P" to "1" and "P" to "F" conversions
+ * 1998-01-11 fl added integer support
+ * 1998-07-01 fl added "YCbCr" support
+ * 1998-07-02 fl added "RGBX" conversions (sort of)
+ * 1998-07-04 fl added floyd-steinberg dithering
+ * 1998-07-12 fl changed "YCrCb" to "YCbCr" (!)
+ * 1998-12-29 fl added basic "I;16" and "I;16B" conversions
+ * 1999-02-03 fl added "RGBa", and "BGR" conversions (experimental)
+ * 2003-09-26 fl added "LA" and "PA" conversions (experimental)
+ * 2005-05-05 fl fixed "P" to "1" threshold
+ * 2005-12-08 fl fixed palette memory leak in topalette
+ *
+ * Copyright (c) 1997-2005 by Secret Labs AB.
+ * Copyright (c) 1995-1997 by Fredrik Lundh.
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#define MAX(a, b) (a) > (b) ? (a) : (b)
+#define MIN(a, b) (a) < (b) ? (a) : (b)
+
+#define CLIP16(v) ((v) <= 0 ? 0 : (v) >= 65535 ? 65535 : (v))
+
+/* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
+#define L(rgb) ((INT32)(rgb)[0] * 299 + (INT32)(rgb)[1] * 587 + (INT32)(rgb)[2] * 114)
+#define L24(rgb) ((rgb)[0] * 19595 + (rgb)[1] * 38470 + (rgb)[2] * 7471 + 0x8000)
+
+/* ------------------- */
+/* 1 (bit) conversions */
+/* ------------------- */
+
+static void
+bit2l(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++) *out++ = (*in++ != 0) ? 255 : 0;
+}
+
+static void
+bit2rgb(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++) {
+ UINT8 v = (*in++ != 0) ? 255 : 0;
+ *out++ = v;
+ *out++ = v;
+ *out++ = v;
+ *out++ = 255;
+ }
+}
+
+static void
+bit2cmyk(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++) {
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = (*in++ != 0) ? 0 : 255;
+ }
+}
+
+static void
+bit2ycbcr(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++) {
+ *out++ = (*in++ != 0) ? 255 : 0;
+ *out++ = 128;
+ *out++ = 128;
+ *out++ = 255;
+ }
+}
+
+static void
+bit2hsv(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, out += 4) {
+ UINT8 v = (*in++ != 0) ? 255 : 0;
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = v;
+ out[3] = 255;
+ }
+}
+
+/* ----------------- */
+/* RGB/L conversions */
+/* ----------------- */
+
+static void
+l2bit(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++) {
+ *out++ = (*in++ >= 128) ? 255 : 0;
+ }
+}
+
+static void
+lA2la(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ unsigned int alpha, pixel, tmp;
+ for (x = 0; x < xsize; x++, in += 4) {
+ alpha = in[3];
+ pixel = MULDIV255(in[0], alpha, tmp);
+ *out++ = (UINT8)pixel;
+ *out++ = (UINT8)pixel;
+ *out++ = (UINT8)pixel;
+ *out++ = (UINT8)alpha;
+ }
+}
+
+/* RGBa -> RGBA conversion to remove premultiplication
+ Needed for correct transforms/resizing on RGBA images */
+static void
+la2lA(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ unsigned int alpha, pixel;
+ for (x = 0; x < xsize; x++, in += 4) {
+ alpha = in[3];
+ if (alpha == 255 || alpha == 0) {
+ pixel = in[0];
+ } else {
+ pixel = CLIP8((255 * in[0]) / alpha);
+ }
+ *out++ = (UINT8)pixel;
+ *out++ = (UINT8)pixel;
+ *out++ = (UINT8)pixel;
+ *out++ = (UINT8)alpha;
+ }
+}
+
+static void
+l2la(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++) {
+ UINT8 v = *in++;
+ *out++ = v;
+ *out++ = v;
+ *out++ = v;
+ *out++ = 255;
+ }
+}
+
+static void
+l2rgb(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++) {
+ UINT8 v = *in++;
+ *out++ = v;
+ *out++ = v;
+ *out++ = v;
+ *out++ = 255;
+ }
+}
+
+static void
+l2hsv(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, out += 4) {
+ UINT8 v = *in++;
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = v;
+ out[3] = 255;
+ }
+}
+
+static void
+la2l(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ *out++ = in[0];
+ }
+}
+
+static void
+la2rgb(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ UINT8 v = in[0];
+ *out++ = v;
+ *out++ = v;
+ *out++ = v;
+ *out++ = in[3];
+ }
+}
+
+static void
+la2hsv(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ UINT8 v = in[0];
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = v;
+ out[3] = in[3];
+ }
+}
+
+static void
+rgb2bit(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
+ *out++ = (L(in) >= 128000) ? 255 : 0;
+ }
+}
+
+static void
+rgb2l(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
+ *out++ = L24(in) >> 16;
+ }
+}
+
+static void
+rgb2la(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
+ out[0] = out[1] = out[2] = L24(in) >> 16;
+ out[3] = 255;
+ }
+}
+
+static void
+rgb2i(UINT8 *out_, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out_ += 4) {
+ INT32 v = L24(in) >> 16;
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+rgb2f(UINT8 *out_, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out_ += 4) {
+ FLOAT32 v = (float)L(in) / 1000.0F;
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+rgb2bgr15(UINT8 *out_, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out_ += 2) {
+ UINT16 v = ((((UINT16)in[0]) << 7) & 0x7c00) +
+ ((((UINT16)in[1]) << 2) & 0x03e0) +
+ ((((UINT16)in[2]) >> 3) & 0x001f);
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+rgb2bgr16(UINT8 *out_, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out_ += 2) {
+ UINT16 v = ((((UINT16)in[0]) << 8) & 0xf800) +
+ ((((UINT16)in[1]) << 3) & 0x07e0) +
+ ((((UINT16)in[2]) >> 3) & 0x001f);
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+rgb2bgr24(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ *out++ = in[2];
+ *out++ = in[1];
+ *out++ = in[0];
+ }
+}
+
+static void
+rgb2hsv_row(UINT8 *out, const UINT8 *in) { // following colorsys.py
+ float h, s, rc, gc, bc, cr;
+ UINT8 maxc, minc;
+ UINT8 r, g, b;
+ UINT8 uh, us, uv;
+
+ r = in[0];
+ g = in[1];
+ b = in[2];
+ maxc = MAX(r, MAX(g, b));
+ minc = MIN(r, MIN(g, b));
+ uv = maxc;
+ if (minc == maxc) {
+ uh = 0;
+ us = 0;
+ } else {
+ cr = (float)(maxc - minc);
+ s = cr / (float)maxc;
+ rc = ((float)(maxc - r)) / cr;
+ gc = ((float)(maxc - g)) / cr;
+ bc = ((float)(maxc - b)) / cr;
+ if (r == maxc) {
+ h = bc - gc;
+ } else if (g == maxc) {
+ h = 2.0 + rc - bc;
+ } else {
+ h = 4.0 + gc - rc;
+ }
+ // incorrect hue happens if h/6 is negative.
+ h = fmod((h / 6.0 + 1.0), 1.0);
+
+ uh = (UINT8)CLIP8((int)(h * 255.0));
+ us = (UINT8)CLIP8((int)(s * 255.0));
+ }
+ out[0] = uh;
+ out[1] = us;
+ out[2] = uv;
+}
+
+static void
+rgb2hsv(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ rgb2hsv_row(out, in);
+ out[3] = in[3];
+ }
+}
+
+static void
+hsv2rgb(UINT8 *out, const UINT8 *in, int xsize) { // following colorsys.py
+
+ int p, q, t;
+ UINT8 up, uq, ut;
+ int i, x;
+ float f, fs;
+ UINT8 h, s, v;
+
+ for (x = 0; x < xsize; x++, in += 4) {
+ h = in[0];
+ s = in[1];
+ v = in[2];
+
+ if (s == 0) {
+ *out++ = v;
+ *out++ = v;
+ *out++ = v;
+ } else {
+ i = floor((float)h * 6.0 / 255.0); // 0 - 6
+ f = (float)h * 6.0 / 255.0 - (float)i; // 0-1 : remainder.
+ fs = ((float)s) / 255.0;
+
+ p = round((float)v * (1.0 - fs));
+ q = round((float)v * (1.0 - fs * f));
+ t = round((float)v * (1.0 - fs * (1.0 - f)));
+ up = (UINT8)CLIP8(p);
+ uq = (UINT8)CLIP8(q);
+ ut = (UINT8)CLIP8(t);
+
+ switch (i % 6) {
+ case 0:
+ *out++ = v;
+ *out++ = ut;
+ *out++ = up;
+ break;
+ case 1:
+ *out++ = uq;
+ *out++ = v;
+ *out++ = up;
+ break;
+ case 2:
+ *out++ = up;
+ *out++ = v;
+ *out++ = ut;
+ break;
+ case 3:
+ *out++ = up;
+ *out++ = uq;
+ *out++ = v;
+ break;
+ case 4:
+ *out++ = ut;
+ *out++ = up;
+ *out++ = v;
+ break;
+ case 5:
+ *out++ = v;
+ *out++ = up;
+ *out++ = uq;
+ break;
+ }
+ }
+ *out++ = in[3];
+ }
+}
+
+/* ---------------- */
+/* RGBA conversions */
+/* ---------------- */
+
+static void
+rgb2rgba(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++) {
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = 255;
+ in++;
+ }
+}
+
+static void
+rgba2la(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ /* ITU-R Recommendation 601-2 (assuming nonlinear RGB) */
+ out[0] = out[1] = out[2] = L24(in) >> 16;
+ out[3] = in[3];
+ }
+}
+
+static void
+rgba2rgb(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++) {
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = *in++;
+ *out++ = 255;
+ in++;
+ }
+}
+
+static void
+rgbA2rgba(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ unsigned int alpha, tmp;
+ for (x = 0; x < xsize; x++) {
+ alpha = in[3];
+ *out++ = MULDIV255(*in++, alpha, tmp);
+ *out++ = MULDIV255(*in++, alpha, tmp);
+ *out++ = MULDIV255(*in++, alpha, tmp);
+ *out++ = *in++;
+ }
+}
+
+/* RGBa -> RGBA conversion to remove premultiplication
+ Needed for correct transforms/resizing on RGBA images */
+static void
+rgba2rgbA(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ unsigned int alpha;
+ for (x = 0; x < xsize; x++, in += 4) {
+ alpha = in[3];
+ if (alpha == 255 || alpha == 0) {
+ *out++ = in[0];
+ *out++ = in[1];
+ *out++ = in[2];
+ } else {
+ *out++ = CLIP8((255 * in[0]) / alpha);
+ *out++ = CLIP8((255 * in[1]) / alpha);
+ *out++ = CLIP8((255 * in[2]) / alpha);
+ }
+ *out++ = in[3];
+ }
+}
+
+static void
+rgba2rgb_(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ unsigned int alpha;
+ for (x = 0; x < xsize; x++, in += 4) {
+ alpha = in[3];
+ if (alpha == 255 || alpha == 0) {
+ *out++ = in[0];
+ *out++ = in[1];
+ *out++ = in[2];
+ } else {
+ *out++ = CLIP8((255 * in[0]) / alpha);
+ *out++ = CLIP8((255 * in[1]) / alpha);
+ *out++ = CLIP8((255 * in[2]) / alpha);
+ }
+ *out++ = 255;
+ }
+}
+
+/*
+ * Conversion of RGB + single transparent color to RGBA,
+ * where any pixel that matches the color will have the
+ * alpha channel set to 0
+ */
+
+static void
+rgbT2rgba(UINT8 *out, int xsize, int r, int g, int b) {
+#ifdef WORDS_BIGENDIAN
+ UINT32 trns = ((r & 0xff) << 24) | ((g & 0xff) << 16) | ((b & 0xff) << 8) | 0xff;
+ UINT32 repl = trns & 0xffffff00;
+#else
+ UINT32 trns = (0xff << 24) | ((b & 0xff) << 16) | ((g & 0xff) << 8) | (r & 0xff);
+ UINT32 repl = trns & 0x00ffffff;
+#endif
+
+ int i;
+
+ for (i = 0; i < xsize; i++, out += sizeof(trns)) {
+ UINT32 v;
+ memcpy(&v, out, sizeof(v));
+ if (v == trns) {
+ memcpy(out, &repl, sizeof(repl));
+ }
+ }
+}
+
+/* ---------------- */
+/* CMYK conversions */
+/* ---------------- */
+
+static void
+l2cmyk(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++) {
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = ~(*in++);
+ }
+}
+
+static void
+la2cmyk(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = ~(in[0]);
+ }
+}
+
+static void
+rgb2cmyk(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++) {
+ /* Note: no undercolour removal */
+ *out++ = ~(*in++);
+ *out++ = ~(*in++);
+ *out++ = ~(*in++);
+ *out++ = 0;
+ in++;
+ }
+}
+
+void
+cmyk2rgb(UINT8 *out, const UINT8 *in, int xsize) {
+ int x, nk, tmp;
+ for (x = 0; x < xsize; x++) {
+ nk = 255 - in[3];
+ out[0] = CLIP8(nk - MULDIV255(in[0], nk, tmp));
+ out[1] = CLIP8(nk - MULDIV255(in[1], nk, tmp));
+ out[2] = CLIP8(nk - MULDIV255(in[2], nk, tmp));
+ out[3] = 255;
+ out += 4;
+ in += 4;
+ }
+}
+
+static void
+cmyk2hsv(UINT8 *out, const UINT8 *in, int xsize) {
+ int x, nk, tmp;
+ for (x = 0; x < xsize; x++) {
+ nk = 255 - in[3];
+ out[0] = CLIP8(nk - MULDIV255(in[0], nk, tmp));
+ out[1] = CLIP8(nk - MULDIV255(in[1], nk, tmp));
+ out[2] = CLIP8(nk - MULDIV255(in[2], nk, tmp));
+ rgb2hsv_row(out, out);
+ out[3] = 255;
+ out += 4;
+ in += 4;
+ }
+}
+
+/* ------------- */
+/* I conversions */
+/* ------------- */
+
+static void
+bit2i(UINT8 *out_, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, out_ += 4) {
+ INT32 v = (*in++ != 0) ? 255 : 0;
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+l2i(UINT8 *out_, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, out_ += 4) {
+ INT32 v = *in++;
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+i2l(UINT8 *out, const UINT8 *in_, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, out++, in_ += 4) {
+ INT32 v;
+ memcpy(&v, in_, sizeof(v));
+ if (v <= 0) {
+ *out = 0;
+ } else if (v >= 255) {
+ *out = 255;
+ } else {
+ *out = (UINT8)v;
+ }
+ }
+}
+
+static void
+i2f(UINT8 *out_, const UINT8 *in_, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in_ += 4, out_ += 4) {
+ INT32 i;
+ FLOAT32 f;
+ memcpy(&i, in_, sizeof(i));
+ f = i;
+ memcpy(out_, &f, sizeof(f));
+ }
+}
+
+static void
+i2rgb(UINT8 *out, const UINT8 *in_, int xsize) {
+ int x;
+ INT32 *in = (INT32 *)in_;
+ for (x = 0; x < xsize; x++, in++, out += 4) {
+ if (*in <= 0) {
+ out[0] = out[1] = out[2] = 0;
+ } else if (*in >= 255) {
+ out[0] = out[1] = out[2] = 255;
+ } else {
+ out[0] = out[1] = out[2] = (UINT8)*in;
+ }
+ out[3] = 255;
+ }
+}
+
+static void
+i2hsv(UINT8 *out, const UINT8 *in_, int xsize) {
+ int x;
+ INT32 *in = (INT32 *)in_;
+ for (x = 0; x < xsize; x++, in++, out += 4) {
+ out[0] = 0;
+ out[1] = 0;
+ if (*in <= 0) {
+ out[2] = 0;
+ } else if (*in >= 255) {
+ out[2] = 255;
+ } else {
+ out[2] = (UINT8)*in;
+ }
+ out[3] = 255;
+ }
+}
+
+/* ------------- */
+/* F conversions */
+/* ------------- */
+
+static void
+bit2f(UINT8 *out_, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, out_ += 4) {
+ FLOAT32 f = (*in++ != 0) ? 255.0F : 0.0F;
+ memcpy(out_, &f, sizeof(f));
+ }
+}
+
+static void
+l2f(UINT8 *out_, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, out_ += 4) {
+ FLOAT32 f = (FLOAT32)*in++;
+ memcpy(out_, &f, sizeof(f));
+ }
+}
+
+static void
+f2l(UINT8 *out, const UINT8 *in_, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, out++, in_ += 4) {
+ FLOAT32 v;
+ memcpy(&v, in_, sizeof(v));
+ if (v <= 0.0) {
+ *out = 0;
+ } else if (v >= 255.0) {
+ *out = 255;
+ } else {
+ *out = (UINT8)v;
+ }
+ }
+}
+
+static void
+f2i(UINT8 *out_, const UINT8 *in_, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in_ += 4, out_ += 4) {
+ FLOAT32 f;
+ INT32 i;
+ memcpy(&f, in_, sizeof(f));
+ i = f;
+ memcpy(out_, &i, sizeof(i));
+ }
+}
+
+/* ----------------- */
+/* YCbCr conversions */
+/* ----------------- */
+
+/* See ConvertYCbCr.c for RGB/YCbCr tables */
+
+static void
+l2ycbcr(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++) {
+ *out++ = *in++;
+ *out++ = 128;
+ *out++ = 128;
+ *out++ = 255;
+ }
+}
+
+static void
+la2ycbcr(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ *out++ = in[0];
+ *out++ = 128;
+ *out++ = 128;
+ *out++ = 255;
+ }
+}
+
+static void
+ycbcr2l(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ *out++ = in[0];
+ }
+}
+
+static void
+ycbcr2la(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ out[0] = out[1] = out[2] = in[0];
+ out[3] = 255;
+ }
+}
+
+/* ------------------------- */
+/* I;16 (16-bit) conversions */
+/* ------------------------- */
+
+static void
+I_I16L(UINT8 *out, const UINT8 *in_, int xsize) {
+ int x, v;
+ for (x = 0; x < xsize; x++, in_ += 4) {
+ INT32 i;
+ memcpy(&i, in_, sizeof(i));
+ v = CLIP16(i);
+ *out++ = (UINT8)v;
+ *out++ = (UINT8)(v >> 8);
+ }
+}
+
+static void
+I_I16B(UINT8 *out, const UINT8 *in_, int xsize) {
+ int x, v;
+ for (x = 0; x < xsize; x++, in_ += 4) {
+ INT32 i;
+ memcpy(&i, in_, sizeof(i));
+ v = CLIP16(i);
+ *out++ = (UINT8)(v >> 8);
+ *out++ = (UINT8)v;
+ }
+}
+
+static void
+I16L_I(UINT8 *out_, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 2, out_ += 4) {
+ INT32 v = in[0] + ((int)in[1] << 8);
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+I16B_I(UINT8 *out_, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 2, out_ += 4) {
+ INT32 v = in[1] + ((int)in[0] << 8);
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+I16L_F(UINT8 *out_, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 2, out_ += 4) {
+ FLOAT32 v = in[0] + ((int)in[1] << 8);
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+I16B_F(UINT8 *out_, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 2, out_ += 4) {
+ FLOAT32 v = in[1] + ((int)in[0] << 8);
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+L_I16L(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in++) {
+ *out++ = *in;
+ *out++ = 0;
+ }
+}
+
+static void
+L_I16B(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in++) {
+ *out++ = 0;
+ *out++ = *in;
+ }
+}
+
+static void
+I16L_L(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 2) {
+ if (in[1] != 0) {
+ *out++ = 255;
+ } else {
+ *out++ = in[0];
+ }
+ }
+}
+
+static void
+I16B_L(UINT8 *out, const UINT8 *in, int xsize) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 2) {
+ if (in[0] != 0) {
+ *out++ = 255;
+ } else {
+ *out++ = in[1];
+ }
+ }
+}
+
+static struct {
+ const char *from;
+ const char *to;
+ ImagingShuffler convert;
+} converters[] = {
+
+ {"1", "L", bit2l},
+ {"1", "I", bit2i},
+ {"1", "F", bit2f},
+ {"1", "RGB", bit2rgb},
+ {"1", "RGBA", bit2rgb},
+ {"1", "RGBX", bit2rgb},
+ {"1", "CMYK", bit2cmyk},
+ {"1", "YCbCr", bit2ycbcr},
+ {"1", "HSV", bit2hsv},
+
+ {"L", "1", l2bit},
+ {"L", "LA", l2la},
+ {"L", "I", l2i},
+ {"L", "F", l2f},
+ {"L", "RGB", l2rgb},
+ {"L", "RGBA", l2rgb},
+ {"L", "RGBX", l2rgb},
+ {"L", "CMYK", l2cmyk},
+ {"L", "YCbCr", l2ycbcr},
+ {"L", "HSV", l2hsv},
+
+ {"LA", "L", la2l},
+ {"LA", "La", lA2la},
+ {"LA", "RGB", la2rgb},
+ {"LA", "RGBA", la2rgb},
+ {"LA", "RGBX", la2rgb},
+ {"LA", "CMYK", la2cmyk},
+ {"LA", "YCbCr", la2ycbcr},
+ {"LA", "HSV", la2hsv},
+
+ {"La", "LA", la2lA},
+
+ {"I", "L", i2l},
+ {"I", "F", i2f},
+ {"I", "RGB", i2rgb},
+ {"I", "RGBA", i2rgb},
+ {"I", "RGBX", i2rgb},
+ {"I", "HSV", i2hsv},
+
+ {"F", "L", f2l},
+ {"F", "I", f2i},
+
+ {"RGB", "1", rgb2bit},
+ {"RGB", "L", rgb2l},
+ {"RGB", "LA", rgb2la},
+ {"RGB", "I", rgb2i},
+ {"RGB", "F", rgb2f},
+ {"RGB", "BGR;15", rgb2bgr15},
+ {"RGB", "BGR;16", rgb2bgr16},
+ {"RGB", "BGR;24", rgb2bgr24},
+ {"RGB", "RGBA", rgb2rgba},
+ {"RGB", "RGBX", rgb2rgba},
+ {"RGB", "CMYK", rgb2cmyk},
+ {"RGB", "YCbCr", ImagingConvertRGB2YCbCr},
+ {"RGB", "HSV", rgb2hsv},
+
+ {"RGBA", "1", rgb2bit},
+ {"RGBA", "L", rgb2l},
+ {"RGBA", "LA", rgba2la},
+ {"RGBA", "I", rgb2i},
+ {"RGBA", "F", rgb2f},
+ {"RGBA", "RGB", rgba2rgb},
+ {"RGBA", "RGBa", rgbA2rgba},
+ {"RGBA", "RGBX", rgb2rgba},
+ {"RGBA", "CMYK", rgb2cmyk},
+ {"RGBA", "YCbCr", ImagingConvertRGB2YCbCr},
+ {"RGBA", "HSV", rgb2hsv},
+
+ {"RGBa", "RGBA", rgba2rgbA},
+ {"RGBa", "RGB", rgba2rgb_},
+
+ {"RGBX", "1", rgb2bit},
+ {"RGBX", "L", rgb2l},
+ {"RGBX", "LA", rgb2la},
+ {"RGBX", "I", rgb2i},
+ {"RGBX", "F", rgb2f},
+ {"RGBX", "RGB", rgba2rgb},
+ {"RGBX", "CMYK", rgb2cmyk},
+ {"RGBX", "YCbCr", ImagingConvertRGB2YCbCr},
+ {"RGBX", "HSV", rgb2hsv},
+
+ {"CMYK", "RGB", cmyk2rgb},
+ {"CMYK", "RGBA", cmyk2rgb},
+ {"CMYK", "RGBX", cmyk2rgb},
+ {"CMYK", "HSV", cmyk2hsv},
+
+ {"YCbCr", "L", ycbcr2l},
+ {"YCbCr", "LA", ycbcr2la},
+ {"YCbCr", "RGB", ImagingConvertYCbCr2RGB},
+
+ {"HSV", "RGB", hsv2rgb},
+
+ {"I", "I;16", I_I16L},
+ {"I;16", "I", I16L_I},
+ {"L", "I;16", L_I16L},
+ {"I;16", "L", I16L_L},
+
+ {"I", "I;16L", I_I16L},
+ {"I;16L", "I", I16L_I},
+ {"I", "I;16B", I_I16B},
+ {"I;16B", "I", I16B_I},
+
+ {"L", "I;16L", L_I16L},
+ {"I;16L", "L", I16L_L},
+ {"L", "I;16B", L_I16B},
+ {"I;16B", "L", I16B_L},
+#ifdef WORDS_BIGENDIAN
+ {"L", "I;16N", L_I16B},
+ {"I;16N", "L", I16B_L},
+#else
+ {"L", "I;16N", L_I16L},
+ {"I;16N", "L", I16L_L},
+#endif
+
+ {"I;16", "F", I16L_F},
+ {"I;16L", "F", I16L_F},
+ {"I;16B", "F", I16B_F},
+
+ {NULL}};
+
+/* FIXME: translate indexed versions to pointer versions below this line */
+
+/* ------------------- */
+/* Palette conversions */
+/* ------------------- */
+
+static void
+p2bit(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ /* FIXME: precalculate greyscale palette? */
+ for (x = 0; x < xsize; x++) {
+ *out++ = (L(&palette->palette[in[x] * 4]) >= 128000) ? 255 : 0;
+ }
+}
+
+static void
+pa2bit(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ /* FIXME: precalculate greyscale palette? */
+ for (x = 0; x < xsize; x++, in += 4) {
+ *out++ = (L(&palette->palette[in[0] * 4]) >= 128000) ? 255 : 0;
+ }
+}
+
+static void
+p2l(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ /* FIXME: precalculate greyscale palette? */
+ for (x = 0; x < xsize; x++) {
+ *out++ = L24(&palette->palette[in[x] * 4]) >> 16;
+ }
+}
+
+static void
+pa2l(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ /* FIXME: precalculate greyscale palette? */
+ for (x = 0; x < xsize; x++, in += 4) {
+ *out++ = L24(&palette->palette[in[0] * 4]) >> 16;
+ }
+}
+
+static void
+pa2p(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ *out++ = in[0];
+ }
+}
+
+static void
+p2pa(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ int rgb = strcmp(palette->mode, "RGB");
+ for (x = 0; x < xsize; x++, in++) {
+ const UINT8 *rgba = &palette->palette[in[0] * 4];
+ *out++ = in[0];
+ *out++ = in[0];
+ *out++ = in[0];
+ *out++ = rgb == 0 ? 255 : rgba[3];
+ }
+}
+
+static void
+p2la(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ /* FIXME: precalculate greyscale palette? */
+ for (x = 0; x < xsize; x++, out += 4) {
+ const UINT8 *rgba = &palette->palette[*in++ * 4];
+ out[0] = out[1] = out[2] = L24(rgba) >> 16;
+ out[3] = rgba[3];
+ }
+}
+
+static void
+pa2la(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ /* FIXME: precalculate greyscale palette? */
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ out[0] = out[1] = out[2] = L24(&palette->palette[in[0] * 4]) >> 16;
+ out[3] = in[3];
+ }
+}
+
+static void
+p2i(UINT8 *out_, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ for (x = 0; x < xsize; x++, out_ += 4) {
+ INT32 v = L24(&palette->palette[in[x] * 4]) >> 16;
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+pa2i(UINT8 *out_, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ INT32 *out = (INT32 *)out_;
+ for (x = 0; x < xsize; x++, in += 4) {
+ *out++ = L24(&palette->palette[in[0] * 4]) >> 16;
+ }
+}
+
+static void
+p2f(UINT8 *out_, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ for (x = 0; x < xsize; x++, out_ += 4) {
+ FLOAT32 v = L(&palette->palette[in[x] * 4]) / 1000.0F;
+ memcpy(out_, &v, sizeof(v));
+ }
+}
+
+static void
+pa2f(UINT8 *out_, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ FLOAT32 *out = (FLOAT32 *)out_;
+ for (x = 0; x < xsize; x++, in += 4) {
+ *out++ = (float)L(&palette->palette[in[0] * 4]) / 1000.0F;
+ }
+}
+
+static void
+p2rgb(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ for (x = 0; x < xsize; x++) {
+ const UINT8 *rgb = &palette->palette[*in++ * 4];
+ *out++ = rgb[0];
+ *out++ = rgb[1];
+ *out++ = rgb[2];
+ *out++ = 255;
+ }
+}
+
+static void
+pa2rgb(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ const UINT8 *rgb = &palette->palette[in[0] * 4];
+ *out++ = rgb[0];
+ *out++ = rgb[1];
+ *out++ = rgb[2];
+ *out++ = 255;
+ }
+}
+
+static void
+p2hsv(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ for (x = 0; x < xsize; x++, out += 4) {
+ const UINT8 *rgb = &palette->palette[*in++ * 4];
+ rgb2hsv_row(out, rgb);
+ out[3] = 255;
+ }
+}
+
+static void
+pa2hsv(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4, out += 4) {
+ const UINT8 *rgb = &palette->palette[in[0] * 4];
+ rgb2hsv_row(out, rgb);
+ out[3] = 255;
+ }
+}
+
+static void
+p2rgba(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ for (x = 0; x < xsize; x++) {
+ const UINT8 *rgba = &palette->palette[*in++ * 4];
+ *out++ = rgba[0];
+ *out++ = rgba[1];
+ *out++ = rgba[2];
+ *out++ = rgba[3];
+ }
+}
+
+static void
+pa2rgba(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ int x;
+ for (x = 0; x < xsize; x++, in += 4) {
+ const UINT8 *rgb = &palette->palette[in[0] * 4];
+ *out++ = rgb[0];
+ *out++ = rgb[1];
+ *out++ = rgb[2];
+ *out++ = in[3];
+ }
+}
+
+static void
+p2cmyk(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ p2rgb(out, in, xsize, palette);
+ rgb2cmyk(out, out, xsize);
+}
+
+static void
+pa2cmyk(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ pa2rgb(out, in, xsize, palette);
+ rgb2cmyk(out, out, xsize);
+}
+
+static void
+p2ycbcr(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ p2rgb(out, in, xsize, palette);
+ ImagingConvertRGB2YCbCr(out, out, xsize);
+}
+
+static void
+pa2ycbcr(UINT8 *out, const UINT8 *in, int xsize, ImagingPalette palette) {
+ pa2rgb(out, in, xsize, palette);
+ ImagingConvertRGB2YCbCr(out, out, xsize);
+}
+
+static Imaging
+frompalette(Imaging imOut, Imaging imIn, const char *mode) {
+ ImagingSectionCookie cookie;
+ int alpha;
+ int y;
+ void (*convert)(UINT8 *, const UINT8 *, int, ImagingPalette);
+
+ /* Map palette image to L, RGB, RGBA, or CMYK */
+
+ if (!imIn->palette) {
+ return (Imaging)ImagingError_ValueError("no palette");
+ }
+
+ alpha = !strcmp(imIn->mode, "PA");
+
+ if (strcmp(mode, "1") == 0) {
+ convert = alpha ? pa2bit : p2bit;
+ } else if (strcmp(mode, "L") == 0) {
+ convert = alpha ? pa2l : p2l;
+ } else if (strcmp(mode, "LA") == 0) {
+ convert = alpha ? pa2la : p2la;
+ } else if (strcmp(mode, "P") == 0) {
+ convert = pa2p;
+ } else if (strcmp(mode, "PA") == 0) {
+ convert = p2pa;
+ } else if (strcmp(mode, "I") == 0) {
+ convert = alpha ? pa2i : p2i;
+ } else if (strcmp(mode, "F") == 0) {
+ convert = alpha ? pa2f : p2f;
+ } else if (strcmp(mode, "RGB") == 0) {
+ convert = alpha ? pa2rgb : p2rgb;
+ } else if (strcmp(mode, "RGBA") == 0 || strcmp(mode, "RGBX") == 0) {
+ convert = alpha ? pa2rgba : p2rgba;
+ } else if (strcmp(mode, "CMYK") == 0) {
+ convert = alpha ? pa2cmyk : p2cmyk;
+ } else if (strcmp(mode, "YCbCr") == 0) {
+ convert = alpha ? pa2ycbcr : p2ycbcr;
+ } else if (strcmp(mode, "HSV") == 0) {
+ convert = alpha ? pa2hsv : p2hsv;
+ } else {
+ return (Imaging)ImagingError_ValueError("conversion not supported");
+ }
+
+ imOut = ImagingNew2Dirty(mode, imOut, imIn);
+ if (!imOut) {
+ return NULL;
+ }
+ if (strcmp(mode, "P") == 0 || strcmp(mode, "PA") == 0) {
+ ImagingPaletteDelete(imOut->palette);
+ imOut->palette = ImagingPaletteDuplicate(imIn->palette);
+ }
+
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ (*convert)(
+ (UINT8 *)imOut->image[y],
+ (UINT8 *)imIn->image[y],
+ imIn->xsize,
+ imIn->palette);
+ }
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
+
+#if defined(_MSC_VER)
+#pragma optimize("", off)
+#endif
+static Imaging
+topalette(
+ Imaging imOut,
+ Imaging imIn,
+ const char *mode,
+ ImagingPalette inpalette,
+ int dither) {
+ ImagingSectionCookie cookie;
+ int alpha;
+ int x, y;
+ ImagingPalette palette = inpalette;
+
+ /* Map L or RGB/RGBX/RGBA to palette image */
+ if (strcmp(imIn->mode, "L") != 0 && strncmp(imIn->mode, "RGB", 3) != 0) {
+ return (Imaging)ImagingError_ValueError("conversion not supported");
+ }
+
+ alpha = !strcmp(mode, "PA");
+
+ if (palette == NULL) {
+ /* FIXME: make user configurable */
+ if (imIn->bands == 1) {
+ palette = ImagingPaletteNew("RGB");
+
+ palette->size = 256;
+ int i;
+ for (i = 0; i < 256; i++) {
+ palette->palette[i * 4] = palette->palette[i * 4 + 1] =
+ palette->palette[i * 4 + 2] = (UINT8)i;
+ }
+ } else {
+ palette = ImagingPaletteNewBrowser(); /* Standard colour cube */
+ }
+ }
+
+ if (!palette) {
+ return (Imaging)ImagingError_ValueError("no palette");
+ }
+
+ imOut = ImagingNew2Dirty(mode, imOut, imIn);
+ if (!imOut) {
+ if (palette != inpalette) {
+ ImagingPaletteDelete(palette);
+ }
+ return NULL;
+ }
+
+ ImagingPaletteDelete(imOut->palette);
+ imOut->palette = ImagingPaletteDuplicate(palette);
+
+ if (imIn->bands == 1) {
+ /* greyscale image */
+
+ /* Greyscale palette: copy data as is */
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ if (alpha) {
+ l2la((UINT8 *)imOut->image[y], (UINT8 *)imIn->image[y], imIn->xsize);
+ } else {
+ memcpy(imOut->image[y], imIn->image[y], imIn->linesize);
+ }
+ }
+ ImagingSectionLeave(&cookie);
+
+ } else {
+ /* colour image */
+
+ /* Create mapping cache */
+ if (ImagingPaletteCachePrepare(palette) < 0) {
+ ImagingDelete(imOut);
+ if (palette != inpalette) {
+ ImagingPaletteDelete(palette);
+ }
+ return NULL;
+ }
+
+ if (dither) {
+ /* floyd-steinberg dither */
+
+ int *errors;
+ errors = calloc(imIn->xsize + 1, sizeof(int) * 3);
+ if (!errors) {
+ ImagingDelete(imOut);
+ return ImagingError_MemoryError();
+ }
+
+ /* Map each pixel to the nearest palette entry */
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ int r, r0, r1, r2;
+ int g, g0, g1, g2;
+ int b, b0, b1, b2;
+ UINT8 *in = (UINT8 *)imIn->image[y];
+ UINT8 *out = alpha ? (UINT8 *)imOut->image32[y] : imOut->image8[y];
+ int *e = errors;
+
+ r = r0 = r1 = 0;
+ g = g0 = g1 = 0;
+ b = b0 = b1 = b2 = 0;
+
+ for (x = 0; x < imIn->xsize; x++, in += 4) {
+ int d2;
+ INT16 *cache;
+
+ r = CLIP8(in[0] + (r + e[3 + 0]) / 16);
+ g = CLIP8(in[1] + (g + e[3 + 1]) / 16);
+ b = CLIP8(in[2] + (b + e[3 + 2]) / 16);
+
+ /* get closest colour */
+ cache = &ImagingPaletteCache(palette, r, g, b);
+ if (cache[0] == 0x100) {
+ ImagingPaletteCacheUpdate(palette, r, g, b);
+ }
+ if (alpha) {
+ out[x * 4] = out[x * 4 + 1] = out[x * 4 + 2] = (UINT8)cache[0];
+ out[x * 4 + 3] = 255;
+ } else {
+ out[x] = (UINT8)cache[0];
+ }
+
+ r -= (int)palette->palette[cache[0] * 4];
+ g -= (int)palette->palette[cache[0] * 4 + 1];
+ b -= (int)palette->palette[cache[0] * 4 + 2];
+
+ /* propagate errors (don't ask ;-) */
+ r2 = r;
+ d2 = r + r;
+ r += d2;
+ e[0] = r + r0;
+ r += d2;
+ r0 = r + r1;
+ r1 = r2;
+ r += d2;
+ g2 = g;
+ d2 = g + g;
+ g += d2;
+ e[1] = g + g0;
+ g += d2;
+ g0 = g + g1;
+ g1 = g2;
+ g += d2;
+ b2 = b;
+ d2 = b + b;
+ b += d2;
+ e[2] = b + b0;
+ b += d2;
+ b0 = b + b1;
+ b1 = b2;
+ b += d2;
+
+ e += 3;
+ }
+
+ e[0] = b0;
+ e[1] = b1;
+ e[2] = b2;
+ }
+ ImagingSectionLeave(&cookie);
+ free(errors);
+
+ } else {
+ /* closest colour */
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ int r, g, b;
+ UINT8 *in = (UINT8 *)imIn->image[y];
+ UINT8 *out = alpha ? (UINT8 *)imOut->image32[y] : imOut->image8[y];
+
+ for (x = 0; x < imIn->xsize; x++, in += 4) {
+ INT16 *cache;
+
+ r = in[0];
+ g = in[1];
+ b = in[2];
+
+ /* get closest colour */
+ cache = &ImagingPaletteCache(palette, r, g, b);
+ if (cache[0] == 0x100) {
+ ImagingPaletteCacheUpdate(palette, r, g, b);
+ }
+ if (alpha) {
+ out[x * 4] = out[x * 4 + 1] = out[x * 4 + 2] = (UINT8)cache[0];
+ out[x * 4 + 3] = 255;
+ } else {
+ out[x] = (UINT8)cache[0];
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ }
+ if (inpalette != palette) {
+ ImagingPaletteCacheDelete(palette);
+ }
+ }
+
+ if (inpalette != palette) {
+ ImagingPaletteDelete(palette);
+ }
+
+ return imOut;
+}
+
+static Imaging
+tobilevel(Imaging imOut, Imaging imIn) {
+ ImagingSectionCookie cookie;
+ int x, y;
+ int *errors;
+
+ /* Map L or RGB to dithered 1 image */
+ if (strcmp(imIn->mode, "L") != 0 && strcmp(imIn->mode, "RGB") != 0) {
+ return (Imaging)ImagingError_ValueError("conversion not supported");
+ }
+
+ imOut = ImagingNew2Dirty("1", imOut, imIn);
+ if (!imOut) {
+ return NULL;
+ }
+
+ errors = calloc(imIn->xsize + 1, sizeof(int));
+ if (!errors) {
+ ImagingDelete(imOut);
+ return ImagingError_MemoryError();
+ }
+
+ if (imIn->bands == 1) {
+ /* map each pixel to black or white, using error diffusion */
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ int l, l0, l1, l2, d2;
+ UINT8 *in = (UINT8 *)imIn->image[y];
+ UINT8 *out = imOut->image8[y];
+
+ l = l0 = l1 = 0;
+
+ for (x = 0; x < imIn->xsize; x++) {
+ /* pick closest colour */
+ l = CLIP8(in[x] + (l + errors[x + 1]) / 16);
+ out[x] = (l > 128) ? 255 : 0;
+
+ /* propagate errors */
+ l -= (int)out[x];
+ l2 = l;
+ d2 = l + l;
+ l += d2;
+ errors[x] = l + l0;
+ l += d2;
+ l0 = l + l1;
+ l1 = l2;
+ l += d2;
+ }
+
+ errors[x] = l0;
+ }
+ ImagingSectionLeave(&cookie);
+
+ } else {
+ /* map each pixel to black or white, using error diffusion */
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ int l, l0, l1, l2, d2;
+ UINT8 *in = (UINT8 *)imIn->image[y];
+ UINT8 *out = imOut->image8[y];
+
+ l = l0 = l1 = 0;
+
+ for (x = 0; x < imIn->xsize; x++, in += 4) {
+ /* pick closest colour */
+ l = CLIP8(L(in) / 1000 + (l + errors[x + 1]) / 16);
+ out[x] = (l > 128) ? 255 : 0;
+
+ /* propagate errors */
+ l -= (int)out[x];
+ l2 = l;
+ d2 = l + l;
+ l += d2;
+ errors[x] = l + l0;
+ l += d2;
+ l0 = l + l1;
+ l1 = l2;
+ l += d2;
+ }
+
+ errors[x] = l0;
+ }
+ ImagingSectionLeave(&cookie);
+ }
+
+ free(errors);
+
+ return imOut;
+}
+#if defined(_MSC_VER)
+#pragma optimize("", on)
+#endif
+
+static Imaging
+convert(
+ Imaging imOut, Imaging imIn, const char *mode, ImagingPalette palette, int dither) {
+ ImagingSectionCookie cookie;
+ ImagingShuffler convert;
+ int y;
+
+ if (!imIn) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ if (!mode) {
+ /* Map palette image to full depth */
+ if (!imIn->palette) {
+ return (Imaging)ImagingError_ModeError();
+ }
+ mode = imIn->palette->mode;
+ } else {
+ /* Same mode? */
+ if (!strcmp(imIn->mode, mode)) {
+ return ImagingCopy2(imOut, imIn);
+ }
+ }
+
+ /* test for special conversions */
+
+ if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "PA") == 0) {
+ return frompalette(imOut, imIn, mode);
+ }
+
+ if (strcmp(mode, "P") == 0 || strcmp(mode, "PA") == 0) {
+ return topalette(imOut, imIn, mode, palette, dither);
+ }
+
+ if (dither && strcmp(mode, "1") == 0) {
+ return tobilevel(imOut, imIn);
+ }
+
+ /* standard conversion machinery */
+
+ convert = NULL;
+
+ for (y = 0; converters[y].from; y++) {
+ if (!strcmp(imIn->mode, converters[y].from) &&
+ !strcmp(mode, converters[y].to)) {
+ convert = converters[y].convert;
+ break;
+ }
+ }
+
+ if (!convert) {
+#ifdef notdef
+ return (Imaging)ImagingError_ValueError("conversion not supported");
+#else
+ static char buf[100];
+ snprintf(buf, 100, "conversion from %.10s to %.10s not supported", imIn->mode, mode);
+ return (Imaging)ImagingError_ValueError(buf);
+#endif
+ }
+
+ imOut = ImagingNew2Dirty(mode, imOut, imIn);
+ if (!imOut) {
+ return NULL;
+ }
+
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ (*convert)((UINT8 *)imOut->image[y], (UINT8 *)imIn->image[y], imIn->xsize);
+ }
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
+
+Imaging
+ImagingConvert(Imaging imIn, const char *mode, ImagingPalette palette, int dither) {
+ return convert(NULL, imIn, mode, palette, dither);
+}
+
+Imaging
+ImagingConvert2(Imaging imOut, Imaging imIn) {
+ return convert(imOut, imIn, imOut->mode, NULL, 0);
+}
+
+Imaging
+ImagingConvertTransparent(Imaging imIn, const char *mode, int r, int g, int b) {
+ ImagingSectionCookie cookie;
+ ImagingShuffler convert;
+ Imaging imOut = NULL;
+ int y;
+
+ if (!imIn) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ if (strcmp(imIn->mode, "RGB") == 0 && strcmp(mode, "RGBA") == 0) {
+ convert = rgb2rgba;
+ } else if ((strcmp(imIn->mode, "1") == 0 ||
+ strcmp(imIn->mode, "I") == 0 ||
+ strcmp(imIn->mode, "L") == 0
+ ) && (
+ strcmp(mode, "RGBA") == 0 ||
+ strcmp(mode, "LA") == 0
+ )) {
+ if (strcmp(imIn->mode, "1") == 0) {
+ convert = bit2rgb;
+ } else if (strcmp(imIn->mode, "I") == 0) {
+ convert = i2rgb;
+ } else {
+ convert = l2rgb;
+ }
+ g = b = r;
+ } else {
+ static char buf[100];
+ snprintf(
+ buf,
+ 100,
+ "conversion from %.10s to %.10s not supported in convert_transparent",
+ imIn->mode,
+ mode);
+ return (Imaging)ImagingError_ValueError(buf);
+ }
+
+ imOut = ImagingNew2Dirty(mode, imOut, imIn);
+ if (!imOut) {
+ return NULL;
+ }
+
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ (*convert)((UINT8 *)imOut->image[y], (UINT8 *)imIn->image[y], imIn->xsize);
+ rgbT2rgba((UINT8 *)imOut->image[y], imIn->xsize, r, g, b);
+ }
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
+
+Imaging
+ImagingConvertInPlace(Imaging imIn, const char *mode) {
+ ImagingSectionCookie cookie;
+ ImagingShuffler convert;
+ int y;
+
+ /* limited support for inplace conversion */
+ if (strcmp(imIn->mode, "L") == 0 && strcmp(mode, "1") == 0) {
+ convert = l2bit;
+ } else if (strcmp(imIn->mode, "1") == 0 && strcmp(mode, "L") == 0) {
+ convert = bit2l;
+ } else {
+ return ImagingError_ModeError();
+ }
+
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ (*convert)((UINT8 *)imIn->image[y], (UINT8 *)imIn->image[y], imIn->xsize);
+ }
+ ImagingSectionLeave(&cookie);
+
+ return imIn;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Convert.h b/contrib/python/Pillow/py3/libImaging/Convert.h
new file mode 100644
index 00000000000..e688e301836
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Convert.h
@@ -0,0 +1,2 @@
+extern void
+cmyk2rgb(UINT8 *out, const UINT8 *in, int xsize);
diff --git a/contrib/python/Pillow/py3/libImaging/ConvertYCbCr.c b/contrib/python/Pillow/py3/libImaging/ConvertYCbCr.c
new file mode 100644
index 00000000000..142f065e57d
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/ConvertYCbCr.c
@@ -0,0 +1,363 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * code to convert YCbCr data
+ *
+ * history:
+ * 98-07-01 hk Created
+ *
+ * Copyright (c) Secret Labs AB 1998
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+/* JPEG/JFIF YCbCr conversions
+
+ Y = R * 0.29900 + G * 0.58700 + B * 0.11400
+ Cb = R * -0.16874 + G * -0.33126 + B * 0.50000 + 128
+ Cr = R * 0.50000 + G * -0.41869 + B * -0.08131 + 128
+
+ R = Y + + (Cr - 128) * 1.40200
+ G = Y + (Cb - 128) * -0.34414 + (Cr - 128) * -0.71414
+ B = Y + (Cb - 128) * 1.77200
+
+*/
+
+#define SCALE 6 /* bits */
+
+static INT16 Y_R[] = {
+ 0, 19, 38, 57, 77, 96, 115, 134, 153, 172, 191, 210, 230, 249,
+ 268, 287, 306, 325, 344, 364, 383, 402, 421, 440, 459, 478, 498, 517,
+ 536, 555, 574, 593, 612, 631, 651, 670, 689, 708, 727, 746, 765, 785,
+ 804, 823, 842, 861, 880, 899, 919, 938, 957, 976, 995, 1014, 1033, 1052,
+ 1072, 1091, 1110, 1129, 1148, 1167, 1186, 1206, 1225, 1244, 1263, 1282, 1301, 1320,
+ 1340, 1359, 1378, 1397, 1416, 1435, 1454, 1473, 1493, 1512, 1531, 1550, 1569, 1588,
+ 1607, 1627, 1646, 1665, 1684, 1703, 1722, 1741, 1761, 1780, 1799, 1818, 1837, 1856,
+ 1875, 1894, 1914, 1933, 1952, 1971, 1990, 2009, 2028, 2048, 2067, 2086, 2105, 2124,
+ 2143, 2162, 2182, 2201, 2220, 2239, 2258, 2277, 2296, 2315, 2335, 2354, 2373, 2392,
+ 2411, 2430, 2449, 2469, 2488, 2507, 2526, 2545, 2564, 2583, 2602, 2622, 2641, 2660,
+ 2679, 2698, 2717, 2736, 2756, 2775, 2794, 2813, 2832, 2851, 2870, 2890, 2909, 2928,
+ 2947, 2966, 2985, 3004, 3023, 3043, 3062, 3081, 3100, 3119, 3138, 3157, 3177, 3196,
+ 3215, 3234, 3253, 3272, 3291, 3311, 3330, 3349, 3368, 3387, 3406, 3425, 3444, 3464,
+ 3483, 3502, 3521, 3540, 3559, 3578, 3598, 3617, 3636, 3655, 3674, 3693, 3712, 3732,
+ 3751, 3770, 3789, 3808, 3827, 3846, 3865, 3885, 3904, 3923, 3942, 3961, 3980, 3999,
+ 4019, 4038, 4057, 4076, 4095, 4114, 4133, 4153, 4172, 4191, 4210, 4229, 4248, 4267,
+ 4286, 4306, 4325, 4344, 4363, 4382, 4401, 4420, 4440, 4459, 4478, 4497, 4516, 4535,
+ 4554, 4574, 4593, 4612, 4631, 4650, 4669, 4688, 4707, 4727, 4746, 4765, 4784, 4803,
+ 4822, 4841, 4861, 4880};
+
+static INT16 Y_G[] = {
+ 0, 38, 75, 113, 150, 188, 225, 263, 301, 338, 376, 413, 451, 488,
+ 526, 564, 601, 639, 676, 714, 751, 789, 826, 864, 902, 939, 977, 1014,
+ 1052, 1089, 1127, 1165, 1202, 1240, 1277, 1315, 1352, 1390, 1428, 1465, 1503, 1540,
+ 1578, 1615, 1653, 1691, 1728, 1766, 1803, 1841, 1878, 1916, 1954, 1991, 2029, 2066,
+ 2104, 2141, 2179, 2217, 2254, 2292, 2329, 2367, 2404, 2442, 2479, 2517, 2555, 2592,
+ 2630, 2667, 2705, 2742, 2780, 2818, 2855, 2893, 2930, 2968, 3005, 3043, 3081, 3118,
+ 3156, 3193, 3231, 3268, 3306, 3344, 3381, 3419, 3456, 3494, 3531, 3569, 3607, 3644,
+ 3682, 3719, 3757, 3794, 3832, 3870, 3907, 3945, 3982, 4020, 4057, 4095, 4132, 4170,
+ 4208, 4245, 4283, 4320, 4358, 4395, 4433, 4471, 4508, 4546, 4583, 4621, 4658, 4696,
+ 4734, 4771, 4809, 4846, 4884, 4921, 4959, 4997, 5034, 5072, 5109, 5147, 5184, 5222,
+ 5260, 5297, 5335, 5372, 5410, 5447, 5485, 5522, 5560, 5598, 5635, 5673, 5710, 5748,
+ 5785, 5823, 5861, 5898, 5936, 5973, 6011, 6048, 6086, 6124, 6161, 6199, 6236, 6274,
+ 6311, 6349, 6387, 6424, 6462, 6499, 6537, 6574, 6612, 6650, 6687, 6725, 6762, 6800,
+ 6837, 6875, 6913, 6950, 6988, 7025, 7063, 7100, 7138, 7175, 7213, 7251, 7288, 7326,
+ 7363, 7401, 7438, 7476, 7514, 7551, 7589, 7626, 7664, 7701, 7739, 7777, 7814, 7852,
+ 7889, 7927, 7964, 8002, 8040, 8077, 8115, 8152, 8190, 8227, 8265, 8303, 8340, 8378,
+ 8415, 8453, 8490, 8528, 8566, 8603, 8641, 8678, 8716, 8753, 8791, 8828, 8866, 8904,
+ 8941, 8979, 9016, 9054, 9091, 9129, 9167, 9204, 9242, 9279, 9317, 9354, 9392, 9430,
+ 9467, 9505, 9542, 9580};
+
+static INT16 Y_B[] = {
+ 0, 7, 15, 22, 29, 36, 44, 51, 58, 66, 73, 80, 88, 95,
+ 102, 109, 117, 124, 131, 139, 146, 153, 161, 168, 175, 182, 190, 197,
+ 204, 212, 219, 226, 233, 241, 248, 255, 263, 270, 277, 285, 292, 299,
+ 306, 314, 321, 328, 336, 343, 350, 358, 365, 372, 379, 387, 394, 401,
+ 409, 416, 423, 430, 438, 445, 452, 460, 467, 474, 482, 489, 496, 503,
+ 511, 518, 525, 533, 540, 547, 554, 562, 569, 576, 584, 591, 598, 606,
+ 613, 620, 627, 635, 642, 649, 657, 664, 671, 679, 686, 693, 700, 708,
+ 715, 722, 730, 737, 744, 751, 759, 766, 773, 781, 788, 795, 803, 810,
+ 817, 824, 832, 839, 846, 854, 861, 868, 876, 883, 890, 897, 905, 912,
+ 919, 927, 934, 941, 948, 956, 963, 970, 978, 985, 992, 1000, 1007, 1014,
+ 1021, 1029, 1036, 1043, 1051, 1058, 1065, 1073, 1080, 1087, 1094, 1102, 1109, 1116,
+ 1124, 1131, 1138, 1145, 1153, 1160, 1167, 1175, 1182, 1189, 1197, 1204, 1211, 1218,
+ 1226, 1233, 1240, 1248, 1255, 1262, 1270, 1277, 1284, 1291, 1299, 1306, 1313, 1321,
+ 1328, 1335, 1342, 1350, 1357, 1364, 1372, 1379, 1386, 1394, 1401, 1408, 1415, 1423,
+ 1430, 1437, 1445, 1452, 1459, 1466, 1474, 1481, 1488, 1496, 1503, 1510, 1518, 1525,
+ 1532, 1539, 1547, 1554, 1561, 1569, 1576, 1583, 1591, 1598, 1605, 1612, 1620, 1627,
+ 1634, 1642, 1649, 1656, 1663, 1671, 1678, 1685, 1693, 1700, 1707, 1715, 1722, 1729,
+ 1736, 1744, 1751, 1758, 1766, 1773, 1780, 1788, 1795, 1802, 1809, 1817, 1824, 1831,
+ 1839, 1846, 1853, 1860};
+
+static INT16 Cb_R[] = {
+ 0, -10, -21, -31, -42, -53, -64, -75, -85, -96, -107, -118,
+ -129, -139, -150, -161, -172, -183, -193, -204, -215, -226, -237, -247,
+ -258, -269, -280, -291, -301, -312, -323, -334, -345, -355, -366, -377,
+ -388, -399, -409, -420, -431, -442, -453, -463, -474, -485, -496, -507,
+ -517, -528, -539, -550, -561, -571, -582, -593, -604, -615, -625, -636,
+ -647, -658, -669, -679, -690, -701, -712, -723, -733, -744, -755, -766,
+ -777, -787, -798, -809, -820, -831, -841, -852, -863, -874, -885, -895,
+ -906, -917, -928, -939, -949, -960, -971, -982, -993, -1003, -1014, -1025,
+ -1036, -1047, -1057, -1068, -1079, -1090, -1101, -1111, -1122, -1133, -1144, -1155,
+ -1165, -1176, -1187, -1198, -1209, -1219, -1230, -1241, -1252, -1263, -1273, -1284,
+ -1295, -1306, -1317, -1327, -1338, -1349, -1360, -1371, -1381, -1392, -1403, -1414,
+ -1425, -1435, -1446, -1457, -1468, -1479, -1489, -1500, -1511, -1522, -1533, -1543,
+ -1554, -1565, -1576, -1587, -1597, -1608, -1619, -1630, -1641, -1651, -1662, -1673,
+ -1684, -1694, -1705, -1716, -1727, -1738, -1748, -1759, -1770, -1781, -1792, -1802,
+ -1813, -1824, -1835, -1846, -1856, -1867, -1878, -1889, -1900, -1910, -1921, -1932,
+ -1943, -1954, -1964, -1975, -1986, -1997, -2008, -2018, -2029, -2040, -2051, -2062,
+ -2072, -2083, -2094, -2105, -2116, -2126, -2137, -2148, -2159, -2170, -2180, -2191,
+ -2202, -2213, -2224, -2234, -2245, -2256, -2267, -2278, -2288, -2299, -2310, -2321,
+ -2332, -2342, -2353, -2364, -2375, -2386, -2396, -2407, -2418, -2429, -2440, -2450,
+ -2461, -2472, -2483, -2494, -2504, -2515, -2526, -2537, -2548, -2558, -2569, -2580,
+ -2591, -2602, -2612, -2623, -2634, -2645, -2656, -2666, -2677, -2688, -2699, -2710,
+ -2720, -2731, -2742, -2753};
+
+static INT16 Cb_G[] = {
+ 0, -20, -41, -63, -84, -105, -126, -147, -169, -190, -211, -232,
+ -253, -275, -296, -317, -338, -359, -381, -402, -423, -444, -465, -487,
+ -508, -529, -550, -571, -593, -614, -635, -656, -677, -699, -720, -741,
+ -762, -783, -805, -826, -847, -868, -889, -911, -932, -953, -974, -995,
+ -1017, -1038, -1059, -1080, -1101, -1123, -1144, -1165, -1186, -1207, -1229, -1250,
+ -1271, -1292, -1313, -1335, -1356, -1377, -1398, -1419, -1441, -1462, -1483, -1504,
+ -1525, -1547, -1568, -1589, -1610, -1631, -1653, -1674, -1695, -1716, -1737, -1759,
+ -1780, -1801, -1822, -1843, -1865, -1886, -1907, -1928, -1949, -1971, -1992, -2013,
+ -2034, -2055, -2077, -2098, -2119, -2140, -2161, -2183, -2204, -2225, -2246, -2267,
+ -2289, -2310, -2331, -2352, -2373, -2395, -2416, -2437, -2458, -2479, -2501, -2522,
+ -2543, -2564, -2585, -2607, -2628, -2649, -2670, -2691, -2713, -2734, -2755, -2776,
+ -2797, -2819, -2840, -2861, -2882, -2903, -2925, -2946, -2967, -2988, -3009, -3031,
+ -3052, -3073, -3094, -3115, -3137, -3158, -3179, -3200, -3221, -3243, -3264, -3285,
+ -3306, -3328, -3349, -3370, -3391, -3412, -3434, -3455, -3476, -3497, -3518, -3540,
+ -3561, -3582, -3603, -3624, -3646, -3667, -3688, -3709, -3730, -3752, -3773, -3794,
+ -3815, -3836, -3858, -3879, -3900, -3921, -3942, -3964, -3985, -4006, -4027, -4048,
+ -4070, -4091, -4112, -4133, -4154, -4176, -4197, -4218, -4239, -4260, -4282, -4303,
+ -4324, -4345, -4366, -4388, -4409, -4430, -4451, -4472, -4494, -4515, -4536, -4557,
+ -4578, -4600, -4621, -4642, -4663, -4684, -4706, -4727, -4748, -4769, -4790, -4812,
+ -4833, -4854, -4875, -4896, -4918, -4939, -4960, -4981, -5002, -5024, -5045, -5066,
+ -5087, -5108, -5130, -5151, -5172, -5193, -5214, -5236, -5257, -5278, -5299, -5320,
+ -5342, -5363, -5384, -5405};
+
+static INT16 Cb_B[] = {
+ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416,
+ 448, 480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864,
+ 896, 928, 960, 992, 1024, 1056, 1088, 1120, 1152, 1184, 1216, 1248, 1280, 1312,
+ 1344, 1376, 1408, 1440, 1472, 1504, 1536, 1568, 1600, 1632, 1664, 1696, 1728, 1760,
+ 1792, 1824, 1856, 1888, 1920, 1952, 1984, 2016, 2048, 2080, 2112, 2144, 2176, 2208,
+ 2240, 2272, 2304, 2336, 2368, 2400, 2432, 2464, 2496, 2528, 2560, 2592, 2624, 2656,
+ 2688, 2720, 2752, 2784, 2816, 2848, 2880, 2912, 2944, 2976, 3008, 3040, 3072, 3104,
+ 3136, 3168, 3200, 3232, 3264, 3296, 3328, 3360, 3392, 3424, 3456, 3488, 3520, 3552,
+ 3584, 3616, 3648, 3680, 3712, 3744, 3776, 3808, 3840, 3872, 3904, 3936, 3968, 4000,
+ 4032, 4064, 4096, 4128, 4160, 4192, 4224, 4256, 4288, 4320, 4352, 4384, 4416, 4448,
+ 4480, 4512, 4544, 4576, 4608, 4640, 4672, 4704, 4736, 4768, 4800, 4832, 4864, 4896,
+ 4928, 4960, 4992, 5024, 5056, 5088, 5120, 5152, 5184, 5216, 5248, 5280, 5312, 5344,
+ 5376, 5408, 5440, 5472, 5504, 5536, 5568, 5600, 5632, 5664, 5696, 5728, 5760, 5792,
+ 5824, 5856, 5888, 5920, 5952, 5984, 6016, 6048, 6080, 6112, 6144, 6176, 6208, 6240,
+ 6272, 6304, 6336, 6368, 6400, 6432, 6464, 6496, 6528, 6560, 6592, 6624, 6656, 6688,
+ 6720, 6752, 6784, 6816, 6848, 6880, 6912, 6944, 6976, 7008, 7040, 7072, 7104, 7136,
+ 7168, 7200, 7232, 7264, 7296, 7328, 7360, 7392, 7424, 7456, 7488, 7520, 7552, 7584,
+ 7616, 7648, 7680, 7712, 7744, 7776, 7808, 7840, 7872, 7904, 7936, 7968, 8000, 8032,
+ 8064, 8096, 8128, 8160};
+
+#define Cr_R Cb_B
+
+static INT16 Cr_G[] = {
+ 0, -26, -53, -79, -106, -133, -160, -187, -213, -240, -267, -294,
+ -321, -347, -374, -401, -428, -455, -481, -508, -535, -562, -589, -615,
+ -642, -669, -696, -722, -749, -776, -803, -830, -856, -883, -910, -937,
+ -964, -990, -1017, -1044, -1071, -1098, -1124, -1151, -1178, -1205, -1232, -1258,
+ -1285, -1312, -1339, -1366, -1392, -1419, -1446, -1473, -1500, -1526, -1553, -1580,
+ -1607, -1634, -1660, -1687, -1714, -1741, -1768, -1794, -1821, -1848, -1875, -1902,
+ -1928, -1955, -1982, -2009, -2036, -2062, -2089, -2116, -2143, -2169, -2196, -2223,
+ -2250, -2277, -2303, -2330, -2357, -2384, -2411, -2437, -2464, -2491, -2518, -2545,
+ -2571, -2598, -2625, -2652, -2679, -2705, -2732, -2759, -2786, -2813, -2839, -2866,
+ -2893, -2920, -2947, -2973, -3000, -3027, -3054, -3081, -3107, -3134, -3161, -3188,
+ -3215, -3241, -3268, -3295, -3322, -3349, -3375, -3402, -3429, -3456, -3483, -3509,
+ -3536, -3563, -3590, -3616, -3643, -3670, -3697, -3724, -3750, -3777, -3804, -3831,
+ -3858, -3884, -3911, -3938, -3965, -3992, -4018, -4045, -4072, -4099, -4126, -4152,
+ -4179, -4206, -4233, -4260, -4286, -4313, -4340, -4367, -4394, -4420, -4447, -4474,
+ -4501, -4528, -4554, -4581, -4608, -4635, -4662, -4688, -4715, -4742, -4769, -4796,
+ -4822, -4849, -4876, -4903, -4929, -4956, -4983, -5010, -5037, -5063, -5090, -5117,
+ -5144, -5171, -5197, -5224, -5251, -5278, -5305, -5331, -5358, -5385, -5412, -5439,
+ -5465, -5492, -5519, -5546, -5573, -5599, -5626, -5653, -5680, -5707, -5733, -5760,
+ -5787, -5814, -5841, -5867, -5894, -5921, -5948, -5975, -6001, -6028, -6055, -6082,
+ -6109, -6135, -6162, -6189, -6216, -6243, -6269, -6296, -6323, -6350, -6376, -6403,
+ -6430, -6457, -6484, -6510, -6537, -6564, -6591, -6618, -6644, -6671, -6698, -6725,
+ -6752, -6778, -6805, -6832};
+
+static INT16 Cr_B[] = {
+ 0, -4, -9, -15, -20, -25, -30, -35, -41, -46, -51, -56,
+ -61, -67, -72, -77, -82, -87, -93, -98, -103, -108, -113, -119,
+ -124, -129, -134, -140, -145, -150, -155, -160, -166, -171, -176, -181,
+ -186, -192, -197, -202, -207, -212, -218, -223, -228, -233, -238, -244,
+ -249, -254, -259, -264, -270, -275, -280, -285, -290, -296, -301, -306,
+ -311, -316, -322, -327, -332, -337, -342, -348, -353, -358, -363, -368,
+ -374, -379, -384, -389, -394, -400, -405, -410, -415, -421, -426, -431,
+ -436, -441, -447, -452, -457, -462, -467, -473, -478, -483, -488, -493,
+ -499, -504, -509, -514, -519, -525, -530, -535, -540, -545, -551, -556,
+ -561, -566, -571, -577, -582, -587, -592, -597, -603, -608, -613, -618,
+ -623, -629, -634, -639, -644, -649, -655, -660, -665, -670, -675, -681,
+ -686, -691, -696, -702, -707, -712, -717, -722, -728, -733, -738, -743,
+ -748, -754, -759, -764, -769, -774, -780, -785, -790, -795, -800, -806,
+ -811, -816, -821, -826, -832, -837, -842, -847, -852, -858, -863, -868,
+ -873, -878, -884, -889, -894, -899, -904, -910, -915, -920, -925, -930,
+ -936, -941, -946, -951, -957, -962, -967, -972, -977, -983, -988, -993,
+ -998, -1003, -1009, -1014, -1019, -1024, -1029, -1035, -1040, -1045, -1050, -1055,
+ -1061, -1066, -1071, -1076, -1081, -1087, -1092, -1097, -1102, -1107, -1113, -1118,
+ -1123, -1128, -1133, -1139, -1144, -1149, -1154, -1159, -1165, -1170, -1175, -1180,
+ -1185, -1191, -1196, -1201, -1206, -1211, -1217, -1222, -1227, -1232, -1238, -1243,
+ -1248, -1253, -1258, -1264, -1269, -1274, -1279, -1284, -1290, -1295, -1300, -1305,
+ -1310, -1316, -1321, -1326};
+
+static INT16 R_Cr[] = {
+ -11484, -11394, -11305, -11215, -11125, -11036, -10946, -10856, -10766, -10677,
+ -10587, -10497, -10407, -10318, -10228, -10138, -10049, -9959, -9869, -9779,
+ -9690, -9600, -9510, -9420, -9331, -9241, -9151, -9062, -8972, -8882,
+ -8792, -8703, -8613, -8523, -8433, -8344, -8254, -8164, -8075, -7985,
+ -7895, -7805, -7716, -7626, -7536, -7446, -7357, -7267, -7177, -7088,
+ -6998, -6908, -6818, -6729, -6639, -6549, -6459, -6370, -6280, -6190,
+ -6101, -6011, -5921, -5831, -5742, -5652, -5562, -5472, -5383, -5293,
+ -5203, -5113, -5024, -4934, -4844, -4755, -4665, -4575, -4485, -4396,
+ -4306, -4216, -4126, -4037, -3947, -3857, -3768, -3678, -3588, -3498,
+ -3409, -3319, -3229, -3139, -3050, -2960, -2870, -2781, -2691, -2601,
+ -2511, -2422, -2332, -2242, -2152, -2063, -1973, -1883, -1794, -1704,
+ -1614, -1524, -1435, -1345, -1255, -1165, -1076, -986, -896, -807,
+ -717, -627, -537, -448, -358, -268, -178, -89, 0, 90,
+ 179, 269, 359, 449, 538, 628, 718, 808, 897, 987,
+ 1077, 1166, 1256, 1346, 1436, 1525, 1615, 1705, 1795, 1884,
+ 1974, 2064, 2153, 2243, 2333, 2423, 2512, 2602, 2692, 2782,
+ 2871, 2961, 3051, 3140, 3230, 3320, 3410, 3499, 3589, 3679,
+ 3769, 3858, 3948, 4038, 4127, 4217, 4307, 4397, 4486, 4576,
+ 4666, 4756, 4845, 4935, 5025, 5114, 5204, 5294, 5384, 5473,
+ 5563, 5653, 5743, 5832, 5922, 6012, 6102, 6191, 6281, 6371,
+ 6460, 6550, 6640, 6730, 6819, 6909, 6999, 7089, 7178, 7268,
+ 7358, 7447, 7537, 7627, 7717, 7806, 7896, 7986, 8076, 8165,
+ 8255, 8345, 8434, 8524, 8614, 8704, 8793, 8883, 8973, 9063,
+ 9152, 9242, 9332, 9421, 9511, 9601, 9691, 9780, 9870, 9960,
+ 10050, 10139, 10229, 10319, 10408, 10498, 10588, 10678, 10767, 10857,
+ 10947, 11037, 11126, 11216, 11306, 11395};
+
+static INT16 G_Cb[] = {
+ 2819, 2797, 2775, 2753, 2731, 2709, 2687, 2665, 2643, 2621, 2599, 2577,
+ 2555, 2533, 2511, 2489, 2467, 2445, 2423, 2401, 2379, 2357, 2335, 2313,
+ 2291, 2269, 2247, 2225, 2202, 2180, 2158, 2136, 2114, 2092, 2070, 2048,
+ 2026, 2004, 1982, 1960, 1938, 1916, 1894, 1872, 1850, 1828, 1806, 1784,
+ 1762, 1740, 1718, 1696, 1674, 1652, 1630, 1608, 1586, 1564, 1542, 1520,
+ 1498, 1476, 1454, 1432, 1410, 1388, 1366, 1344, 1321, 1299, 1277, 1255,
+ 1233, 1211, 1189, 1167, 1145, 1123, 1101, 1079, 1057, 1035, 1013, 991,
+ 969, 947, 925, 903, 881, 859, 837, 815, 793, 771, 749, 727,
+ 705, 683, 661, 639, 617, 595, 573, 551, 529, 507, 485, 463,
+ 440, 418, 396, 374, 352, 330, 308, 286, 264, 242, 220, 198,
+ 176, 154, 132, 110, 88, 66, 44, 22, 0, -21, -43, -65,
+ -87, -109, -131, -153, -175, -197, -219, -241, -263, -285, -307, -329,
+ -351, -373, -395, -417, -439, -462, -484, -506, -528, -550, -572, -594,
+ -616, -638, -660, -682, -704, -726, -748, -770, -792, -814, -836, -858,
+ -880, -902, -924, -946, -968, -990, -1012, -1034, -1056, -1078, -1100, -1122,
+ -1144, -1166, -1188, -1210, -1232, -1254, -1276, -1298, -1320, -1343, -1365, -1387,
+ -1409, -1431, -1453, -1475, -1497, -1519, -1541, -1563, -1585, -1607, -1629, -1651,
+ -1673, -1695, -1717, -1739, -1761, -1783, -1805, -1827, -1849, -1871, -1893, -1915,
+ -1937, -1959, -1981, -2003, -2025, -2047, -2069, -2091, -2113, -2135, -2157, -2179,
+ -2201, -2224, -2246, -2268, -2290, -2312, -2334, -2356, -2378, -2400, -2422, -2444,
+ -2466, -2488, -2510, -2532, -2554, -2576, -2598, -2620, -2642, -2664, -2686, -2708,
+ -2730, -2752, -2774, -2796};
+
+static INT16 G_Cr[] = {
+ 5850, 5805, 5759, 5713, 5667, 5622, 5576, 5530, 5485, 5439, 5393, 5347,
+ 5302, 5256, 5210, 5165, 5119, 5073, 5028, 4982, 4936, 4890, 4845, 4799,
+ 4753, 4708, 4662, 4616, 4570, 4525, 4479, 4433, 4388, 4342, 4296, 4251,
+ 4205, 4159, 4113, 4068, 4022, 3976, 3931, 3885, 3839, 3794, 3748, 3702,
+ 3656, 3611, 3565, 3519, 3474, 3428, 3382, 3336, 3291, 3245, 3199, 3154,
+ 3108, 3062, 3017, 2971, 2925, 2879, 2834, 2788, 2742, 2697, 2651, 2605,
+ 2559, 2514, 2468, 2422, 2377, 2331, 2285, 2240, 2194, 2148, 2102, 2057,
+ 2011, 1965, 1920, 1874, 1828, 1782, 1737, 1691, 1645, 1600, 1554, 1508,
+ 1463, 1417, 1371, 1325, 1280, 1234, 1188, 1143, 1097, 1051, 1006, 960,
+ 914, 868, 823, 777, 731, 686, 640, 594, 548, 503, 457, 411,
+ 366, 320, 274, 229, 183, 137, 91, 46, 0, -45, -90, -136,
+ -182, -228, -273, -319, -365, -410, -456, -502, -547, -593, -639, -685,
+ -730, -776, -822, -867, -913, -959, -1005, -1050, -1096, -1142, -1187, -1233,
+ -1279, -1324, -1370, -1416, -1462, -1507, -1553, -1599, -1644, -1690, -1736, -1781,
+ -1827, -1873, -1919, -1964, -2010, -2056, -2101, -2147, -2193, -2239, -2284, -2330,
+ -2376, -2421, -2467, -2513, -2558, -2604, -2650, -2696, -2741, -2787, -2833, -2878,
+ -2924, -2970, -3016, -3061, -3107, -3153, -3198, -3244, -3290, -3335, -3381, -3427,
+ -3473, -3518, -3564, -3610, -3655, -3701, -3747, -3793, -3838, -3884, -3930, -3975,
+ -4021, -4067, -4112, -4158, -4204, -4250, -4295, -4341, -4387, -4432, -4478, -4524,
+ -4569, -4615, -4661, -4707, -4752, -4798, -4844, -4889, -4935, -4981, -5027, -5072,
+ -5118, -5164, -5209, -5255, -5301, -5346, -5392, -5438, -5484, -5529, -5575, -5621,
+ -5666, -5712, -5758, -5804};
+
+static INT16 B_Cb[] = {
+ -14515, -14402, -14288, -14175, -14062, -13948, -13835, -13721, -13608, -13495,
+ -13381, -13268, -13154, -13041, -12928, -12814, -12701, -12587, -12474, -12360,
+ -12247, -12134, -12020, -11907, -11793, -11680, -11567, -11453, -11340, -11226,
+ -11113, -11000, -10886, -10773, -10659, -10546, -10433, -10319, -10206, -10092,
+ -9979, -9865, -9752, -9639, -9525, -9412, -9298, -9185, -9072, -8958,
+ -8845, -8731, -8618, -8505, -8391, -8278, -8164, -8051, -7938, -7824,
+ -7711, -7597, -7484, -7371, -7257, -7144, -7030, -6917, -6803, -6690,
+ -6577, -6463, -6350, -6236, -6123, -6010, -5896, -5783, -5669, -5556,
+ -5443, -5329, -5216, -5102, -4989, -4876, -4762, -4649, -4535, -4422,
+ -4309, -4195, -4082, -3968, -3855, -3741, -3628, -3515, -3401, -3288,
+ -3174, -3061, -2948, -2834, -2721, -2607, -2494, -2381, -2267, -2154,
+ -2040, -1927, -1814, -1700, -1587, -1473, -1360, -1246, -1133, -1020,
+ -906, -793, -679, -566, -453, -339, -226, -112, 0, 113,
+ 227, 340, 454, 567, 680, 794, 907, 1021, 1134, 1247,
+ 1361, 1474, 1588, 1701, 1815, 1928, 2041, 2155, 2268, 2382,
+ 2495, 2608, 2722, 2835, 2949, 3062, 3175, 3289, 3402, 3516,
+ 3629, 3742, 3856, 3969, 4083, 4196, 4310, 4423, 4536, 4650,
+ 4763, 4877, 4990, 5103, 5217, 5330, 5444, 5557, 5670, 5784,
+ 5897, 6011, 6124, 6237, 6351, 6464, 6578, 6691, 6804, 6918,
+ 7031, 7145, 7258, 7372, 7485, 7598, 7712, 7825, 7939, 8052,
+ 8165, 8279, 8392, 8506, 8619, 8732, 8846, 8959, 9073, 9186,
+ 9299, 9413, 9526, 9640, 9753, 9866, 9980, 10093, 10207, 10320,
+ 10434, 10547, 10660, 10774, 10887, 11001, 11114, 11227, 11341, 11454,
+ 11568, 11681, 11794, 11908, 12021, 12135, 12248, 12361, 12475, 12588,
+ 12702, 12815, 12929, 13042, 13155, 13269, 13382, 13496, 13609, 13722,
+ 13836, 13949, 14063, 14176, 14289, 14403};
+
+void
+ImagingConvertRGB2YCbCr(UINT8 *out, const UINT8 *in, int pixels) {
+ int x;
+ UINT8 a;
+ int r, g, b;
+ int y, cr, cb;
+
+ for (x = 0; x < pixels; x++, in += 4, out += 4) {
+ r = in[0];
+ g = in[1];
+ b = in[2];
+ a = in[3];
+
+ y = (Y_R[r] + Y_G[g] + Y_B[b]) >> SCALE;
+ cb = ((Cb_R[r] + Cb_G[g] + Cb_B[b]) >> SCALE) + 128;
+ cr = ((Cr_R[r] + Cr_G[g] + Cr_B[b]) >> SCALE) + 128;
+
+ out[0] = (UINT8)y;
+ out[1] = (UINT8)cb;
+ out[2] = (UINT8)cr;
+ out[3] = a;
+ }
+}
+
+void
+ImagingConvertYCbCr2RGB(UINT8 *out, const UINT8 *in, int pixels) {
+ int x;
+ UINT8 a;
+ int r, g, b;
+ int y, cr, cb;
+
+ for (x = 0; x < pixels; x++, in += 4, out += 4) {
+ y = in[0];
+ cb = in[1];
+ cr = in[2];
+ a = in[3];
+
+ r = y + ((R_Cr[cr]) >> SCALE);
+ g = y + ((G_Cb[cb] + G_Cr[cr]) >> SCALE);
+ b = y + ((B_Cb[cb]) >> SCALE);
+
+ out[0] = (r <= 0) ? 0 : (r >= 255) ? 255 : r;
+ out[1] = (g <= 0) ? 0 : (g >= 255) ? 255 : g;
+ out[2] = (b <= 0) ? 0 : (b >= 255) ? 255 : b;
+ out[3] = a;
+ }
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Copy.c b/contrib/python/Pillow/py3/libImaging/Copy.c
new file mode 100644
index 00000000000..571133e14b6
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Copy.c
@@ -0,0 +1,57 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * copy image
+ *
+ * history:
+ * 95-11-26 fl Moved from Imaging.c
+ * 97-05-12 fl Added ImagingCopy2
+ * 97-08-28 fl Allow imOut == NULL in ImagingCopy2
+ *
+ * Copyright (c) Fredrik Lundh 1995-97.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+static Imaging
+_copy(Imaging imOut, Imaging imIn) {
+ ImagingSectionCookie cookie;
+ int y;
+
+ if (!imIn) {
+ return (Imaging)ImagingError_ValueError(NULL);
+ }
+
+ imOut = ImagingNew2Dirty(imIn->mode, imOut, imIn);
+ if (!imOut) {
+ return NULL;
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+ ImagingSectionEnter(&cookie);
+ if (imIn->block != NULL && imOut->block != NULL) {
+ memcpy(imOut->block, imIn->block, imIn->ysize * imIn->linesize);
+ } else {
+ for (y = 0; y < imIn->ysize; y++) {
+ memcpy(imOut->image[y], imIn->image[y], imIn->linesize);
+ }
+ }
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
+
+Imaging
+ImagingCopy(Imaging imIn) {
+ return _copy(NULL, imIn);
+}
+
+Imaging
+ImagingCopy2(Imaging imOut, Imaging imIn) {
+ return _copy(imOut, imIn);
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Crop.c b/contrib/python/Pillow/py3/libImaging/Crop.c
new file mode 100644
index 00000000000..2425b4cd589
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Crop.c
@@ -0,0 +1,63 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * cut region from image
+ *
+ * history:
+ * 95-11-27 fl Created
+ * 98-07-10 fl Fixed "null result" error
+ * 99-02-05 fl Rewritten to use Paste primitive
+ *
+ * Copyright (c) Secret Labs AB 1997-99.
+ * Copyright (c) Fredrik Lundh 1995.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+Imaging
+ImagingCrop(Imaging imIn, int sx0, int sy0, int sx1, int sy1) {
+ Imaging imOut;
+ int xsize, ysize;
+ int dx0, dy0, dx1, dy1;
+ INT32 zero = 0;
+
+ if (!imIn) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ xsize = sx1 - sx0;
+ if (xsize < 0) {
+ xsize = 0;
+ }
+ ysize = sy1 - sy0;
+ if (ysize < 0) {
+ ysize = 0;
+ }
+
+ imOut = ImagingNewDirty(imIn->mode, xsize, ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+ if (sx0 < 0 || sy0 < 0 || sx1 > imIn->xsize || sy1 > imIn->ysize) {
+ (void)ImagingFill(imOut, &zero);
+ }
+
+ dx0 = -sx0;
+ dy0 = -sy0;
+ dx1 = imIn->xsize - sx0;
+ dy1 = imIn->ysize - sy0;
+
+ /* paste the source image on top of the output image!!! */
+ if (ImagingPaste(imOut, imIn, NULL, dx0, dy0, dx1, dy1) < 0) {
+ ImagingDelete(imOut);
+ return NULL;
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Dib.c b/contrib/python/Pillow/py3/libImaging/Dib.c
new file mode 100644
index 00000000000..f8a2901b8c7
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Dib.c
@@ -0,0 +1,313 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * imaging display object for Windows
+ *
+ * history:
+ * 1996-05-12 fl Created
+ * 1996-05-17 fl Up and running
+ * 1996-05-21 fl Added palette stuff
+ * 1996-05-26 fl Added query palette and mode inquery
+ * 1997-09-21 fl Added draw primitive
+ * 1998-01-20 fl Use StretchDIBits instead of StretchBlt
+ * 1998-12-30 fl Plugged a resource leak in DeleteDIB (from Roger Burnham)
+ *
+ * Copyright (c) Secret Labs AB 1997-2001.
+ * Copyright (c) Fredrik Lundh 1996.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#ifdef _WIN32
+
+#include "ImDib.h"
+
+char *
+ImagingGetModeDIB(int size_out[2]) {
+ /* Get device characteristics */
+
+ HDC dc;
+ char *mode;
+
+ dc = CreateCompatibleDC(NULL);
+
+ mode = "P";
+ if (!(GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE)) {
+ mode = "RGB";
+ if (GetDeviceCaps(dc, BITSPIXEL) == 1) {
+ mode = "1";
+ }
+ }
+
+ if (size_out) {
+ size_out[0] = GetDeviceCaps(dc, HORZRES);
+ size_out[1] = GetDeviceCaps(dc, VERTRES);
+ }
+
+ DeleteDC(dc);
+
+ return mode;
+}
+
+ImagingDIB
+ImagingNewDIB(const char *mode, int xsize, int ysize) {
+ /* Create a Windows bitmap */
+
+ ImagingDIB dib;
+ RGBQUAD *palette;
+ int i;
+
+ /* Check mode */
+ if (strcmp(mode, "1") != 0 && strcmp(mode, "L") != 0 && strcmp(mode, "RGB") != 0) {
+ return (ImagingDIB)ImagingError_ModeError();
+ }
+
+ /* Create DIB context and info header */
+ /* malloc check ok, small constant allocation */
+ dib = (ImagingDIB)malloc(sizeof(*dib));
+ if (!dib) {
+ return (ImagingDIB)ImagingError_MemoryError();
+ }
+ /* malloc check ok, small constant allocation */
+ dib->info = (BITMAPINFO *)malloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+ if (!dib->info) {
+ free(dib);
+ return (ImagingDIB)ImagingError_MemoryError();
+ }
+
+ memset(dib->info, 0, sizeof(BITMAPINFOHEADER));
+ dib->info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ dib->info->bmiHeader.biWidth = xsize;
+ dib->info->bmiHeader.biHeight = ysize;
+ dib->info->bmiHeader.biPlanes = 1;
+ dib->info->bmiHeader.biBitCount = strlen(mode) * 8;
+ dib->info->bmiHeader.biCompression = BI_RGB;
+
+ /* Create DIB */
+ dib->dc = CreateCompatibleDC(NULL);
+ if (!dib->dc) {
+ free(dib->info);
+ free(dib);
+ return (ImagingDIB)ImagingError_MemoryError();
+ }
+
+ dib->bitmap =
+ CreateDIBSection(dib->dc, dib->info, DIB_RGB_COLORS, &dib->bits, NULL, 0);
+ if (!dib->bitmap) {
+ free(dib->info);
+ free(dib);
+ return (ImagingDIB)ImagingError_MemoryError();
+ }
+
+ strcpy(dib->mode, mode);
+ dib->xsize = xsize;
+ dib->ysize = ysize;
+
+ dib->pixelsize = strlen(mode);
+ dib->linesize = (xsize * dib->pixelsize + 3) & -4;
+
+ if (dib->pixelsize == 1) {
+ dib->pack = dib->unpack = (ImagingShuffler)memcpy;
+ } else {
+ dib->pack = ImagingPackBGR;
+ dib->unpack = ImagingPackBGR;
+ }
+
+ /* Bind the DIB to the device context */
+ dib->old_bitmap = SelectObject(dib->dc, dib->bitmap);
+
+ palette = dib->info->bmiColors;
+
+ /* Bind a palette to it as well (only required for 8-bit DIBs) */
+ if (dib->pixelsize == 1) {
+ for (i = 0; i < 256; i++) {
+ palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = i;
+ palette[i].rgbReserved = 0;
+ }
+ SetDIBColorTable(dib->dc, 0, 256, palette);
+ }
+
+ /* Create an associated palette (for 8-bit displays only) */
+ if (strcmp(ImagingGetModeDIB(NULL), "P") == 0) {
+ char palbuf[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)];
+ LPLOGPALETTE pal = (LPLOGPALETTE)palbuf;
+ int i, r, g, b;
+
+ /* Load system palette */
+ pal->palVersion = 0x300;
+ pal->palNumEntries = 256;
+ GetSystemPaletteEntries(dib->dc, 0, 256, pal->palPalEntry);
+
+ if (strcmp(mode, "L") == 0) {
+ /* Greyscale DIB. Fill all 236 slots with a greyscale ramp
+ * (this is usually overkill on Windows since VGA only offers
+ * 6 bits greyscale resolution). Ignore the slots already
+ * allocated by Windows */
+
+ i = 10;
+ for (r = 0; r < 236; r++) {
+ pal->palPalEntry[i].peRed = pal->palPalEntry[i].peGreen =
+ pal->palPalEntry[i].peBlue = i;
+ i++;
+ }
+
+ dib->palette = CreatePalette(pal);
+
+ } else if (strcmp(mode, "RGB") == 0) {
+#ifdef CUBE216
+
+ /* Colour DIB. Create a 6x6x6 colour cube (216 entries) and
+ * add 20 extra greylevels for best result with greyscale
+ * images. */
+
+ i = 10;
+ for (r = 0; r < 256; r += 51) {
+ for (g = 0; g < 256; g += 51) {
+ for (b = 0; b < 256; b += 51) {
+ pal->palPalEntry[i].peRed = r;
+ pal->palPalEntry[i].peGreen = g;
+ pal->palPalEntry[i].peBlue = b;
+ i++;
+ }
+ }
+ }
+ for (r = 1; r < 22 - 1; r++) {
+ /* Black and white are already provided by the cube. */
+ pal->palPalEntry[i].peRed = pal->palPalEntry[i].peGreen =
+ pal->palPalEntry[i].peBlue = r * 255 / (22 - 1);
+ i++;
+ }
+
+#else
+
+ /* Colour DIB. Alternate palette. */
+
+ i = 10;
+ for (r = 0; r < 256; r += 37) {
+ for (g = 0; g < 256; g += 32) {
+ for (b = 0; b < 256; b += 64) {
+ pal->palPalEntry[i].peRed = r;
+ pal->palPalEntry[i].peGreen = g;
+ pal->palPalEntry[i].peBlue = b;
+ i++;
+ }
+ }
+ }
+
+#endif
+
+ dib->palette = CreatePalette(pal);
+ }
+ }
+
+ return dib;
+}
+
+void
+ImagingPasteDIB(ImagingDIB dib, Imaging im, int xy[4]) {
+ /* Paste image data into a bitmap */
+
+ /* FIXME: check size! */
+
+ int y;
+ for (y = 0; y < im->ysize; y++) {
+ dib->pack(
+ dib->bits + dib->linesize * (dib->ysize - (xy[1] + y) - 1) +
+ xy[0] * dib->pixelsize,
+ im->image[y],
+ im->xsize);
+ }
+}
+
+void
+ImagingExposeDIB(ImagingDIB dib, void *dc) {
+ /* Copy bitmap to display */
+
+ if (dib->palette != 0) {
+ SelectPalette((HDC)dc, dib->palette, FALSE);
+ }
+ BitBlt((HDC)dc, 0, 0, dib->xsize, dib->ysize, dib->dc, 0, 0, SRCCOPY);
+}
+
+void
+ImagingDrawDIB(ImagingDIB dib, void *dc, int dst[4], int src[4]) {
+ /* Copy bitmap to printer/display */
+
+ if (GetDeviceCaps((HDC)dc, RASTERCAPS) & RC_STRETCHDIB) {
+ /* stretchdib (printers) */
+ StretchDIBits(
+ (HDC)dc,
+ dst[0],
+ dst[1],
+ dst[2] - dst[0],
+ dst[3] - dst[1],
+ src[0],
+ src[1],
+ src[2] - src[0],
+ src[3] - src[1],
+ dib->bits,
+ dib->info,
+ DIB_RGB_COLORS,
+ SRCCOPY);
+ } else {
+ /* stretchblt (displays) */
+ if (dib->palette != 0) {
+ SelectPalette((HDC)dc, dib->palette, FALSE);
+ }
+ StretchBlt(
+ (HDC)dc,
+ dst[0],
+ dst[1],
+ dst[2] - dst[0],
+ dst[3] - dst[1],
+ dib->dc,
+ src[0],
+ src[1],
+ src[2] - src[0],
+ src[3] - src[1],
+ SRCCOPY);
+ }
+}
+
+int
+ImagingQueryPaletteDIB(ImagingDIB dib, void *dc) {
+ /* Install bitmap palette */
+
+ int n;
+
+ if (dib->palette != 0) {
+ /* Realize associated palette */
+ HPALETTE now = SelectPalette((HDC)dc, dib->palette, FALSE);
+ n = RealizePalette((HDC)dc);
+
+ /* Restore palette */
+ SelectPalette((HDC)dc, now, FALSE);
+
+ } else {
+ n = 0;
+ }
+
+ return n; /* number of colours that was changed */
+}
+
+void
+ImagingDeleteDIB(ImagingDIB dib) {
+ /* Clean up */
+
+ if (dib->palette) {
+ DeleteObject(dib->palette);
+ }
+ if (dib->bitmap) {
+ SelectObject(dib->dc, dib->old_bitmap);
+ DeleteObject(dib->bitmap);
+ }
+ if (dib->dc) {
+ DeleteDC(dib->dc);
+ }
+ free(dib->info);
+}
+
+#endif /* _WIN32 */
diff --git a/contrib/python/Pillow/py3/libImaging/Draw.c b/contrib/python/Pillow/py3/libImaging/Draw.c
new file mode 100644
index 00000000000..0ccf22d58dd
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Draw.c
@@ -0,0 +1,1948 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * a simple drawing package for the Imaging library
+ *
+ * history:
+ * 1996-04-13 fl Created.
+ * 1996-04-30 fl Added transforms and polygon support.
+ * 1996-08-12 fl Added filled polygons.
+ * 1996-11-05 fl Fixed float/int confusion in polygon filler
+ * 1997-07-04 fl Support 32-bit images (C++ would have been nice)
+ * 1998-09-09 fl Eliminated qsort casts; improved rectangle clipping
+ * 1998-09-10 fl Fixed fill rectangle to include lower edge (!)
+ * 1998-12-29 fl Added arc, chord, and pieslice primitives
+ * 1999-01-10 fl Added some level 2 ("arrow") stuff (experimental)
+ * 1999-02-06 fl Added bitmap primitive
+ * 1999-07-26 fl Eliminated a compiler warning
+ * 1999-07-31 fl Pass ink as void* instead of int
+ * 2002-12-10 fl Added experimental RGBA-on-RGB drawing
+ * 2004-09-04 fl Support simple wide lines (no joins)
+ * 2005-05-25 fl Fixed line width calculation
+ *
+ * Copyright (c) 1996-2006 by Fredrik Lundh
+ * Copyright (c) 1997-2006 by Secret Labs AB.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+/* FIXME: support fill/outline attribute for all filled shapes */
+/* FIXME: support zero-winding fill */
+/* FIXME: add drawing context, support affine transforms */
+/* FIXME: support clip window (and mask?) */
+
+#include "Imaging.h"
+
+#include <math.h>
+#include <stdint.h>
+
+#define CEIL(v) (int)ceil(v)
+#define FLOOR(v) ((v) >= 0.0 ? (int)(v) : (int)floor(v))
+
+#define INK8(ink) (*(UINT8 *)ink)
+#define INK16(ink) (*(UINT16 *)ink)
+
+/*
+ * Rounds around zero (up=away from zero, down=towards zero)
+ * This guarantees that ROUND_UP|DOWN(f) == -ROUND_UP|DOWN(-f)
+ */
+#define ROUND_UP(f) ((int)((f) >= 0.0 ? floor((f) + 0.5F) : -floor(fabs(f) + 0.5F)))
+#define ROUND_DOWN(f) ((int)((f) >= 0.0 ? ceil((f)-0.5F) : -ceil(fabs(f) - 0.5F)))
+
+/* -------------------------------------------------------------------- */
+/* Primitives */
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+ /* edge descriptor for polygon engine */
+ int d;
+ int x0, y0;
+ int xmin, ymin, xmax, ymax;
+ float dx;
+} Edge;
+
+/* Type used in "polygon*" functions */
+typedef void (*hline_handler)(Imaging, int, int, int, int);
+
+static inline void
+point8(Imaging im, int x, int y, int ink) {
+ if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize) {
+ if (strncmp(im->mode, "I;16", 4) == 0) {
+#ifdef WORDS_BIGENDIAN
+ im->image8[y][x * 2] = (UINT8)(ink >> 8);
+ im->image8[y][x * 2 + 1] = (UINT8)ink;
+#else
+ im->image8[y][x * 2] = (UINT8)ink;
+ im->image8[y][x * 2 + 1] = (UINT8)(ink >> 8);
+#endif
+ } else {
+ im->image8[y][x] = (UINT8)ink;
+ }
+ }
+}
+
+static inline void
+point32(Imaging im, int x, int y, int ink) {
+ if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize) {
+ im->image32[y][x] = ink;
+ }
+}
+
+static inline void
+point32rgba(Imaging im, int x, int y, int ink) {
+ unsigned int tmp;
+
+ if (x >= 0 && x < im->xsize && y >= 0 && y < im->ysize) {
+ UINT8 *out = (UINT8 *)im->image[y] + x * 4;
+ UINT8 *in = (UINT8 *)&ink;
+ out[0] = BLEND(in[3], out[0], in[0], tmp);
+ out[1] = BLEND(in[3], out[1], in[1], tmp);
+ out[2] = BLEND(in[3], out[2], in[2], tmp);
+ }
+}
+
+static inline void
+hline8(Imaging im, int x0, int y0, int x1, int ink) {
+ int pixelwidth;
+
+ if (y0 >= 0 && y0 < im->ysize) {
+ if (x0 < 0) {
+ x0 = 0;
+ } else if (x0 >= im->xsize) {
+ return;
+ }
+ if (x1 < 0) {
+ return;
+ } else if (x1 >= im->xsize) {
+ x1 = im->xsize - 1;
+ }
+ if (x0 <= x1) {
+ pixelwidth = strncmp(im->mode, "I;16", 4) == 0 ? 2 : 1;
+ memset(
+ im->image8[y0] + x0 * pixelwidth,
+ (UINT8)ink,
+ (x1 - x0 + 1) * pixelwidth);
+ }
+ }
+}
+
+static inline void
+hline32(Imaging im, int x0, int y0, int x1, int ink) {
+ INT32 *p;
+
+ if (y0 >= 0 && y0 < im->ysize) {
+ if (x0 < 0) {
+ x0 = 0;
+ } else if (x0 >= im->xsize) {
+ return;
+ }
+ if (x1 < 0) {
+ return;
+ } else if (x1 >= im->xsize) {
+ x1 = im->xsize - 1;
+ }
+ p = im->image32[y0];
+ while (x0 <= x1) {
+ p[x0++] = ink;
+ }
+ }
+}
+
+static inline void
+hline32rgba(Imaging im, int x0, int y0, int x1, int ink) {
+ unsigned int tmp;
+
+ if (y0 >= 0 && y0 < im->ysize) {
+ if (x0 < 0) {
+ x0 = 0;
+ } else if (x0 >= im->xsize) {
+ return;
+ }
+ if (x1 < 0) {
+ return;
+ } else if (x1 >= im->xsize) {
+ x1 = im->xsize - 1;
+ }
+ if (x0 <= x1) {
+ UINT8 *out = (UINT8 *)im->image[y0] + x0 * 4;
+ UINT8 *in = (UINT8 *)&ink;
+ while (x0 <= x1) {
+ out[0] = BLEND(in[3], out[0], in[0], tmp);
+ out[1] = BLEND(in[3], out[1], in[1], tmp);
+ out[2] = BLEND(in[3], out[2], in[2], tmp);
+ x0++;
+ out += 4;
+ }
+ }
+ }
+}
+
+static inline void
+line8(Imaging im, int x0, int y0, int x1, int y1, int ink) {
+ int i, n, e;
+ int dx, dy;
+ int xs, ys;
+
+ /* normalize coordinates */
+ dx = x1 - x0;
+ if (dx < 0) {
+ dx = -dx, xs = -1;
+ } else {
+ xs = 1;
+ }
+ dy = y1 - y0;
+ if (dy < 0) {
+ dy = -dy, ys = -1;
+ } else {
+ ys = 1;
+ }
+
+ n = (dx > dy) ? dx : dy;
+
+ if (dx == 0) {
+ /* vertical */
+ for (i = 0; i < dy; i++) {
+ point8(im, x0, y0, ink);
+ y0 += ys;
+ }
+
+ } else if (dy == 0) {
+ /* horizontal */
+ for (i = 0; i < dx; i++) {
+ point8(im, x0, y0, ink);
+ x0 += xs;
+ }
+
+ } else if (dx > dy) {
+ /* bresenham, horizontal slope */
+ n = dx;
+ dy += dy;
+ e = dy - dx;
+ dx += dx;
+
+ for (i = 0; i < n; i++) {
+ point8(im, x0, y0, ink);
+ if (e >= 0) {
+ y0 += ys;
+ e -= dx;
+ }
+ e += dy;
+ x0 += xs;
+ }
+
+ } else {
+ /* bresenham, vertical slope */
+ n = dy;
+ dx += dx;
+ e = dx - dy;
+ dy += dy;
+
+ for (i = 0; i < n; i++) {
+ point8(im, x0, y0, ink);
+ if (e >= 0) {
+ x0 += xs;
+ e -= dy;
+ }
+ e += dx;
+ y0 += ys;
+ }
+ }
+}
+
+static inline void
+line32(Imaging im, int x0, int y0, int x1, int y1, int ink) {
+ int i, n, e;
+ int dx, dy;
+ int xs, ys;
+
+ /* normalize coordinates */
+ dx = x1 - x0;
+ if (dx < 0) {
+ dx = -dx, xs = -1;
+ } else {
+ xs = 1;
+ }
+ dy = y1 - y0;
+ if (dy < 0) {
+ dy = -dy, ys = -1;
+ } else {
+ ys = 1;
+ }
+
+ n = (dx > dy) ? dx : dy;
+
+ if (dx == 0) {
+ /* vertical */
+ for (i = 0; i < dy; i++) {
+ point32(im, x0, y0, ink);
+ y0 += ys;
+ }
+
+ } else if (dy == 0) {
+ /* horizontal */
+ for (i = 0; i < dx; i++) {
+ point32(im, x0, y0, ink);
+ x0 += xs;
+ }
+
+ } else if (dx > dy) {
+ /* bresenham, horizontal slope */
+ n = dx;
+ dy += dy;
+ e = dy - dx;
+ dx += dx;
+
+ for (i = 0; i < n; i++) {
+ point32(im, x0, y0, ink);
+ if (e >= 0) {
+ y0 += ys;
+ e -= dx;
+ }
+ e += dy;
+ x0 += xs;
+ }
+
+ } else {
+ /* bresenham, vertical slope */
+ n = dy;
+ dx += dx;
+ e = dx - dy;
+ dy += dy;
+
+ for (i = 0; i < n; i++) {
+ point32(im, x0, y0, ink);
+ if (e >= 0) {
+ x0 += xs;
+ e -= dy;
+ }
+ e += dx;
+ y0 += ys;
+ }
+ }
+}
+
+static inline void
+line32rgba(Imaging im, int x0, int y0, int x1, int y1, int ink) {
+ int i, n, e;
+ int dx, dy;
+ int xs, ys;
+
+ /* normalize coordinates */
+ dx = x1 - x0;
+ if (dx < 0) {
+ dx = -dx, xs = -1;
+ } else {
+ xs = 1;
+ }
+ dy = y1 - y0;
+ if (dy < 0) {
+ dy = -dy, ys = -1;
+ } else {
+ ys = 1;
+ }
+
+ n = (dx > dy) ? dx : dy;
+
+ if (dx == 0) {
+ /* vertical */
+ for (i = 0; i < dy; i++) {
+ point32rgba(im, x0, y0, ink);
+ y0 += ys;
+ }
+
+ } else if (dy == 0) {
+ /* horizontal */
+ for (i = 0; i < dx; i++) {
+ point32rgba(im, x0, y0, ink);
+ x0 += xs;
+ }
+
+ } else if (dx > dy) {
+ /* bresenham, horizontal slope */
+ n = dx;
+ dy += dy;
+ e = dy - dx;
+ dx += dx;
+
+ for (i = 0; i < n; i++) {
+ point32rgba(im, x0, y0, ink);
+ if (e >= 0) {
+ y0 += ys;
+ e -= dx;
+ }
+ e += dy;
+ x0 += xs;
+ }
+
+ } else {
+ /* bresenham, vertical slope */
+ n = dy;
+ dx += dx;
+ e = dx - dy;
+ dy += dy;
+
+ for (i = 0; i < n; i++) {
+ point32rgba(im, x0, y0, ink);
+ if (e >= 0) {
+ x0 += xs;
+ e -= dy;
+ }
+ e += dx;
+ y0 += ys;
+ }
+ }
+}
+
+static int
+x_cmp(const void *x0, const void *x1) {
+ float diff = *((float *)x0) - *((float *)x1);
+ if (diff < 0) {
+ return -1;
+ } else if (diff > 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void
+draw_horizontal_lines(
+ Imaging im, int n, Edge *e, int ink, int *x_pos, int y, hline_handler hline) {
+ int i;
+ for (i = 0; i < n; i++) {
+ if (e[i].ymin == y && e[i].ymin == e[i].ymax) {
+ int xmax;
+ int xmin = e[i].xmin;
+ if (*x_pos != -1 && *x_pos < xmin) {
+ // Line would be after the current position
+ continue;
+ }
+
+ xmax = e[i].xmax;
+ if (*x_pos > xmin) {
+ // Line would be partway through x_pos, so increase the starting point
+ xmin = *x_pos;
+ if (xmax < xmin) {
+ // Line would now end before it started
+ continue;
+ }
+ }
+
+ (*hline)(im, xmin, e[i].ymin, xmax, ink);
+ *x_pos = xmax + 1;
+ }
+ }
+}
+
+/*
+ * Filled polygon draw function using scan line algorithm.
+ */
+static inline int
+polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler hline, int hasAlpha) {
+ Edge **edge_table;
+ float *xx;
+ int edge_count = 0;
+ int ymin = im->ysize - 1;
+ int ymax = 0;
+ int i, j, k;
+ float adjacent_line_x, adjacent_line_x_other_edge;
+
+ if (n <= 0) {
+ return 0;
+ }
+
+ /* Initialize the edge table and find polygon boundaries */
+ /* malloc check ok, using calloc */
+ edge_table = calloc(n, sizeof(Edge *));
+ if (!edge_table) {
+ return -1;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (ymin > e[i].ymin) {
+ ymin = e[i].ymin;
+ }
+ if (ymax < e[i].ymax) {
+ ymax = e[i].ymax;
+ }
+ if (e[i].ymin == e[i].ymax) {
+ if (hasAlpha != 1) {
+ (*hline)(im, e[i].xmin, e[i].ymin, e[i].xmax, ink);
+ }
+ continue;
+ }
+ edge_table[edge_count++] = (e + i);
+ }
+ if (ymin < 0) {
+ ymin = 0;
+ }
+ if (ymax > im->ysize) {
+ ymax = im->ysize;
+ }
+
+ /* Process the edge table with a scan line searching for intersections */
+ /* malloc check ok, using calloc */
+ xx = calloc(edge_count * 2, sizeof(float));
+ if (!xx) {
+ free(edge_table);
+ return -1;
+ }
+ for (; ymin <= ymax; ymin++) {
+ j = 0;
+ for (i = 0; i < edge_count; i++) {
+ Edge *current = edge_table[i];
+ if (ymin >= current->ymin && ymin <= current->ymax) {
+ xx[j++] = (ymin - current->y0) * current->dx + current->x0;
+
+ if (ymin == current->ymax && ymin < ymax) {
+ // Needed to draw consistent polygons
+ xx[j] = xx[j - 1];
+ j++;
+ } else if (current->dx != 0 && roundf(xx[j-1]) == xx[j-1]) {
+ // Connect discontiguous corners
+ for (k = 0; k < i; k++) {
+ Edge *other_edge = edge_table[k];
+ if ((current->dx > 0 && other_edge->dx <= 0) ||
+ (current->dx < 0 && other_edge->dx >= 0)) {
+ continue;
+ }
+ // Check if the two edges join to make a corner
+ if (((ymin == current->ymin && ymin == other_edge->ymin) ||
+ (ymin == current->ymax && ymin == other_edge->ymax)) &&
+ xx[j-1] == (ymin - other_edge->y0) * other_edge->dx + other_edge->x0) {
+ // Determine points from the edges on the next row
+ // Or if this is the last row, check the previous row
+ int offset = ymin == ymax ? -1 : 1;
+ adjacent_line_x = (ymin + offset - current->y0) * current->dx + current->x0;
+ adjacent_line_x_other_edge = (ymin + offset - other_edge->y0) * other_edge->dx + other_edge->x0;
+ if (ymin == current->ymax) {
+ if (current->dx > 0) {
+ xx[k] = fmax(adjacent_line_x, adjacent_line_x_other_edge) + 1;
+ } else {
+ xx[k] = fmin(adjacent_line_x, adjacent_line_x_other_edge) - 1;
+ }
+ } else {
+ if (current->dx > 0) {
+ xx[k] = fmin(adjacent_line_x, adjacent_line_x_other_edge);
+ } else {
+ xx[k] = fmax(adjacent_line_x, adjacent_line_x_other_edge) + 1;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ qsort(xx, j, sizeof(float), x_cmp);
+ if (hasAlpha == 1) {
+ int x_pos = j == 0 ? -1 : 0;
+ for (i = 1; i < j; i += 2) {
+ int x_end = ROUND_DOWN(xx[i]);
+ if (x_end < x_pos) {
+ // Line would be before the current position
+ continue;
+ }
+ draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline);
+ if (x_end < x_pos) {
+ // Line would be before the current position
+ continue;
+ }
+
+ int x_start = ROUND_UP(xx[i - 1]);
+ if (x_pos > x_start) {
+ // Line would be partway through x_pos, so increase the starting point
+ x_start = x_pos;
+ if (x_end < x_start) {
+ // Line would now end before it started
+ continue;
+ }
+ }
+ (*hline)(im, x_start, ymin, x_end, ink);
+ x_pos = x_end + 1;
+ }
+ draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline);
+ } else {
+ for (i = 1; i < j; i += 2) {
+ (*hline)(im, ROUND_UP(xx[i - 1]), ymin, ROUND_DOWN(xx[i]), ink);
+ }
+ }
+ }
+
+ free(xx);
+ free(edge_table);
+ return 0;
+}
+
+static inline int
+polygon8(Imaging im, int n, Edge *e, int ink, int eofill) {
+ return polygon_generic(im, n, e, ink, eofill, hline8, 0);
+}
+
+static inline int
+polygon32(Imaging im, int n, Edge *e, int ink, int eofill) {
+ return polygon_generic(im, n, e, ink, eofill, hline32, 0);
+}
+
+static inline int
+polygon32rgba(Imaging im, int n, Edge *e, int ink, int eofill) {
+ return polygon_generic(im, n, e, ink, eofill, hline32rgba, 1);
+}
+
+static inline void
+add_edge(Edge *e, int x0, int y0, int x1, int y1) {
+ /* printf("edge %d %d %d %d\n", x0, y0, x1, y1); */
+
+ if (x0 <= x1) {
+ e->xmin = x0, e->xmax = x1;
+ } else {
+ e->xmin = x1, e->xmax = x0;
+ }
+
+ if (y0 <= y1) {
+ e->ymin = y0, e->ymax = y1;
+ } else {
+ e->ymin = y1, e->ymax = y0;
+ }
+
+ if (y0 == y1) {
+ e->d = 0;
+ e->dx = 0.0;
+ } else {
+ e->dx = ((float)(x1 - x0)) / (y1 - y0);
+ if (y0 == e->ymin) {
+ e->d = 1;
+ } else {
+ e->d = -1;
+ }
+ }
+
+ e->x0 = x0;
+ e->y0 = y0;
+}
+
+typedef struct {
+ void (*point)(Imaging im, int x, int y, int ink);
+ void (*hline)(Imaging im, int x0, int y0, int x1, int ink);
+ void (*line)(Imaging im, int x0, int y0, int x1, int y1, int ink);
+ int (*polygon)(Imaging im, int n, Edge *e, int ink, int eofill);
+} DRAW;
+
+DRAW draw8 = {point8, hline8, line8, polygon8};
+DRAW draw32 = {point32, hline32, line32, polygon32};
+DRAW draw32rgba = {point32rgba, hline32rgba, line32rgba, polygon32rgba};
+
+/* -------------------------------------------------------------------- */
+/* Interface */
+/* -------------------------------------------------------------------- */
+
+#define DRAWINIT() \
+ if (im->image8) { \
+ draw = &draw8; \
+ if (strncmp(im->mode, "I;16", 4) == 0) { \
+ ink = INK16(ink_); \
+ } else { \
+ ink = INK8(ink_); \
+ } \
+ } else { \
+ draw = (op) ? &draw32rgba : &draw32; \
+ memcpy(&ink, ink_, sizeof(ink)); \
+ }
+
+int
+ImagingDrawPoint(Imaging im, int x0, int y0, const void *ink_, int op) {
+ DRAW *draw;
+ INT32 ink;
+
+ DRAWINIT();
+
+ draw->point(im, x0, y0, ink);
+
+ return 0;
+}
+
+int
+ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void *ink_, int op) {
+ DRAW *draw;
+ INT32 ink;
+
+ DRAWINIT();
+
+ draw->line(im, x0, y0, x1, y1, ink);
+
+ return 0;
+}
+
+int
+ImagingDrawWideLine(
+ Imaging im, int x0, int y0, int x1, int y1, const void *ink_, int width, int op) {
+ DRAW *draw;
+ INT32 ink;
+ int dx, dy;
+ double big_hypotenuse, small_hypotenuse, ratio_max, ratio_min;
+ int dxmin, dxmax, dymin, dymax;
+ Edge e[4];
+
+ DRAWINIT();
+
+ dx = x1 - x0;
+ dy = y1 - y0;
+ if (dx == 0 && dy == 0) {
+ draw->point(im, x0, y0, ink);
+ return 0;
+ }
+
+ big_hypotenuse = hypot(dx, dy);
+ small_hypotenuse = (width - 1) / 2.0;
+ ratio_max = ROUND_UP(small_hypotenuse) / big_hypotenuse;
+ ratio_min = ROUND_DOWN(small_hypotenuse) / big_hypotenuse;
+
+ dxmin = ROUND_DOWN(ratio_min * dy);
+ dxmax = ROUND_DOWN(ratio_max * dy);
+ dymin = ROUND_DOWN(ratio_min * dx);
+ dymax = ROUND_DOWN(ratio_max * dx);
+ {
+ int vertices[4][2] = {
+ {x0 - dxmin, y0 + dymax},
+ {x1 - dxmin, y1 + dymax},
+ {x1 + dxmax, y1 - dymin},
+ {x0 + dxmax, y0 - dymin}};
+
+ add_edge(e + 0, vertices[0][0], vertices[0][1], vertices[1][0], vertices[1][1]);
+ add_edge(e + 1, vertices[1][0], vertices[1][1], vertices[2][0], vertices[2][1]);
+ add_edge(e + 2, vertices[2][0], vertices[2][1], vertices[3][0], vertices[3][1]);
+ add_edge(e + 3, vertices[3][0], vertices[3][1], vertices[0][0], vertices[0][1]);
+
+ draw->polygon(im, 4, e, ink, 0);
+ }
+ return 0;
+}
+
+int
+ImagingDrawRectangle(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ const void *ink_,
+ int fill,
+ int width,
+ int op) {
+ int i;
+ int y;
+ int tmp;
+ DRAW *draw;
+ INT32 ink;
+
+ DRAWINIT();
+
+ if (y0 > y1) {
+ tmp = y0, y0 = y1, y1 = tmp;
+ }
+
+ if (fill) {
+ if (y0 < 0) {
+ y0 = 0;
+ } else if (y0 >= im->ysize) {
+ return 0;
+ }
+
+ if (y1 < 0) {
+ return 0;
+ } else if (y1 > im->ysize) {
+ y1 = im->ysize;
+ }
+
+ for (y = y0; y <= y1; y++) {
+ draw->hline(im, x0, y, x1, ink);
+ }
+
+ } else {
+ /* outline */
+ if (width == 0) {
+ width = 1;
+ }
+ for (i = 0; i < width; i++) {
+ draw->hline(im, x0, y0 + i, x1, ink);
+ draw->hline(im, x0, y1 - i, x1, ink);
+ draw->line(im, x1 - i, y0 + width, x1 - i, y1 - width + 1, ink);
+ draw->line(im, x0 + i, y0 + width, x0 + i, y1 - width + 1, ink);
+ }
+ }
+
+ return 0;
+}
+
+int
+ImagingDrawPolygon(Imaging im, int count, int *xy, const void *ink_, int fill, int width, int op) {
+ int i, n, x0, y0, x1, y1;
+ DRAW *draw;
+ INT32 ink;
+
+ if (count <= 0) {
+ return 0;
+ }
+
+ DRAWINIT();
+
+ if (fill) {
+ /* Build edge list */
+ /* malloc check ok, using calloc */
+ Edge *e = calloc(count, sizeof(Edge));
+ if (!e) {
+ (void)ImagingError_MemoryError();
+ return -1;
+ }
+ for (i = n = 0; i < count - 1; i++) {
+ x0 = xy[i * 2];
+ y0 = xy[i * 2 + 1];
+ x1 = xy[i * 2 + 2];
+ y1 = xy[i * 2 + 3];
+ if (y0 == y1 && i != 0 && y0 == xy[i * 2 - 1]) {
+ // This is a horizontal line,
+ // that immediately follows another horizontal line
+ Edge *last_e = &e[n-1];
+ if (x1 > x0 && x0 > xy[i * 2 - 2]) {
+ // They are both increasing in x
+ last_e->xmax = x1;
+ continue;
+ } else if (x1 < x0 && x0 < xy[i * 2 - 2]) {
+ // They are both decreasing in x
+ last_e->xmin = x1;
+ continue;
+ }
+ }
+ add_edge(&e[n++], x0, y0, x1, y1);
+ }
+ if (xy[i * 2] != xy[0] || xy[i * 2 + 1] != xy[1]) {
+ add_edge(&e[n++], xy[i * 2], xy[i * 2 + 1], xy[0], xy[1]);
+ }
+ draw->polygon(im, n, e, ink, 0);
+ free(e);
+
+ } else {
+ /* Outline */
+ if (width == 1) {
+ for (i = 0; i < count - 1; i++) {
+ draw->line(im, xy[i * 2], xy[i * 2 + 1], xy[i * 2 + 2], xy[i * 2 + 3], ink);
+ }
+ draw->line(im, xy[i * 2], xy[i * 2 + 1], xy[0], xy[1], ink);
+ } else {
+ for (i = 0; i < count - 1; i++) {
+ ImagingDrawWideLine(im, xy[i * 2], xy[i * 2 + 1], xy[i * 2 + 2], xy[i * 2 + 3], ink_, width, op);
+ }
+ ImagingDrawWideLine(im, xy[i * 2], xy[i * 2 + 1], xy[0], xy[1], ink_, width, op);
+ }
+ }
+
+ return 0;
+}
+
+int
+ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap, const void *ink, int op) {
+ return ImagingFill2(
+ im, ink, bitmap, x0, y0, x0 + bitmap->xsize, y0 + bitmap->ysize);
+}
+
+/* -------------------------------------------------------------------- */
+/* standard shapes */
+
+// Imagine 2D plane and ellipse with center in (0, 0) and semi-major axes a and b.
+// Then quarter_* stuff approximates its top right quarter (x, y >= 0) with integer
+// points from set {(2x+x0, 2y+y0) | x,y in Z} where x0, y0 are from {0, 1} and
+// are such that point (a, b) is in the set.
+
+typedef struct {
+ int32_t a, b, cx, cy, ex, ey;
+ int64_t a2, b2, a2b2;
+ int8_t finished;
+} quarter_state;
+
+void
+quarter_init(quarter_state *s, int32_t a, int32_t b) {
+ if (a < 0 || b < 0) {
+ s->finished = 1;
+ } else {
+ s->a = a;
+ s->b = b;
+ s->cx = a;
+ s->cy = b % 2;
+ s->ex = a % 2;
+ s->ey = b;
+ s->a2 = a * a;
+ s->b2 = b * b;
+ s->a2b2 = s->a2 * s->b2;
+ s->finished = 0;
+ }
+}
+
+// deviation of the point from ellipse curve, basically a substitution
+// of the point into the ellipse equation
+int64_t
+quarter_delta(quarter_state *s, int64_t x, int64_t y) {
+ return llabs(s->a2 * y * y + s->b2 * x * x - s->a2b2);
+}
+
+int8_t
+quarter_next(quarter_state *s, int32_t *ret_x, int32_t *ret_y) {
+ if (s->finished) {
+ return -1;
+ }
+ *ret_x = s->cx;
+ *ret_y = s->cy;
+ if (s->cx == s->ex && s->cy == s->ey) {
+ s->finished = 1;
+ } else {
+ // Bresenham's algorithm, possible optimization: only consider 2 of 3
+ // next points depending on current slope
+ int32_t nx = s->cx;
+ int32_t ny = s->cy + 2;
+ int64_t ndelta = quarter_delta(s, nx, ny);
+ if (nx > 1) {
+ int64_t newdelta = quarter_delta(s, s->cx - 2, s->cy + 2);
+ if (ndelta > newdelta) {
+ nx = s->cx - 2;
+ ny = s->cy + 2;
+ ndelta = newdelta;
+ }
+ newdelta = quarter_delta(s, s->cx - 2, s->cy);
+ if (ndelta > newdelta) {
+ nx = s->cx - 2;
+ ny = s->cy;
+ }
+ }
+ s->cx = nx;
+ s->cy = ny;
+ }
+ return 0;
+}
+
+// quarter_* stuff can "draw" a quarter of an ellipse with thickness 1, great.
+// Now we use ellipse_* stuff to join all four quarters of two different sized
+// ellipses and receive horizontal segments of a complete ellipse with
+// specified thickness.
+//
+// Still using integer grid with step 2 at this point (like in quarter_*)
+// to ease angle clipping in future.
+
+typedef struct {
+ quarter_state st_o, st_i;
+ int32_t py, pl, pr;
+ int32_t cy[4], cl[4], cr[4];
+ int8_t bufcnt;
+ int8_t finished;
+ int8_t leftmost;
+} ellipse_state;
+
+void
+ellipse_init(ellipse_state *s, int32_t a, int32_t b, int32_t w) {
+ s->bufcnt = 0;
+ s->leftmost = a % 2;
+ quarter_init(&s->st_o, a, b);
+ if (w < 1 || quarter_next(&s->st_o, &s->pr, &s->py) == -1) {
+ s->finished = 1;
+ } else {
+ s->finished = 0;
+ quarter_init(&s->st_i, a - 2 * (w - 1), b - 2 * (w - 1));
+ s->pl = s->leftmost;
+ }
+}
+
+int8_t
+ellipse_next(ellipse_state *s, int32_t *ret_x0, int32_t *ret_y, int32_t *ret_x1) {
+ if (s->bufcnt == 0) {
+ if (s->finished) {
+ return -1;
+ }
+ int32_t y = s->py;
+ int32_t l = s->pl;
+ int32_t r = s->pr;
+ int32_t cx = 0, cy = 0;
+ int8_t next_ret;
+ while ((next_ret = quarter_next(&s->st_o, &cx, &cy)) != -1 && cy <= y) {
+ }
+ if (next_ret == -1) {
+ s->finished = 1;
+ } else {
+ s->pr = cx;
+ s->py = cy;
+ }
+ while ((next_ret = quarter_next(&s->st_i, &cx, &cy)) != -1 && cy <= y) {
+ l = cx;
+ }
+ s->pl = next_ret == -1 ? s->leftmost : cx;
+
+ if ((l > 0 || l < r) && y > 0) {
+ s->cl[s->bufcnt] = l == 0 ? 2 : l;
+ s->cy[s->bufcnt] = y;
+ s->cr[s->bufcnt] = r;
+ ++s->bufcnt;
+ }
+ if (y > 0) {
+ s->cl[s->bufcnt] = -r;
+ s->cy[s->bufcnt] = y;
+ s->cr[s->bufcnt] = -l;
+ ++s->bufcnt;
+ }
+ if (l > 0 || l < r) {
+ s->cl[s->bufcnt] = l == 0 ? 2 : l;
+ s->cy[s->bufcnt] = -y;
+ s->cr[s->bufcnt] = r;
+ ++s->bufcnt;
+ }
+ s->cl[s->bufcnt] = -r;
+ s->cy[s->bufcnt] = -y;
+ s->cr[s->bufcnt] = -l;
+ ++s->bufcnt;
+ }
+ --s->bufcnt;
+ *ret_x0 = s->cl[s->bufcnt];
+ *ret_y = s->cy[s->bufcnt];
+ *ret_x1 = s->cr[s->bufcnt];
+ return 0;
+}
+
+// Clipping tree consists of half-plane clipping nodes and combining nodes.
+// We can throw a horizontal segment in such a tree and collect an ordered set
+// of resulting disjoint clipped segments organized into a sorted linked list
+// of their end points.
+typedef enum {
+ CT_AND, // intersection
+ CT_OR, // union
+ CT_CLIP // half-plane clipping
+} clip_type;
+
+typedef struct clip_node {
+ clip_type type;
+ double a, b, c; // half-plane coeffs, only used in clipping nodes
+ struct clip_node *l; // child pointers, are only non-NULL in combining nodes
+ struct clip_node *r;
+} clip_node;
+
+// Linked list for the ends of the clipped horizontal segments.
+// Since the segment is always horizontal, we don't need to store Y coordinate.
+typedef struct event_list {
+ int32_t x;
+ int8_t type; // used internally, 1 for the left end (smaller X), -1 for the
+ // right end; pointless in output since the output segments
+ // are disjoint, therefore the types would always come in pairs
+ // and interchange (1 -1 1 -1 ...)
+ struct event_list *next;
+} event_list;
+
+// Mirrors all the clipping nodes of the tree relative to the y = x line.
+void
+clip_tree_transpose(clip_node *root) {
+ if (root != NULL) {
+ if (root->type == CT_CLIP) {
+ double t = root->a;
+ root->a = root->b;
+ root->b = t;
+ }
+ clip_tree_transpose(root->l);
+ clip_tree_transpose(root->r);
+ }
+}
+
+// Outputs a sequence of open-close events (types -1 and 1) for
+// non-intersecting segments sorted by X coordinate.
+// Combining nodes (AND, OR) may also accept sequences for intersecting
+// segments, i.e. something like correct bracket sequences.
+int
+clip_tree_do_clip(
+ clip_node *root, int32_t x0, int32_t y, int32_t x1, event_list **ret) {
+ if (root == NULL) {
+ event_list *start = malloc(sizeof(event_list));
+ if (!start) {
+ ImagingError_MemoryError();
+ return -1;
+ }
+ event_list *end = malloc(sizeof(event_list));
+ if (!end) {
+ free(start);
+ ImagingError_MemoryError();
+ return -1;
+ }
+ start->x = x0;
+ start->type = 1;
+ start->next = end;
+ end->x = x1;
+ end->type = -1;
+ end->next = NULL;
+ *ret = start;
+ return 0;
+ }
+ if (root->type == CT_CLIP) {
+ double eps = 1e-9;
+ double A = root->a;
+ double B = root->b;
+ double C = root->c;
+ if (fabs(A) < eps) {
+ if (B * y + C < -eps) {
+ x0 = 1;
+ x1 = 0;
+ }
+ } else {
+ // X of intersection
+ double ix = -(B * y + C) / A;
+ if (A * x0 + B * y + C < eps) {
+ x0 = lround(fmax(x0, ix));
+ }
+ if (A * x1 + B * y + C < eps) {
+ x1 = lround(fmin(x1, ix));
+ }
+ }
+ if (x0 <= x1) {
+ event_list *start = malloc(sizeof(event_list));
+ if (!start) {
+ ImagingError_MemoryError();
+ return -1;
+ }
+ event_list *end = malloc(sizeof(event_list));
+ if (!end) {
+ free(start);
+ ImagingError_MemoryError();
+ return -1;
+ }
+ start->x = x0;
+ start->type = 1;
+ start->next = end;
+ end->x = x1;
+ end->type = -1;
+ end->next = NULL;
+ *ret = start;
+ } else {
+ *ret = NULL;
+ }
+ return 0;
+ }
+ if (root->type == CT_OR || root->type == CT_AND) {
+ event_list *l1;
+ event_list *l2;
+ if (clip_tree_do_clip(root->l, x0, y, x1, &l1) < 0) {
+ return -1;
+ }
+ if (clip_tree_do_clip(root->r, x0, y, x1, &l2) < 0) {
+ while (l1) {
+ l2 = l1->next;
+ free(l1);
+ l1 = l2;
+ }
+ return -1;
+ }
+ *ret = NULL;
+ event_list *tail = NULL;
+ int32_t k1 = 0;
+ int32_t k2 = 0;
+ while (l1 != NULL || l2 != NULL) {
+ event_list *t;
+ if (l2 == NULL ||
+ (l1 != NULL &&
+ (l1->x < l2->x || (l1->x == l2->x && l1->type > l2->type)))) {
+ t = l1;
+ k1 += t->type;
+ assert(k1 >= 0);
+ l1 = l1->next;
+ } else {
+ t = l2;
+ k2 += t->type;
+ assert(k2 >= 0);
+ l2 = l2->next;
+ }
+ t->next = NULL;
+ if ((root->type == CT_OR &&
+ ((t->type == 1 && (tail == NULL || tail->type == -1)) ||
+ (t->type == -1 && k1 == 0 && k2 == 0))) ||
+ (root->type == CT_AND &&
+ ((t->type == 1 && (tail == NULL || tail->type == -1) && k1 > 0 &&
+ k2 > 0) ||
+ (t->type == -1 && tail != NULL && tail->type == 1 &&
+ (k1 == 0 || k2 == 0))))) {
+ if (tail == NULL) {
+ *ret = t;
+ } else {
+ tail->next = t;
+ }
+ tail = t;
+ } else {
+ free(t);
+ }
+ }
+ return 0;
+ }
+ *ret = NULL;
+ return 0;
+}
+
+// One more layer of processing on top of the regular ellipse.
+// Uses the clipping tree.
+// Used for producing ellipse derivatives such as arc, chord, pie, etc.
+typedef struct {
+ ellipse_state st;
+ clip_node *root;
+ clip_node nodes[7];
+ int32_t node_count;
+ event_list *head;
+ int32_t y;
+} clip_ellipse_state;
+
+typedef void (*clip_ellipse_init)(
+ clip_ellipse_state *, int32_t, int32_t, int32_t, float, float);
+
+void
+debug_clip_tree(clip_node *root, int space) {
+ if (root == NULL) {
+ return;
+ }
+ if (root->type == CT_CLIP) {
+ int t = space;
+ while (t--) {
+ fputc(' ', stderr);
+ }
+ fprintf(stderr, "clip %+fx%+fy%+f > 0\n", root->a, root->b, root->c);
+ } else {
+ debug_clip_tree(root->l, space + 2);
+ int t = space;
+ while (t--) {
+ fputc(' ', stderr);
+ }
+ fprintf(stderr, "%s\n", root->type == CT_AND ? "and" : "or");
+ debug_clip_tree(root->r, space + 2);
+ }
+ if (space == 0) {
+ fputc('\n', stderr);
+ }
+}
+
+// Resulting angles will satisfy 0 <= al < 360, al <= ar <= al + 360
+void
+normalize_angles(float *al, float *ar) {
+ if (*ar - *al >= 360) {
+ *al = 0;
+ *ar = 360;
+ } else {
+ *al = fmod(*al < 0 ? 360 - (fmod(-*al, 360)) : *al, 360);
+ *ar = *al + fmod(*ar < *al ? 360 - fmod(*al - *ar, 360) : *ar - *al, 360);
+ }
+}
+
+// An arc with caps orthogonal to the ellipse curve.
+void
+arc_init(clip_ellipse_state *s, int32_t a, int32_t b, int32_t w, float al, float ar) {
+ if (a < b) {
+ // transpose the coordinate system
+ arc_init(s, b, a, w, 90 - ar, 90 - al);
+ ellipse_init(&s->st, a, b, w);
+ clip_tree_transpose(s->root);
+ } else {
+ // a >= b, based on "wide" ellipse
+ ellipse_init(&s->st, a, b, w);
+
+ s->head = NULL;
+ s->node_count = 0;
+ normalize_angles(&al, &ar);
+
+ // building clipping tree, a lot of different cases
+ if (ar == al + 360) {
+ s->root = NULL;
+ } else {
+ clip_node *lc = s->nodes + s->node_count++;
+ clip_node *rc = s->nodes + s->node_count++;
+ lc->l = lc->r = rc->l = rc->r = NULL;
+ lc->type = rc->type = CT_CLIP;
+ lc->a = -a * sin(al * M_PI / 180.0);
+ lc->b = b * cos(al * M_PI / 180.0);
+ lc->c = (a * a - b * b) * sin(al * M_PI / 90.0) / 2.0;
+ rc->a = a * sin(ar * M_PI / 180.0);
+ rc->b = -b * cos(ar * M_PI / 180.0);
+ rc->c = (b * b - a * a) * sin(ar * M_PI / 90.0) / 2.0;
+ if (fmod(al, 180) == 0 || fmod(ar, 180) == 0) {
+ s->root = s->nodes + s->node_count++;
+ s->root->l = lc;
+ s->root->r = rc;
+ s->root->type = ar - al < 180 ? CT_AND : CT_OR;
+ } else if (((int)(al / 180) + (int)(ar / 180)) % 2 == 1) {
+ s->root = s->nodes + s->node_count++;
+ s->root->l = s->nodes + s->node_count++;
+ s->root->l->l = s->nodes + s->node_count++;
+ s->root->l->r = lc;
+ s->root->r = s->nodes + s->node_count++;
+ s->root->r->l = s->nodes + s->node_count++;
+ s->root->r->r = rc;
+ s->root->type = CT_OR;
+ s->root->l->type = CT_AND;
+ s->root->r->type = CT_AND;
+ s->root->l->l->type = CT_CLIP;
+ s->root->r->l->type = CT_CLIP;
+ s->root->l->l->l = s->root->l->l->r = NULL;
+ s->root->r->l->l = s->root->r->l->r = NULL;
+ s->root->l->l->a = s->root->l->l->c = 0;
+ s->root->r->l->a = s->root->r->l->c = 0;
+ s->root->l->l->b = (int)(al / 180) % 2 == 0 ? 1 : -1;
+ s->root->r->l->b = (int)(ar / 180) % 2 == 0 ? 1 : -1;
+ } else {
+ s->root = s->nodes + s->node_count++;
+ s->root->l = s->nodes + s->node_count++;
+ s->root->r = s->nodes + s->node_count++;
+ s->root->type = s->root->l->type = ar - al < 180 ? CT_AND : CT_OR;
+ s->root->l->l = lc;
+ s->root->l->r = rc;
+ s->root->r->type = CT_CLIP;
+ s->root->r->l = s->root->r->r = NULL;
+ s->root->r->a = s->root->r->c = 0;
+ s->root->r->b = ar < 180 || ar > 540 ? 1 : -1;
+ }
+ }
+ }
+}
+
+// A chord line.
+void
+chord_line_init(
+ clip_ellipse_state *s, int32_t a, int32_t b, int32_t w, float al, float ar) {
+ ellipse_init(&s->st, a, b, a + b + 1);
+
+ s->head = NULL;
+ s->node_count = 0;
+
+ // line equation for chord
+ double xl = a * cos(al * M_PI / 180.0), xr = a * cos(ar * M_PI / 180.0);
+ double yl = b * sin(al * M_PI / 180.0), yr = b * sin(ar * M_PI / 180.0);
+ s->root = s->nodes + s->node_count++;
+ s->root->l = s->nodes + s->node_count++;
+ s->root->r = s->nodes + s->node_count++;
+ s->root->type = CT_AND;
+ s->root->l->type = s->root->r->type = CT_CLIP;
+ s->root->l->l = s->root->l->r = s->root->r->l = s->root->r->r = NULL;
+ s->root->l->a = yr - yl;
+ s->root->l->b = xl - xr;
+ s->root->l->c = -(s->root->l->a * xl + s->root->l->b * yl);
+ s->root->r->a = -s->root->l->a;
+ s->root->r->b = -s->root->l->b;
+ s->root->r->c =
+ 2 * w * sqrt(pow(s->root->l->a, 2.0) + pow(s->root->l->b, 2.0)) - s->root->l->c;
+}
+
+// Pie side.
+void
+pie_side_init(
+ clip_ellipse_state *s, int32_t a, int32_t b, int32_t w, float al, float _) {
+ ellipse_init(&s->st, a, b, a + b + 1);
+
+ s->head = NULL;
+ s->node_count = 0;
+
+ double xl = a * cos(al * M_PI / 180.0);
+ double yl = b * sin(al * M_PI / 180.0);
+ double a1 = -yl;
+ double b1 = xl;
+ double c1 = w * sqrt(a1 * a1 + b1 * b1);
+
+ s->root = s->nodes + s->node_count++;
+ s->root->type = CT_AND;
+ s->root->l = s->nodes + s->node_count++;
+ s->root->l->type = CT_AND;
+
+ clip_node *cnode;
+ cnode = s->nodes + s->node_count++;
+ cnode->l = cnode->r = NULL;
+ cnode->type = CT_CLIP;
+ cnode->a = a1;
+ cnode->b = b1;
+ cnode->c = c1;
+ s->root->l->l = cnode;
+ cnode = s->nodes + s->node_count++;
+ cnode->l = cnode->r = NULL;
+ cnode->type = CT_CLIP;
+ cnode->a = -a1;
+ cnode->b = -b1;
+ cnode->c = c1;
+ s->root->l->r = cnode;
+ cnode = s->nodes + s->node_count++;
+ cnode->l = cnode->r = NULL;
+ cnode->type = CT_CLIP;
+ cnode->a = b1;
+ cnode->b = -a1;
+ cnode->c = 0;
+ s->root->r = cnode;
+}
+
+// A chord.
+void
+chord_init(clip_ellipse_state *s, int32_t a, int32_t b, int32_t w, float al, float ar) {
+ ellipse_init(&s->st, a, b, w);
+
+ s->head = NULL;
+ s->node_count = 0;
+
+ // line equation for chord
+ double xl = a * cos(al * M_PI / 180.0), xr = a * cos(ar * M_PI / 180.0);
+ double yl = b * sin(al * M_PI / 180.0), yr = b * sin(ar * M_PI / 180.0);
+ s->root = s->nodes + s->node_count++;
+ s->root->l = s->root->r = NULL;
+ s->root->type = CT_CLIP;
+ s->root->a = yr - yl;
+ s->root->b = xl - xr;
+ s->root->c = -(s->root->a * xl + s->root->b * yl);
+}
+
+// A pie. Can also be used to draw an arc with ugly sharp caps.
+void
+pie_init(clip_ellipse_state *s, int32_t a, int32_t b, int32_t w, float al, float ar) {
+ ellipse_init(&s->st, a, b, w);
+
+ s->head = NULL;
+ s->node_count = 0;
+
+ // line equations for pie sides
+ double xl = a * cos(al * M_PI / 180.0), xr = a * cos(ar * M_PI / 180.0);
+ double yl = b * sin(al * M_PI / 180.0), yr = b * sin(ar * M_PI / 180.0);
+
+ clip_node *lc = s->nodes + s->node_count++;
+ clip_node *rc = s->nodes + s->node_count++;
+ lc->l = lc->r = rc->l = rc->r = NULL;
+ lc->type = rc->type = CT_CLIP;
+ lc->a = -yl;
+ lc->b = xl;
+ lc->c = 0;
+ rc->a = yr;
+ rc->b = -xr;
+ rc->c = 0;
+
+ s->root = s->nodes + s->node_count++;
+ s->root->l = lc;
+ s->root->r = rc;
+ s->root->type = ar - al < 180 ? CT_AND : CT_OR;
+
+ // add one more semiplane to avoid spikes
+ if (ar - al < 90) {
+ clip_node *old_root = s->root;
+ clip_node *spike_clipper = s->nodes + s->node_count++;
+ s->root = s->nodes + s->node_count++;
+ s->root->l = old_root;
+ s->root->r = spike_clipper;
+ s->root->type = CT_AND;
+
+ spike_clipper->l = spike_clipper->r = NULL;
+ spike_clipper->type = CT_CLIP;
+ spike_clipper->a = (xl + xr) / 2.0;
+ spike_clipper->b = (yl + yr) / 2.0;
+ spike_clipper->c = 0;
+ }
+}
+
+void
+clip_ellipse_free(clip_ellipse_state *s) {
+ while (s->head != NULL) {
+ event_list *t = s->head;
+ s->head = s->head->next;
+ free(t);
+ }
+}
+
+int8_t
+clip_ellipse_next(
+ clip_ellipse_state *s, int32_t *ret_x0, int32_t *ret_y, int32_t *ret_x1) {
+ int32_t x0, y, x1;
+ while (s->head == NULL && ellipse_next(&s->st, &x0, &y, &x1) >= 0) {
+ if (clip_tree_do_clip(s->root, x0, y, x1, &s->head) < 0) {
+ return -2;
+ }
+ s->y = y;
+ }
+ if (s->head != NULL) {
+ *ret_y = s->y;
+ event_list *t = s->head;
+ s->head = s->head->next;
+ *ret_x0 = t->x;
+ free(t);
+ t = s->head;
+ assert(t != NULL);
+ s->head = s->head->next;
+ *ret_x1 = t->x;
+ free(t);
+ return 0;
+ }
+ return -1;
+}
+
+static int
+ellipseNew(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ const void *ink_,
+ int fill,
+ int width,
+ int op) {
+ DRAW *draw;
+ INT32 ink;
+ DRAWINIT();
+
+ int a = x1 - x0;
+ int b = y1 - y0;
+ if (a < 0 || b < 0) {
+ return 0;
+ }
+ if (fill) {
+ width = a + b;
+ }
+
+ ellipse_state st;
+ ellipse_init(&st, a, b, width);
+ int32_t X0, Y, X1;
+ while (ellipse_next(&st, &X0, &Y, &X1) != -1) {
+ draw->hline(im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink);
+ }
+ return 0;
+}
+
+static int
+clipEllipseNew(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ float start,
+ float end,
+ const void *ink_,
+ int width,
+ int op,
+ clip_ellipse_init init) {
+ DRAW *draw;
+ INT32 ink;
+ DRAWINIT();
+
+ int a = x1 - x0;
+ int b = y1 - y0;
+ if (a < 0 || b < 0) {
+ return 0;
+ }
+
+ clip_ellipse_state st;
+ init(&st, a, b, width, start, end);
+ // debug_clip_tree(st.root, 0);
+ int32_t X0, Y, X1;
+ int next_code;
+ while ((next_code = clip_ellipse_next(&st, &X0, &Y, &X1)) >= 0) {
+ draw->hline(im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink);
+ }
+ clip_ellipse_free(&st);
+ return next_code == -1 ? 0 : -1;
+}
+static int
+arcNew(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ float start,
+ float end,
+ const void *ink_,
+ int width,
+ int op) {
+ return clipEllipseNew(im, x0, y0, x1, y1, start, end, ink_, width, op, arc_init);
+}
+
+static int
+chordNew(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ float start,
+ float end,
+ const void *ink_,
+ int width,
+ int op) {
+ return clipEllipseNew(im, x0, y0, x1, y1, start, end, ink_, width, op, chord_init);
+}
+
+static int
+chordLineNew(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ float start,
+ float end,
+ const void *ink_,
+ int width,
+ int op) {
+ return clipEllipseNew(
+ im, x0, y0, x1, y1, start, end, ink_, width, op, chord_line_init);
+}
+
+static int
+pieNew(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ float start,
+ float end,
+ const void *ink_,
+ int width,
+ int op) {
+ return clipEllipseNew(im, x0, y0, x1, y1, start, end, ink_, width, op, pie_init);
+}
+
+static int
+pieSideNew(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ float start,
+ const void *ink_,
+ int width,
+ int op) {
+ return clipEllipseNew(im, x0, y0, x1, y1, start, 0, ink_, width, op, pie_side_init);
+}
+
+int
+ImagingDrawEllipse(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ const void *ink,
+ int fill,
+ int width,
+ int op) {
+ return ellipseNew(im, x0, y0, x1, y1, ink, fill, width, op);
+}
+
+int
+ImagingDrawArc(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ float start,
+ float end,
+ const void *ink,
+ int width,
+ int op) {
+ normalize_angles(&start, &end);
+ if (start + 360 == end) {
+ return ImagingDrawEllipse(im, x0, y0, x1, y1, ink, 0, width, op);
+ }
+ if (start == end) {
+ return 0;
+ }
+ return arcNew(im, x0, y0, x1, y1, start, end, ink, width, op);
+}
+
+int
+ImagingDrawChord(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ float start,
+ float end,
+ const void *ink,
+ int fill,
+ int width,
+ int op) {
+ normalize_angles(&start, &end);
+ if (start + 360 == end) {
+ return ImagingDrawEllipse(im, x0, y0, x1, y1, ink, fill, width, op);
+ }
+ if (start == end) {
+ return 0;
+ }
+ if (fill) {
+ return chordNew(im, x0, y0, x1, y1, start, end, ink, x1 - x0 + y1 - y0 + 1, op);
+ } else {
+ if (chordLineNew(im, x0, y0, x1, y1, start, end, ink, width, op)) {
+ return -1;
+ }
+ return chordNew(im, x0, y0, x1, y1, start, end, ink, width, op);
+ }
+}
+
+int
+ImagingDrawPieslice(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ float start,
+ float end,
+ const void *ink,
+ int fill,
+ int width,
+ int op) {
+ normalize_angles(&start, &end);
+ if (start + 360 == end) {
+ return ellipseNew(im, x0, y0, x1, y1, ink, fill, width, op);
+ }
+ if (start == end) {
+ return 0;
+ }
+ if (fill) {
+ return pieNew(im, x0, y0, x1, y1, start, end, ink, x1 + y1 - x0 - y0, op);
+ } else {
+ if (pieSideNew(im, x0, y0, x1, y1, start, ink, width, op)) {
+ return -1;
+ }
+ if (pieSideNew(im, x0, y0, x1, y1, end, ink, width, op)) {
+ return -1;
+ }
+ int xc = lround((x0 + x1 - width) / 2.0), yc = lround((y0 + y1 - width) / 2.0);
+ ellipseNew(im, xc, yc, xc + width - 1, yc + width - 1, ink, 1, 0, op);
+ return pieNew(im, x0, y0, x1, y1, start, end, ink, width, op);
+ }
+}
+
+/* -------------------------------------------------------------------- */
+
+/* experimental level 2 ("arrow") graphics stuff. this implements
+ portions of the arrow api on top of the Edge structure. the
+ semantics are ok, except that "curve" flattens the bezier curves by
+ itself */
+
+struct ImagingOutlineInstance {
+ float x0, y0;
+
+ float x, y;
+
+ int count;
+ Edge *edges;
+
+ int size;
+};
+
+ImagingOutline
+ImagingOutlineNew(void) {
+ ImagingOutline outline;
+
+ outline = calloc(1, sizeof(struct ImagingOutlineInstance));
+ if (!outline) {
+ return (ImagingOutline)ImagingError_MemoryError();
+ }
+
+ outline->edges = NULL;
+ outline->count = outline->size = 0;
+
+ ImagingOutlineMove(outline, 0, 0);
+
+ return outline;
+}
+
+void
+ImagingOutlineDelete(ImagingOutline outline) {
+ if (!outline) {
+ return;
+ }
+
+ if (outline->edges) {
+ free(outline->edges);
+ }
+
+ free(outline);
+}
+
+static Edge *
+allocate(ImagingOutline outline, int extra) {
+ Edge *e;
+
+ if (outline->count + extra > outline->size) {
+ /* expand outline buffer */
+ outline->size += extra + 25;
+ if (!outline->edges) {
+ /* malloc check ok, uses calloc for overflow */
+ e = calloc(outline->size, sizeof(Edge));
+ } else {
+ if (outline->size > INT_MAX / (int)sizeof(Edge)) {
+ return NULL;
+ }
+ /* malloc check ok, overflow checked above */
+ e = realloc(outline->edges, outline->size * sizeof(Edge));
+ }
+ if (!e) {
+ return NULL;
+ }
+ outline->edges = e;
+ }
+
+ e = outline->edges + outline->count;
+
+ outline->count += extra;
+
+ return e;
+}
+
+int
+ImagingOutlineMove(ImagingOutline outline, float x0, float y0) {
+ outline->x = outline->x0 = x0;
+ outline->y = outline->y0 = y0;
+
+ return 0;
+}
+
+int
+ImagingOutlineLine(ImagingOutline outline, float x1, float y1) {
+ Edge *e;
+
+ e = allocate(outline, 1);
+ if (!e) {
+ return -1; /* out of memory */
+ }
+
+ add_edge(e, (int)outline->x, (int)outline->y, (int)x1, (int)y1);
+
+ outline->x = x1;
+ outline->y = y1;
+
+ return 0;
+}
+
+int
+ImagingOutlineCurve(
+ ImagingOutline outline,
+ float x1,
+ float y1,
+ float x2,
+ float y2,
+ float x3,
+ float y3) {
+ Edge *e;
+ int i;
+ float xo, yo;
+
+#define STEPS 32
+
+ e = allocate(outline, STEPS);
+ if (!e) {
+ return -1; /* out of memory */
+ }
+
+ xo = outline->x;
+ yo = outline->y;
+
+ /* flatten the bezier segment */
+
+ for (i = 1; i <= STEPS; i++) {
+ float t = ((float)i) / STEPS;
+ float t2 = t * t;
+ float t3 = t2 * t;
+
+ float u = 1.0F - t;
+ float u2 = u * u;
+ float u3 = u2 * u;
+
+ float x = outline->x * u3 + 3 * (x1 * t * u2 + x2 * t2 * u) + x3 * t3 + 0.5;
+ float y = outline->y * u3 + 3 * (y1 * t * u2 + y2 * t2 * u) + y3 * t3 + 0.5;
+
+ add_edge(e++, xo, yo, (int)x, (int)y);
+
+ xo = x, yo = y;
+ }
+
+ outline->x = xo;
+ outline->y = yo;
+
+ return 0;
+}
+
+int
+ImagingOutlineClose(ImagingOutline outline) {
+ if (outline->x == outline->x0 && outline->y == outline->y0) {
+ return 0;
+ }
+ return ImagingOutlineLine(outline, outline->x0, outline->y0);
+}
+
+int
+ImagingOutlineTransform(ImagingOutline outline, double a[6]) {
+ Edge *eIn;
+ Edge *eOut;
+ int i, n;
+ int x0, y0, x1, y1;
+ int X0, Y0, X1, Y1;
+
+ double a0 = a[0];
+ double a1 = a[1];
+ double a2 = a[2];
+ double a3 = a[3];
+ double a4 = a[4];
+ double a5 = a[5];
+
+ eIn = outline->edges;
+ n = outline->count;
+
+ eOut = allocate(outline, n);
+ if (!eOut) {
+ ImagingError_MemoryError();
+ return -1;
+ }
+
+ for (i = 0; i < n; i++) {
+ x0 = eIn->x0;
+ y0 = eIn->y0;
+
+ /* FIXME: ouch! */
+ if (eIn->x0 == eIn->xmin) {
+ x1 = eIn->xmax;
+ } else {
+ x1 = eIn->xmin;
+ }
+ if (eIn->y0 == eIn->ymin) {
+ y1 = eIn->ymax;
+ } else {
+ y1 = eIn->ymin;
+ }
+
+ /* full moon tonight! if this doesn't work, you may need to
+ upgrade your compiler (make sure you have the right service
+ pack) */
+
+ X0 = (int)(a0 * x0 + a1 * y0 + a2);
+ Y0 = (int)(a3 * x0 + a4 * y0 + a5);
+ X1 = (int)(a0 * x1 + a1 * y1 + a2);
+ Y1 = (int)(a3 * x1 + a4 * y1 + a5);
+
+ add_edge(eOut, X0, Y0, X1, Y1);
+
+ eIn++;
+ eOut++;
+ }
+
+ free(outline->edges);
+
+ /* FIXME: ugly! */
+ outline->edges = NULL;
+ outline->count = outline->size = 0;
+
+ return 0;
+}
+
+int
+ImagingDrawOutline(
+ Imaging im, ImagingOutline outline, const void *ink_, int fill, int op) {
+ DRAW *draw;
+ INT32 ink;
+
+ DRAWINIT();
+
+ draw->polygon(im, outline->count, outline->edges, ink, 0);
+
+ return 0;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Effects.c b/contrib/python/Pillow/py3/libImaging/Effects.c
new file mode 100644
index 00000000000..93e7af0bce9
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Effects.c
@@ -0,0 +1,160 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * various special effects and image generators
+ *
+ * history:
+ * 1997-05-21 fl Just for fun
+ * 1997-06-05 fl Added mandelbrot generator
+ * 2003-05-24 fl Added perlin_turbulence generator (in progress)
+ *
+ * Copyright (c) 1997-2003 by Fredrik Lundh.
+ * Copyright (c) 1997 by Secret Labs AB.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#include <math.h>
+
+Imaging
+ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality) {
+ /* Generate a Mandelbrot set covering the given extent */
+
+ Imaging im;
+ int x, y, k;
+ double width, height;
+ double x1, y1, xi2, yi2, cr, ci, radius;
+ double dr, di;
+
+ /* Check arguments */
+ width = extent[2] - extent[0];
+ height = extent[3] - extent[1];
+ if (width < 0.0 || height < 0.0 || quality < 2) {
+ return (Imaging)ImagingError_ValueError(NULL);
+ }
+
+ im = ImagingNewDirty("L", xsize, ysize);
+ if (!im) {
+ return NULL;
+ }
+
+ dr = width / (xsize - 1);
+ di = height / (ysize - 1);
+
+ radius = 100.0;
+
+ for (y = 0; y < ysize; y++) {
+ UINT8 *buf = im->image8[y];
+ for (x = 0; x < xsize; x++) {
+ x1 = y1 = xi2 = yi2 = 0.0;
+ cr = x * dr + extent[0];
+ ci = y * di + extent[1];
+ for (k = 1;; k++) {
+ y1 = 2 * x1 * y1 + ci;
+ x1 = xi2 - yi2 + cr;
+ xi2 = x1 * x1;
+ yi2 = y1 * y1;
+ if ((xi2 + yi2) > radius) {
+ buf[x] = k * 255 / quality;
+ break;
+ }
+ if (k > quality) {
+ buf[x] = 0;
+ break;
+ }
+ }
+ }
+ }
+ return im;
+}
+
+Imaging
+ImagingEffectNoise(int xsize, int ysize, float sigma) {
+ /* Generate Gaussian noise centered around 128 */
+
+ Imaging imOut;
+ int x, y;
+ int nextok;
+ double this, next;
+
+ imOut = ImagingNewDirty("L", xsize, ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ next = 0.0;
+ nextok = 0;
+
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8 *out = imOut->image8[y];
+ for (x = 0; x < imOut->xsize; x++) {
+ if (nextok) {
+ this = next;
+ nextok = 0;
+ } else {
+ /* after numerical recipes */
+ double v1, v2, radius, factor;
+ do {
+ v1 = rand() * (2.0 / RAND_MAX) - 1.0;
+ v2 = rand() * (2.0 / RAND_MAX) - 1.0;
+ radius = v1 * v1 + v2 * v2;
+ } while (radius >= 1.0);
+ factor = sqrt(-2.0 * log(radius) / radius);
+ this = factor * v1;
+ next = factor * v2;
+ }
+ out[x] = CLIP8(128 + sigma * this);
+ }
+ }
+
+ return imOut;
+}
+
+Imaging
+ImagingEffectSpread(Imaging imIn, int distance) {
+ /* Randomly spread pixels in an image */
+
+ Imaging imOut;
+ int x, y;
+
+ imOut = ImagingNewDirty(imIn->mode, imIn->xsize, imIn->ysize);
+
+ if (!imOut) {
+ return NULL;
+ }
+
+#define SPREAD(type, image) \
+ if (distance == 0) { \
+ for (y = 0; y < imOut->ysize; y++) { \
+ for (x = 0; x < imOut->xsize; x++) { \
+ imOut->image[y][x] = imIn->image[y][x]; \
+ } \
+ } \
+ } else { \
+ for (y = 0; y < imOut->ysize; y++) { \
+ for (x = 0; x < imOut->xsize; x++) { \
+ int xx = x + (rand() % distance) - distance / 2; \
+ int yy = y + (rand() % distance) - distance / 2; \
+ if (xx >= 0 && xx < imIn->xsize && yy >= 0 && yy < imIn->ysize) { \
+ imOut->image[yy][xx] = imIn->image[y][x]; \
+ imOut->image[y][x] = imIn->image[yy][xx]; \
+ } else { \
+ imOut->image[y][x] = imIn->image[y][x]; \
+ } \
+ } \
+ } \
+ }
+
+ if (imIn->image8) {
+ SPREAD(UINT8, image8);
+ } else {
+ SPREAD(INT32, image32);
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/EpsEncode.c b/contrib/python/Pillow/py3/libImaging/EpsEncode.c
new file mode 100644
index 00000000000..3f2cb33b2d2
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/EpsEncode.c
@@ -0,0 +1,77 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * encoder for EPS hex data
+ *
+ * history:
+ * 96-04-19 fl created
+ * 96-06-27 fl don't drop last block of encoded data
+ *
+ * notes:
+ * FIXME: rename to HexEncode.c ??
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+int
+ImagingEpsEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
+ enum { HEXBYTE = 1, NEWLINE };
+ const char *hex = "0123456789abcdef";
+
+ UINT8 *ptr = buf;
+ UINT8 *in, i;
+
+ if (!state->state) {
+ state->state = HEXBYTE;
+ state->xsize *= im->pixelsize; /* Hack! */
+ }
+
+ in = (UINT8 *)im->image[state->y];
+
+ for (;;) {
+ if (state->state == NEWLINE) {
+ if (bytes < 1) {
+ break;
+ }
+ *ptr++ = '\n';
+ bytes--;
+ state->state = HEXBYTE;
+ }
+
+ if (bytes < 2) {
+ break;
+ }
+
+ i = in[state->x++];
+ *ptr++ = hex[(i >> 4) & 15];
+ *ptr++ = hex[i & 15];
+ bytes -= 2;
+
+ /* Skip junk bytes */
+ if (im->bands == 3 && (state->x & 3) == 3) {
+ state->x++;
+ }
+
+ if (++state->count >= 79 / 2) {
+ state->state = NEWLINE;
+ state->count = 0;
+ }
+
+ if (state->x >= state->xsize) {
+ state->x = 0;
+ if (++state->y >= state->ysize) {
+ state->errcode = IMAGING_CODEC_END;
+ break;
+ }
+ in = (UINT8 *)im->image[state->y];
+ }
+ }
+
+ return ptr - buf;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/File.c b/contrib/python/Pillow/py3/libImaging/File.c
new file mode 100644
index 00000000000..76d0abccc4f
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/File.c
@@ -0,0 +1,78 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * built-in image file handling
+ *
+ * history:
+ * 1995-11-26 fl Created, supports PGM/PPM
+ * 1996-08-07 fl Write "1" images as PGM
+ * 1999-02-21 fl Don't write non-standard modes
+ *
+ * Copyright (c) 1997-99 by Secret Labs AB.
+ * Copyright (c) 1995-96 by Fredrik Lundh.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#include <ctype.h>
+
+int
+ImagingSaveRaw(Imaging im, FILE *fp) {
+ int x, y, i;
+
+ if (strcmp(im->mode, "1") == 0 || strcmp(im->mode, "L") == 0) {
+ /* @PIL227: FIXME: for mode "1", map != 0 to 255 */
+
+ /* PGM "L" */
+ for (y = 0; y < im->ysize; y++) {
+ fwrite(im->image[y], 1, im->xsize, fp);
+ }
+
+ } else {
+ /* PPM "RGB" or other internal format */
+ for (y = 0; y < im->ysize; y++) {
+ for (x = i = 0; x < im->xsize; x++, i += im->pixelsize) {
+ fwrite(im->image[y] + i, 1, im->bands, fp);
+ }
+ }
+ }
+
+ return 1;
+}
+
+int
+ImagingSavePPM(Imaging im, const char *outfile) {
+ FILE *fp;
+
+ if (!im) {
+ (void)ImagingError_ValueError(NULL);
+ return 0;
+ }
+
+ fp = fopen(outfile, "wb");
+ if (!fp) {
+ (void)ImagingError_OSError();
+ return 0;
+ }
+
+ if (strcmp(im->mode, "1") == 0 || strcmp(im->mode, "L") == 0) {
+ /* Write "PGM" */
+ fprintf(fp, "P5\n%d %d\n255\n", im->xsize, im->ysize);
+ } else if (strcmp(im->mode, "RGB") == 0) {
+ /* Write "PPM" */
+ fprintf(fp, "P6\n%d %d\n255\n", im->xsize, im->ysize);
+ } else {
+ fclose(fp);
+ (void)ImagingError_ModeError();
+ return 0;
+ }
+
+ ImagingSaveRaw(im, fp);
+
+ fclose(fp);
+
+ return 1;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Fill.c b/contrib/python/Pillow/py3/libImaging/Fill.c
new file mode 100644
index 00000000000..5b6bfb89cd8
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Fill.c
@@ -0,0 +1,139 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * fill image with constant pixel value
+ *
+ * history:
+ * 95-11-26 fl moved from Imaging.c
+ * 96-05-17 fl added radial fill, renamed wedge to linear
+ * 98-06-23 fl changed ImageFill signature
+ *
+ * Copyright (c) Secret Labs AB 1997-98. All rights reserved.
+ * Copyright (c) Fredrik Lundh 1995-96.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#include "math.h"
+
+Imaging
+ImagingFill(Imaging im, const void *colour) {
+ int x, y;
+ ImagingSectionCookie cookie;
+
+ /* 0-width or 0-height image. No need to do anything */
+ if (!im->linesize || !im->ysize) {
+ return im;
+ }
+
+ if (im->type == IMAGING_TYPE_SPECIAL) {
+ /* use generic API */
+ ImagingAccess access = ImagingAccessNew(im);
+ if (access) {
+ for (y = 0; y < im->ysize; y++) {
+ for (x = 0; x < im->xsize; x++) {
+ access->put_pixel(im, x, y, colour);
+ }
+ }
+ ImagingAccessDelete(im, access);
+ } else {
+ /* wipe the image */
+ for (y = 0; y < im->ysize; y++) {
+ memset(im->image[y], 0, im->linesize);
+ }
+ }
+ } else {
+ INT32 c = 0L;
+ ImagingSectionEnter(&cookie);
+ memcpy(&c, colour, im->pixelsize);
+ if (im->image32 && c != 0L) {
+ for (y = 0; y < im->ysize; y++) {
+ for (x = 0; x < im->xsize; x++) {
+ im->image32[y][x] = c;
+ }
+ }
+ } else {
+ unsigned char cc = (unsigned char)*(UINT8 *)colour;
+ for (y = 0; y < im->ysize; y++) {
+ memset(im->image[y], cc, im->linesize);
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ }
+
+ return im;
+}
+
+Imaging
+ImagingFillLinearGradient(const char *mode) {
+ Imaging im;
+ int y;
+
+ if (strlen(mode) != 1) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ im = ImagingNewDirty(mode, 256, 256);
+ if (!im) {
+ return NULL;
+ }
+
+ if (im->image8) {
+ for (y = 0; y < 256; y++) {
+ memset(im->image8[y], (unsigned char)y, 256);
+ }
+ } else {
+ int x;
+ for (y = 0; y < 256; y++) {
+ for (x = 0; x < 256; x++) {
+ if (im->type == IMAGING_TYPE_FLOAT32) {
+ IMAGING_PIXEL_FLOAT32(im, x, y) = y;
+ } else {
+ IMAGING_PIXEL_INT32(im, x, y) = y;
+ }
+ }
+ }
+ }
+
+ return im;
+}
+
+Imaging
+ImagingFillRadialGradient(const char *mode) {
+ Imaging im;
+ int x, y;
+ int d;
+
+ if (strlen(mode) != 1) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ im = ImagingNewDirty(mode, 256, 256);
+ if (!im) {
+ return NULL;
+ }
+
+ for (y = 0; y < 256; y++) {
+ for (x = 0; x < 256; x++) {
+ d = (int)sqrt(
+ (double)((x - 128) * (x - 128) + (y - 128) * (y - 128)) * 2.0);
+ if (d >= 255) {
+ d = 255;
+ }
+ if (im->image8) {
+ im->image8[y][x] = d;
+ } else {
+ if (im->type == IMAGING_TYPE_FLOAT32) {
+ IMAGING_PIXEL_FLOAT32(im, x, y) = d;
+ } else {
+ IMAGING_PIXEL_INT32(im, x, y) = d;
+ }
+ }
+ }
+ }
+
+ return im;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Filter.c b/contrib/python/Pillow/py3/libImaging/Filter.c
new file mode 100644
index 00000000000..4dcd368ca80
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Filter.c
@@ -0,0 +1,412 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * apply convolution kernel to image
+ *
+ * history:
+ * 1995-11-26 fl Created, supports 3x3 kernels
+ * 1995-11-27 fl Added 5x5 kernels, copy border
+ * 1999-07-26 fl Eliminated a few compiler warnings
+ * 2002-06-09 fl Moved kernel definitions to Python
+ * 2002-06-11 fl Support floating point kernels
+ * 2003-09-15 fl Added ImagingExpand helper
+ *
+ * Copyright (c) Secret Labs AB 1997-2002. All rights reserved.
+ * Copyright (c) Fredrik Lundh 1995.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+/*
+ * FIXME: Support RGB and RGBA/CMYK modes as well
+ * FIXME: Expand image border (current version leaves border as is)
+ * FIXME: Implement image processing gradient filters
+ */
+
+#include "Imaging.h"
+
+static inline UINT8
+clip8(float in) {
+ if (in <= 0.0) {
+ return 0;
+ }
+ if (in >= 255.0) {
+ return 255;
+ }
+ return (UINT8)in;
+}
+
+static inline INT32
+clip32(float in) {
+ if (in <= 0.0) {
+ return 0;
+ }
+ if (in >= pow(2, 31) - 1) {
+ return pow(2, 31) - 1;
+ }
+ return (INT32)in;
+}
+
+Imaging
+ImagingExpand(Imaging imIn, int xmargin, int ymargin) {
+ Imaging imOut;
+ int x, y;
+ ImagingSectionCookie cookie;
+
+ if (xmargin < 0 && ymargin < 0) {
+ return (Imaging)ImagingError_ValueError("bad kernel size");
+ }
+
+ imOut = ImagingNewDirty(
+ imIn->mode, imIn->xsize + 2 * xmargin, imIn->ysize + 2 * ymargin);
+ if (!imOut) {
+ return NULL;
+ }
+
+#define EXPAND_LINE(type, image, yin, yout) \
+ { \
+ for (x = 0; x < xmargin; x++) { \
+ imOut->image[yout][x] = imIn->image[yin][0]; \
+ } \
+ for (x = 0; x < imIn->xsize; x++) { \
+ imOut->image[yout][x + xmargin] = imIn->image[yin][x]; \
+ } \
+ for (x = 0; x < xmargin; x++) { \
+ imOut->image[yout][xmargin + imIn->xsize + x] = \
+ imIn->image[yin][imIn->xsize - 1]; \
+ } \
+ }
+
+#define EXPAND(type, image) \
+ { \
+ for (y = 0; y < ymargin; y++) { \
+ EXPAND_LINE(type, image, 0, y); \
+ } \
+ for (y = 0; y < imIn->ysize; y++) { \
+ EXPAND_LINE(type, image, y, y + ymargin); \
+ } \
+ for (y = 0; y < ymargin; y++) { \
+ EXPAND_LINE(type, image, imIn->ysize - 1, ymargin + imIn->ysize + y); \
+ } \
+ }
+
+ ImagingSectionEnter(&cookie);
+ if (imIn->image8) {
+ EXPAND(UINT8, image8);
+ } else {
+ EXPAND(INT32, image32);
+ }
+ ImagingSectionLeave(&cookie);
+
+ ImagingCopyPalette(imOut, imIn);
+
+ return imOut;
+}
+
+void
+ImagingFilter3x3(Imaging imOut, Imaging im, const float *kernel, float offset) {
+#define KERNEL1x3(in0, x, kernel, d) \
+ (_i2f(in0[x - d]) * (kernel)[0] + _i2f(in0[x]) * (kernel)[1] + \
+ _i2f(in0[x + d]) * (kernel)[2])
+
+ int x = 0, y = 0;
+
+ memcpy(imOut->image[0], im->image[0], im->linesize);
+ if (im->bands == 1) {
+ // Add one time for rounding
+ offset += 0.5;
+ if (im->type == IMAGING_TYPE_INT32) {
+ for (y = 1; y < im->ysize - 1; y++) {
+ INT32 *in_1 = (INT32 *)im->image[y - 1];
+ INT32 *in0 = (INT32 *)im->image[y];
+ INT32 *in1 = (INT32 *)im->image[y + 1];
+ INT32 *out = (INT32 *)imOut->image[y];
+
+ out[0] = in0[0];
+ for (x = 1; x < im->xsize - 1; x++) {
+ float ss = offset;
+ ss += KERNEL1x3(in1, x, &kernel[0], 1);
+ ss += KERNEL1x3(in0, x, &kernel[3], 1);
+ ss += KERNEL1x3(in_1, x, &kernel[6], 1);
+ out[x] = clip32(ss);
+ }
+ out[x] = in0[x];
+ }
+ } else {
+ for (y = 1; y < im->ysize - 1; y++) {
+ UINT8 *in_1 = (UINT8 *)im->image[y - 1];
+ UINT8 *in0 = (UINT8 *)im->image[y];
+ UINT8 *in1 = (UINT8 *)im->image[y + 1];
+ UINT8 *out = (UINT8 *)imOut->image[y];
+
+ out[0] = in0[0];
+ for (x = 1; x < im->xsize - 1; x++) {
+ float ss = offset;
+ ss += KERNEL1x3(in1, x, &kernel[0], 1);
+ ss += KERNEL1x3(in0, x, &kernel[3], 1);
+ ss += KERNEL1x3(in_1, x, &kernel[6], 1);
+ out[x] = clip8(ss);
+ }
+ out[x] = in0[x];
+ }
+ }
+ } else {
+ // Add one time for rounding
+ offset += 0.5;
+ for (y = 1; y < im->ysize - 1; y++) {
+ UINT8 *in_1 = (UINT8 *)im->image[y - 1];
+ UINT8 *in0 = (UINT8 *)im->image[y];
+ UINT8 *in1 = (UINT8 *)im->image[y + 1];
+ UINT8 *out = (UINT8 *)imOut->image[y];
+
+ memcpy(out, in0, sizeof(UINT32));
+ if (im->bands == 2) {
+ for (x = 1; x < im->xsize - 1; x++) {
+ float ss0 = offset;
+ float ss3 = offset;
+ UINT32 v;
+ ss0 += KERNEL1x3(in1, x * 4 + 0, &kernel[0], 4);
+ ss3 += KERNEL1x3(in1, x * 4 + 3, &kernel[0], 4);
+ ss0 += KERNEL1x3(in0, x * 4 + 0, &kernel[3], 4);
+ ss3 += KERNEL1x3(in0, x * 4 + 3, &kernel[3], 4);
+ ss0 += KERNEL1x3(in_1, x * 4 + 0, &kernel[6], 4);
+ ss3 += KERNEL1x3(in_1, x * 4 + 3, &kernel[6], 4);
+ v = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3));
+ memcpy(out + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (im->bands == 3) {
+ for (x = 1; x < im->xsize - 1; x++) {
+ float ss0 = offset;
+ float ss1 = offset;
+ float ss2 = offset;
+ UINT32 v;
+ ss0 += KERNEL1x3(in1, x * 4 + 0, &kernel[0], 4);
+ ss1 += KERNEL1x3(in1, x * 4 + 1, &kernel[0], 4);
+ ss2 += KERNEL1x3(in1, x * 4 + 2, &kernel[0], 4);
+ ss0 += KERNEL1x3(in0, x * 4 + 0, &kernel[3], 4);
+ ss1 += KERNEL1x3(in0, x * 4 + 1, &kernel[3], 4);
+ ss2 += KERNEL1x3(in0, x * 4 + 2, &kernel[3], 4);
+ ss0 += KERNEL1x3(in_1, x * 4 + 0, &kernel[6], 4);
+ ss1 += KERNEL1x3(in_1, x * 4 + 1, &kernel[6], 4);
+ ss2 += KERNEL1x3(in_1, x * 4 + 2, &kernel[6], 4);
+ v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), 0);
+ memcpy(out + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (im->bands == 4) {
+ for (x = 1; x < im->xsize - 1; x++) {
+ float ss0 = offset;
+ float ss1 = offset;
+ float ss2 = offset;
+ float ss3 = offset;
+ UINT32 v;
+ ss0 += KERNEL1x3(in1, x * 4 + 0, &kernel[0], 4);
+ ss1 += KERNEL1x3(in1, x * 4 + 1, &kernel[0], 4);
+ ss2 += KERNEL1x3(in1, x * 4 + 2, &kernel[0], 4);
+ ss3 += KERNEL1x3(in1, x * 4 + 3, &kernel[0], 4);
+ ss0 += KERNEL1x3(in0, x * 4 + 0, &kernel[3], 4);
+ ss1 += KERNEL1x3(in0, x * 4 + 1, &kernel[3], 4);
+ ss2 += KERNEL1x3(in0, x * 4 + 2, &kernel[3], 4);
+ ss3 += KERNEL1x3(in0, x * 4 + 3, &kernel[3], 4);
+ ss0 += KERNEL1x3(in_1, x * 4 + 0, &kernel[6], 4);
+ ss1 += KERNEL1x3(in_1, x * 4 + 1, &kernel[6], 4);
+ ss2 += KERNEL1x3(in_1, x * 4 + 2, &kernel[6], 4);
+ ss3 += KERNEL1x3(in_1, x * 4 + 3, &kernel[6], 4);
+ v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
+ memcpy(out + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ memcpy(out + x * sizeof(UINT32), in0 + x * sizeof(UINT32), sizeof(UINT32));
+ }
+ }
+ memcpy(imOut->image[y], im->image[y], im->linesize);
+}
+
+void
+ImagingFilter5x5(Imaging imOut, Imaging im, const float *kernel, float offset) {
+#define KERNEL1x5(in0, x, kernel, d) \
+ (_i2f(in0[x - d - d]) * (kernel)[0] + \
+ _i2f(in0[x - d]) * (kernel)[1] + _i2f(in0[x]) * (kernel)[2] + \
+ _i2f(in0[x + d]) * (kernel)[3] + \
+ _i2f(in0[x + d + d]) * (kernel)[4])
+
+ int x = 0, y = 0;
+
+ memcpy(imOut->image[0], im->image[0], im->linesize);
+ memcpy(imOut->image[1], im->image[1], im->linesize);
+ if (im->bands == 1) {
+ // Add one time for rounding
+ offset += 0.5;
+ if (im->type == IMAGING_TYPE_INT32) {
+ for (y = 2; y < im->ysize - 2; y++) {
+ INT32 *in_2 = (INT32 *)im->image[y - 2];
+ INT32 *in_1 = (INT32 *)im->image[y - 1];
+ INT32 *in0 = (INT32 *)im->image[y];
+ INT32 *in1 = (INT32 *)im->image[y + 1];
+ INT32 *in2 = (INT32 *)im->image[y + 2];
+ INT32 *out = (INT32 *)imOut->image[y];
+
+ out[0] = in0[0];
+ out[1] = in0[1];
+ for (x = 2; x < im->xsize - 2; x++) {
+ float ss = offset;
+ ss += KERNEL1x5(in2, x, &kernel[0], 1);
+ ss += KERNEL1x5(in1, x, &kernel[5], 1);
+ ss += KERNEL1x5(in0, x, &kernel[10], 1);
+ ss += KERNEL1x5(in_1, x, &kernel[15], 1);
+ ss += KERNEL1x5(in_2, x, &kernel[20], 1);
+ out[x] = clip32(ss);
+ }
+ out[x + 0] = in0[x + 0];
+ out[x + 1] = in0[x + 1];
+ }
+ } else {
+ for (y = 2; y < im->ysize - 2; y++) {
+ UINT8 *in_2 = (UINT8 *)im->image[y - 2];
+ UINT8 *in_1 = (UINT8 *)im->image[y - 1];
+ UINT8 *in0 = (UINT8 *)im->image[y];
+ UINT8 *in1 = (UINT8 *)im->image[y + 1];
+ UINT8 *in2 = (UINT8 *)im->image[y + 2];
+ UINT8 *out = (UINT8 *)imOut->image[y];
+
+ out[0] = in0[0];
+ out[1] = in0[1];
+ for (x = 2; x < im->xsize - 2; x++) {
+ float ss = offset;
+ ss += KERNEL1x5(in2, x, &kernel[0], 1);
+ ss += KERNEL1x5(in1, x, &kernel[5], 1);
+ ss += KERNEL1x5(in0, x, &kernel[10], 1);
+ ss += KERNEL1x5(in_1, x, &kernel[15], 1);
+ ss += KERNEL1x5(in_2, x, &kernel[20], 1);
+ out[x] = clip8(ss);
+ }
+ out[x + 0] = in0[x + 0];
+ out[x + 1] = in0[x + 1];
+ }
+ }
+ } else {
+ // Add one time for rounding
+ offset += 0.5;
+ for (y = 2; y < im->ysize - 2; y++) {
+ UINT8 *in_2 = (UINT8 *)im->image[y - 2];
+ UINT8 *in_1 = (UINT8 *)im->image[y - 1];
+ UINT8 *in0 = (UINT8 *)im->image[y];
+ UINT8 *in1 = (UINT8 *)im->image[y + 1];
+ UINT8 *in2 = (UINT8 *)im->image[y + 2];
+ UINT8 *out = (UINT8 *)imOut->image[y];
+
+ memcpy(out, in0, sizeof(UINT32) * 2);
+ if (im->bands == 2) {
+ for (x = 2; x < im->xsize - 2; x++) {
+ float ss0 = offset;
+ float ss3 = offset;
+ UINT32 v;
+ ss0 += KERNEL1x5(in2, x * 4 + 0, &kernel[0], 4);
+ ss3 += KERNEL1x5(in2, x * 4 + 3, &kernel[0], 4);
+ ss0 += KERNEL1x5(in1, x * 4 + 0, &kernel[5], 4);
+ ss3 += KERNEL1x5(in1, x * 4 + 3, &kernel[5], 4);
+ ss0 += KERNEL1x5(in0, x * 4 + 0, &kernel[10], 4);
+ ss3 += KERNEL1x5(in0, x * 4 + 3, &kernel[10], 4);
+ ss0 += KERNEL1x5(in_1, x * 4 + 0, &kernel[15], 4);
+ ss3 += KERNEL1x5(in_1, x * 4 + 3, &kernel[15], 4);
+ ss0 += KERNEL1x5(in_2, x * 4 + 0, &kernel[20], 4);
+ ss3 += KERNEL1x5(in_2, x * 4 + 3, &kernel[20], 4);
+ v = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3));
+ memcpy(out + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (im->bands == 3) {
+ for (x = 2; x < im->xsize - 2; x++) {
+ float ss0 = offset;
+ float ss1 = offset;
+ float ss2 = offset;
+ UINT32 v;
+ ss0 += KERNEL1x5(in2, x * 4 + 0, &kernel[0], 4);
+ ss1 += KERNEL1x5(in2, x * 4 + 1, &kernel[0], 4);
+ ss2 += KERNEL1x5(in2, x * 4 + 2, &kernel[0], 4);
+ ss0 += KERNEL1x5(in1, x * 4 + 0, &kernel[5], 4);
+ ss1 += KERNEL1x5(in1, x * 4 + 1, &kernel[5], 4);
+ ss2 += KERNEL1x5(in1, x * 4 + 2, &kernel[5], 4);
+ ss0 += KERNEL1x5(in0, x * 4 + 0, &kernel[10], 4);
+ ss1 += KERNEL1x5(in0, x * 4 + 1, &kernel[10], 4);
+ ss2 += KERNEL1x5(in0, x * 4 + 2, &kernel[10], 4);
+ ss0 += KERNEL1x5(in_1, x * 4 + 0, &kernel[15], 4);
+ ss1 += KERNEL1x5(in_1, x * 4 + 1, &kernel[15], 4);
+ ss2 += KERNEL1x5(in_1, x * 4 + 2, &kernel[15], 4);
+ ss0 += KERNEL1x5(in_2, x * 4 + 0, &kernel[20], 4);
+ ss1 += KERNEL1x5(in_2, x * 4 + 1, &kernel[20], 4);
+ ss2 += KERNEL1x5(in_2, x * 4 + 2, &kernel[20], 4);
+ v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), 0);
+ memcpy(out + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (im->bands == 4) {
+ for (x = 2; x < im->xsize - 2; x++) {
+ float ss0 = offset;
+ float ss1 = offset;
+ float ss2 = offset;
+ float ss3 = offset;
+ UINT32 v;
+ ss0 += KERNEL1x5(in2, x * 4 + 0, &kernel[0], 4);
+ ss1 += KERNEL1x5(in2, x * 4 + 1, &kernel[0], 4);
+ ss2 += KERNEL1x5(in2, x * 4 + 2, &kernel[0], 4);
+ ss3 += KERNEL1x5(in2, x * 4 + 3, &kernel[0], 4);
+ ss0 += KERNEL1x5(in1, x * 4 + 0, &kernel[5], 4);
+ ss1 += KERNEL1x5(in1, x * 4 + 1, &kernel[5], 4);
+ ss2 += KERNEL1x5(in1, x * 4 + 2, &kernel[5], 4);
+ ss3 += KERNEL1x5(in1, x * 4 + 3, &kernel[5], 4);
+ ss0 += KERNEL1x5(in0, x * 4 + 0, &kernel[10], 4);
+ ss1 += KERNEL1x5(in0, x * 4 + 1, &kernel[10], 4);
+ ss2 += KERNEL1x5(in0, x * 4 + 2, &kernel[10], 4);
+ ss3 += KERNEL1x5(in0, x * 4 + 3, &kernel[10], 4);
+ ss0 += KERNEL1x5(in_1, x * 4 + 0, &kernel[15], 4);
+ ss1 += KERNEL1x5(in_1, x * 4 + 1, &kernel[15], 4);
+ ss2 += KERNEL1x5(in_1, x * 4 + 2, &kernel[15], 4);
+ ss3 += KERNEL1x5(in_1, x * 4 + 3, &kernel[15], 4);
+ ss0 += KERNEL1x5(in_2, x * 4 + 0, &kernel[20], 4);
+ ss1 += KERNEL1x5(in_2, x * 4 + 1, &kernel[20], 4);
+ ss2 += KERNEL1x5(in_2, x * 4 + 2, &kernel[20], 4);
+ ss3 += KERNEL1x5(in_2, x * 4 + 3, &kernel[20], 4);
+ v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
+ memcpy(out + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ memcpy(
+ out + x * sizeof(UINT32), in0 + x * sizeof(UINT32), sizeof(UINT32) * 2);
+ }
+ }
+ memcpy(imOut->image[y], im->image[y], im->linesize);
+ memcpy(imOut->image[y + 1], im->image[y + 1], im->linesize);
+}
+
+Imaging
+ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32 *kernel, FLOAT32 offset) {
+ Imaging imOut;
+ ImagingSectionCookie cookie;
+
+ if (im->type != IMAGING_TYPE_UINT8 && im->type != IMAGING_TYPE_INT32) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ if (im->xsize < xsize || im->ysize < ysize) {
+ return ImagingCopy(im);
+ }
+
+ if ((xsize != 3 && xsize != 5) || xsize != ysize) {
+ return (Imaging)ImagingError_ValueError("bad kernel size");
+ }
+
+ imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ ImagingSectionEnter(&cookie);
+ if (xsize == 3) {
+ /* 3x3 kernel. */
+ ImagingFilter3x3(imOut, im, kernel, offset);
+ } else {
+ /* 5x5 kernel. */
+ ImagingFilter5x5(imOut, im, kernel, offset);
+ }
+ ImagingSectionLeave(&cookie);
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/FliDecode.c b/contrib/python/Pillow/py3/libImaging/FliDecode.c
new file mode 100644
index 00000000000..d6e4ea0ff9d
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/FliDecode.c
@@ -0,0 +1,268 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for Autodesk Animator FLI/FLC animations
+ *
+ * history:
+ * 97-01-03 fl Created
+ * 97-01-17 fl Added SS2 support (FLC)
+ *
+ * Copyright (c) Fredrik Lundh 1997.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#define I16(ptr) ((ptr)[0] + ((ptr)[1] << 8))
+
+#define I32(ptr) ((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24))
+
+#define ERR_IF_DATA_OOB(offset) \
+ if ((data + (offset)) > ptr + bytes) { \
+ state->errcode = IMAGING_CODEC_OVERRUN; \
+ return -1; \
+ }
+
+int
+ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ UINT8 *ptr;
+ int framesize;
+ int c, chunks, advance;
+ int l, lines;
+ int i, j, x = 0, y, ymax;
+
+ /* If not even the chunk size is present, we'd better leave */
+
+ if (bytes < 4) {
+ return 0;
+ }
+
+ /* We don't decode anything unless we have a full chunk in the
+ input buffer */
+
+ ptr = buf;
+
+ framesize = I32(ptr);
+ // there can be one pad byte in the framesize
+ if (bytes + (bytes % 2) < framesize) {
+ return 0;
+ }
+
+ /* Make sure this is a frame chunk. The Python driver takes
+ case of other chunk types. */
+
+ if (bytes < 8) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ if (I16(ptr + 4) != 0xF1FA) {
+ state->errcode = IMAGING_CODEC_UNKNOWN;
+ return -1;
+ }
+
+ chunks = I16(ptr + 6);
+ ptr += 16;
+ bytes -= 16;
+
+ /* Process subchunks */
+ for (c = 0; c < chunks; c++) {
+ UINT8 *data;
+ if (bytes < 10) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ data = ptr + 6;
+ switch (I16(ptr + 4)) {
+ case 4:
+ case 11:
+ /* FLI COLOR chunk */
+ break; /* ignored; handled by Python code */
+ case 7:
+ /* FLI SS2 chunk (word delta) */
+ /* OOB ok, we've got 4 bytes min on entry */
+ lines = I16(data);
+ data += 2;
+ for (l = y = 0; l < lines && y < state->ysize; l++, y++) {
+ UINT8 *local_buf = (UINT8 *)im->image[y];
+ int p, packets;
+ ERR_IF_DATA_OOB(2)
+ packets = I16(data);
+ data += 2;
+ while (packets & 0x8000) {
+ /* flag word */
+ if (packets & 0x4000) {
+ y += 65536 - packets; /* skip lines */
+ if (y >= state->ysize) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ local_buf = (UINT8 *)im->image[y];
+ } else {
+ /* store last byte (used if line width is odd) */
+ local_buf[state->xsize - 1] = (UINT8)packets;
+ }
+ ERR_IF_DATA_OOB(2)
+ packets = I16(data);
+ data += 2;
+ }
+ for (p = x = 0; p < packets; p++) {
+ ERR_IF_DATA_OOB(2)
+ x += data[0]; /* pixel skip */
+ if (data[1] >= 128) {
+ ERR_IF_DATA_OOB(4)
+ i = 256 - data[1]; /* run */
+ if (x + i + i > state->xsize) {
+ break;
+ }
+ for (j = 0; j < i; j++) {
+ local_buf[x++] = data[2];
+ local_buf[x++] = data[3];
+ }
+ data += 2 + 2;
+ } else {
+ i = 2 * (int)data[1]; /* chunk */
+ if (x + i > state->xsize) {
+ break;
+ }
+ ERR_IF_DATA_OOB(2 + i)
+ memcpy(local_buf + x, data + 2, i);
+ data += 2 + i;
+ x += i;
+ }
+ }
+ if (p < packets) {
+ break; /* didn't process all packets */
+ }
+ }
+ if (l < lines) {
+ /* didn't process all lines */
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ break;
+ case 12:
+ /* FLI LC chunk (byte delta) */
+ /* OOB Check ok, we have 4 bytes min here */
+ y = I16(data);
+ ymax = y + I16(data + 2);
+ data += 4;
+ for (; y < ymax && y < state->ysize; y++) {
+ UINT8 *out = (UINT8 *)im->image[y];
+ ERR_IF_DATA_OOB(1)
+ int p, packets = *data++;
+ for (p = x = 0; p < packets; p++, x += i) {
+ ERR_IF_DATA_OOB(2)
+ x += data[0]; /* skip pixels */
+ if (data[1] & 0x80) {
+ i = 256 - data[1]; /* run */
+ if (x + i > state->xsize) {
+ break;
+ }
+ ERR_IF_DATA_OOB(3)
+ memset(out + x, data[2], i);
+ data += 3;
+ } else {
+ i = data[1]; /* chunk */
+ if (x + i > state->xsize) {
+ break;
+ }
+ ERR_IF_DATA_OOB(2 + i)
+ memcpy(out + x, data + 2, i);
+ data += i + 2;
+ }
+ }
+ if (p < packets) {
+ break; /* didn't process all packets */
+ }
+ }
+ if (y < ymax) {
+ /* didn't process all lines */
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ break;
+ case 13:
+ /* FLI BLACK chunk */
+ for (y = 0; y < state->ysize; y++) {
+ memset(im->image[y], 0, state->xsize);
+ }
+ break;
+ case 15:
+ /* FLI BRUN chunk */
+ /* OOB, ok, we've got 4 bytes min on entry */
+ for (y = 0; y < state->ysize; y++) {
+ UINT8 *out = (UINT8 *)im->image[y];
+ data += 1; /* ignore packetcount byte */
+ for (x = 0; x < state->xsize; x += i) {
+ ERR_IF_DATA_OOB(2)
+ if (data[0] & 0x80) {
+ i = 256 - data[0];
+ if (x + i > state->xsize) {
+ break; /* safety first */
+ }
+ ERR_IF_DATA_OOB(i + 1)
+ memcpy(out + x, data + 1, i);
+ data += i + 1;
+ } else {
+ i = data[0];
+ if (x + i > state->xsize) {
+ break; /* safety first */
+ }
+ memset(out + x, data[1], i);
+ data += 2;
+ }
+ }
+ if (x != state->xsize) {
+ /* didn't unpack whole line */
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ }
+ break;
+ case 16:
+ /* COPY chunk */
+ if (INT32_MAX / state->xsize < state->ysize) {
+ /* Integer overflow, bail */
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ /* Note, have to check Data + size, not just ptr + size) */
+ if (data + (state->xsize * state->ysize) > ptr + bytes) {
+ /* not enough data for frame */
+ /* UNDONE Unclear that we're actually going to leave the buffer at the right place. */
+ return ptr - buf; /* bytes consumed */
+ }
+ for (y = 0; y < state->ysize; y++) {
+ UINT8 *local_buf = (UINT8 *)im->image[y];
+ memcpy(local_buf, data, state->xsize);
+ data += state->xsize;
+ }
+ break;
+ case 18:
+ /* PSTAMP chunk */
+ break; /* ignored */
+ default:
+ /* unknown chunk */
+ /* printf("unknown FLI/FLC chunk: %d\n", I16(ptr+4)); */
+ state->errcode = IMAGING_CODEC_UNKNOWN;
+ return -1;
+ }
+ advance = I32(ptr);
+ if (advance == 0 ) {
+ // If there's no advance, we're in an infinite loop
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+ if (advance < 0 || advance > bytes) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+ ptr += advance;
+ bytes -= advance;
+ }
+
+ return -1; /* end of frame */
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Geometry.c b/contrib/python/Pillow/py3/libImaging/Geometry.c
new file mode 100644
index 00000000000..0c591579217
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Geometry.c
@@ -0,0 +1,1157 @@
+#include "Imaging.h"
+
+/* For large images rotation is an inefficient operation in terms of CPU cache.
+ One row in the source image affects each column in destination.
+ Rotating in chunks that fit in the cache can speed up rotation
+ 8x on a modern CPU. A chunk size of 128 requires only 65k and is large enough
+ that the overhead from the extra loops are not apparent. */
+#define ROTATE_CHUNK 512
+#define ROTATE_SMALL_CHUNK 8
+
+#define COORD(v) ((v) < 0.0 ? -1 : ((int)(v)))
+#define FLOOR(v) ((v) < 0.0 ? ((int)floor(v)) : ((int)(v)))
+
+/* -------------------------------------------------------------------- */
+/* Transpose operations */
+
+Imaging
+ImagingFlipLeftRight(Imaging imOut, Imaging imIn) {
+ ImagingSectionCookie cookie;
+ int x, y, xr;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
+ return (Imaging)ImagingError_ModeError();
+ }
+ if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) {
+ return (Imaging)ImagingError_Mismatch();
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+#define FLIP_LEFT_RIGHT(INT, image) \
+ for (y = 0; y < imIn->ysize; y++) { \
+ INT *in = (INT *)imIn->image[y]; \
+ INT *out = (INT *)imOut->image[y]; \
+ xr = imIn->xsize - 1; \
+ for (x = 0; x < imIn->xsize; x++, xr--) { \
+ out[xr] = in[x]; \
+ } \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ if (strncmp(imIn->mode, "I;16", 4) == 0) {
+ FLIP_LEFT_RIGHT(UINT16, image8)
+ } else {
+ FLIP_LEFT_RIGHT(UINT8, image8)
+ }
+ } else {
+ FLIP_LEFT_RIGHT(INT32, image32)
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef FLIP_LEFT_RIGHT
+
+ return imOut;
+}
+
+Imaging
+ImagingFlipTopBottom(Imaging imOut, Imaging imIn) {
+ ImagingSectionCookie cookie;
+ int y, yr;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
+ return (Imaging)ImagingError_ModeError();
+ }
+ if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) {
+ return (Imaging)ImagingError_Mismatch();
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+ ImagingSectionEnter(&cookie);
+
+ yr = imIn->ysize - 1;
+ for (y = 0; y < imIn->ysize; y++, yr--) {
+ memcpy(imOut->image[yr], imIn->image[y], imIn->linesize);
+ }
+
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
+
+Imaging
+ImagingRotate90(Imaging imOut, Imaging imIn) {
+ ImagingSectionCookie cookie;
+ int x, y, xx, yy, xr, xxsize, yysize;
+ int xxx, yyy, xxxsize, yyysize;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
+ return (Imaging)ImagingError_ModeError();
+ }
+ if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) {
+ return (Imaging)ImagingError_Mismatch();
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+#define ROTATE_90(INT, image) \
+ for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
+ for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
+ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
+ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
+ for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
+ for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
+ yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \
+ ? yy + ROTATE_SMALL_CHUNK \
+ : imIn->ysize; \
+ xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \
+ ? xx + ROTATE_SMALL_CHUNK \
+ : imIn->xsize; \
+ for (yyy = yy; yyy < yyysize; yyy++) { \
+ INT *in = (INT *)imIn->image[yyy]; \
+ xr = imIn->xsize - 1 - xx; \
+ for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \
+ INT *out = (INT *)imOut->image[xr]; \
+ out[yyy] = in[xxx]; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ if (strncmp(imIn->mode, "I;16", 4) == 0) {
+ ROTATE_90(UINT16, image8);
+ } else {
+ ROTATE_90(UINT8, image8);
+ }
+ } else {
+ ROTATE_90(INT32, image32);
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef ROTATE_90
+
+ return imOut;
+}
+
+Imaging
+ImagingTranspose(Imaging imOut, Imaging imIn) {
+ ImagingSectionCookie cookie;
+ int x, y, xx, yy, xxsize, yysize;
+ int xxx, yyy, xxxsize, yyysize;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
+ return (Imaging)ImagingError_ModeError();
+ }
+ if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) {
+ return (Imaging)ImagingError_Mismatch();
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+#define TRANSPOSE(INT, image) \
+ for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
+ for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
+ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
+ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
+ for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
+ for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
+ yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \
+ ? yy + ROTATE_SMALL_CHUNK \
+ : imIn->ysize; \
+ xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \
+ ? xx + ROTATE_SMALL_CHUNK \
+ : imIn->xsize; \
+ for (yyy = yy; yyy < yyysize; yyy++) { \
+ INT *in = (INT *)imIn->image[yyy]; \
+ for (xxx = xx; xxx < xxxsize; xxx++) { \
+ INT *out = (INT *)imOut->image[xxx]; \
+ out[yyy] = in[xxx]; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ if (strncmp(imIn->mode, "I;16", 4) == 0) {
+ TRANSPOSE(UINT16, image8);
+ } else {
+ TRANSPOSE(UINT8, image8);
+ }
+ } else {
+ TRANSPOSE(INT32, image32);
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef TRANSPOSE
+
+ return imOut;
+}
+
+Imaging
+ImagingTransverse(Imaging imOut, Imaging imIn) {
+ ImagingSectionCookie cookie;
+ int x, y, xr, yr, xx, yy, xxsize, yysize;
+ int xxx, yyy, xxxsize, yyysize;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
+ return (Imaging)ImagingError_ModeError();
+ }
+ if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) {
+ return (Imaging)ImagingError_Mismatch();
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+#define TRANSVERSE(INT, image) \
+ for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
+ for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
+ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
+ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
+ for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
+ for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
+ yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \
+ ? yy + ROTATE_SMALL_CHUNK \
+ : imIn->ysize; \
+ xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \
+ ? xx + ROTATE_SMALL_CHUNK \
+ : imIn->xsize; \
+ yr = imIn->ysize - 1 - yy; \
+ for (yyy = yy; yyy < yyysize; yyy++, yr--) { \
+ INT *in = (INT *)imIn->image[yyy]; \
+ xr = imIn->xsize - 1 - xx; \
+ for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \
+ INT *out = (INT *)imOut->image[xr]; \
+ out[yr] = in[xxx]; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ if (strncmp(imIn->mode, "I;16", 4) == 0) {
+ TRANSVERSE(UINT16, image8);
+ } else {
+ TRANSVERSE(UINT8, image8);
+ }
+ } else {
+ TRANSVERSE(INT32, image32);
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef TRANSVERSE
+
+ return imOut;
+}
+
+Imaging
+ImagingRotate180(Imaging imOut, Imaging imIn) {
+ ImagingSectionCookie cookie;
+ int x, y, xr, yr;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
+ return (Imaging)ImagingError_ModeError();
+ }
+ if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) {
+ return (Imaging)ImagingError_Mismatch();
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+#define ROTATE_180(INT, image) \
+ for (y = 0; y < imIn->ysize; y++, yr--) { \
+ INT *in = (INT *)imIn->image[y]; \
+ INT *out = (INT *)imOut->image[yr]; \
+ xr = imIn->xsize - 1; \
+ for (x = 0; x < imIn->xsize; x++, xr--) { \
+ out[xr] = in[x]; \
+ } \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ yr = imIn->ysize - 1;
+ if (imIn->image8) {
+ if (strncmp(imIn->mode, "I;16", 4) == 0) {
+ ROTATE_180(UINT16, image8)
+ } else {
+ ROTATE_180(UINT8, image8)
+ }
+ } else {
+ ROTATE_180(INT32, image32)
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef ROTATE_180
+
+ return imOut;
+}
+
+Imaging
+ImagingRotate270(Imaging imOut, Imaging imIn) {
+ ImagingSectionCookie cookie;
+ int x, y, xx, yy, yr, xxsize, yysize;
+ int xxx, yyy, xxxsize, yyysize;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
+ return (Imaging)ImagingError_ModeError();
+ }
+ if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) {
+ return (Imaging)ImagingError_Mismatch();
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+#define ROTATE_270(INT, image) \
+ for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
+ for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
+ yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
+ xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
+ for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
+ for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
+ yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \
+ ? yy + ROTATE_SMALL_CHUNK \
+ : imIn->ysize; \
+ xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \
+ ? xx + ROTATE_SMALL_CHUNK \
+ : imIn->xsize; \
+ yr = imIn->ysize - 1 - yy; \
+ for (yyy = yy; yyy < yyysize; yyy++, yr--) { \
+ INT *in = (INT *)imIn->image[yyy]; \
+ for (xxx = xx; xxx < xxxsize; xxx++) { \
+ INT *out = (INT *)imOut->image[xxx]; \
+ out[yr] = in[xxx]; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ if (strncmp(imIn->mode, "I;16", 4) == 0) {
+ ROTATE_270(UINT16, image8);
+ } else {
+ ROTATE_270(UINT8, image8);
+ }
+ } else {
+ ROTATE_270(INT32, image32);
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef ROTATE_270
+
+ return imOut;
+}
+
+/* -------------------------------------------------------------------- */
+/* Transforms */
+
+/* transform primitives (ImagingTransformMap) */
+
+static int
+affine_transform(double *xout, double *yout, int x, int y, void *data) {
+ /* full moon tonight. your compiler will generate bogus code
+ for simple expressions, unless you reorganize the code, or
+ install Service Pack 3 */
+
+ double *a = (double *)data;
+ double a0 = a[0];
+ double a1 = a[1];
+ double a2 = a[2];
+ double a3 = a[3];
+ double a4 = a[4];
+ double a5 = a[5];
+
+ double xin = x + 0.5;
+ double yin = y + 0.5;
+
+ xout[0] = a0 * xin + a1 * yin + a2;
+ yout[0] = a3 * xin + a4 * yin + a5;
+
+ return 1;
+}
+
+static int
+perspective_transform(double *xout, double *yout, int x, int y, void *data) {
+ double *a = (double *)data;
+ double a0 = a[0];
+ double a1 = a[1];
+ double a2 = a[2];
+ double a3 = a[3];
+ double a4 = a[4];
+ double a5 = a[5];
+ double a6 = a[6];
+ double a7 = a[7];
+
+ double xin = x + 0.5;
+ double yin = y + 0.5;
+
+ xout[0] = (a0 * xin + a1 * yin + a2) / (a6 * xin + a7 * yin + 1);
+ yout[0] = (a3 * xin + a4 * yin + a5) / (a6 * xin + a7 * yin + 1);
+
+ return 1;
+}
+
+static int
+quad_transform(double *xout, double *yout, int x, int y, void *data) {
+ /* quad warp: map quadrilateral to rectangle */
+
+ double *a = (double *)data;
+ double a0 = a[0];
+ double a1 = a[1];
+ double a2 = a[2];
+ double a3 = a[3];
+ double a4 = a[4];
+ double a5 = a[5];
+ double a6 = a[6];
+ double a7 = a[7];
+
+ double xin = x + 0.5;
+ double yin = y + 0.5;
+
+ xout[0] = a0 + a1 * xin + a2 * yin + a3 * xin * yin;
+ yout[0] = a4 + a5 * xin + a6 * yin + a7 * xin * yin;
+
+ return 1;
+}
+
+/* transform filters (ImagingTransformFilter) */
+
+static int
+nearest_filter8(void *out, Imaging im, double xin, double yin) {
+ int x = COORD(xin);
+ int y = COORD(yin);
+ if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
+ return 0;
+ }
+ ((UINT8 *)out)[0] = im->image8[y][x];
+ return 1;
+}
+
+static int
+nearest_filter16(void *out, Imaging im, double xin, double yin) {
+ int x = COORD(xin);
+ int y = COORD(yin);
+ if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
+ return 0;
+ }
+ memcpy(out, im->image8[y] + x * sizeof(INT16), sizeof(INT16));
+ return 1;
+}
+
+static int
+nearest_filter32(void *out, Imaging im, double xin, double yin) {
+ int x = COORD(xin);
+ int y = COORD(yin);
+ if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
+ return 0;
+ }
+ memcpy(out, &im->image32[y][x], sizeof(INT32));
+ return 1;
+}
+
+#define XCLIP(im, x) (((x) < 0) ? 0 : ((x) < im->xsize) ? (x) : im->xsize - 1)
+#define YCLIP(im, y) (((y) < 0) ? 0 : ((y) < im->ysize) ? (y) : im->ysize - 1)
+
+#define BILINEAR(v, a, b, d) (v = (a) + ((b) - (a)) * (d))
+
+#define BILINEAR_HEAD(type) \
+ int x, y; \
+ int x0, x1; \
+ double v1, v2; \
+ double dx, dy; \
+ type *in; \
+ if (xin < 0.0 || xin >= im->xsize || yin < 0.0 || yin >= im->ysize) { \
+ return 0; \
+ } \
+ xin -= 0.5; \
+ yin -= 0.5; \
+ x = FLOOR(xin); \
+ y = FLOOR(yin); \
+ dx = xin - x; \
+ dy = yin - y;
+
+#define BILINEAR_BODY(type, image, step, offset) \
+ { \
+ in = (type *)((image)[YCLIP(im, y)] + offset); \
+ x0 = XCLIP(im, x + 0) * step; \
+ x1 = XCLIP(im, x + 1) * step; \
+ BILINEAR(v1, in[x0], in[x1], dx); \
+ if (y + 1 >= 0 && y + 1 < im->ysize) { \
+ in = (type *)((image)[y + 1] + offset); \
+ BILINEAR(v2, in[x0], in[x1], dx); \
+ } else { \
+ v2 = v1; \
+ } \
+ BILINEAR(v1, v1, v2, dy); \
+ }
+
+static int
+bilinear_filter8(void *out, Imaging im, double xin, double yin) {
+ BILINEAR_HEAD(UINT8);
+ BILINEAR_BODY(UINT8, im->image8, 1, 0);
+ ((UINT8 *)out)[0] = (UINT8)v1;
+ return 1;
+}
+
+static int
+bilinear_filter32I(void *out, Imaging im, double xin, double yin) {
+ INT32 k;
+ BILINEAR_HEAD(INT32);
+ BILINEAR_BODY(INT32, im->image32, 1, 0);
+ k = v1;
+ memcpy(out, &k, sizeof(k));
+ return 1;
+}
+
+static int
+bilinear_filter32F(void *out, Imaging im, double xin, double yin) {
+ FLOAT32 k;
+ BILINEAR_HEAD(FLOAT32);
+ BILINEAR_BODY(FLOAT32, im->image32, 1, 0);
+ k = v1;
+ memcpy(out, &k, sizeof(k));
+ return 1;
+}
+
+static int
+bilinear_filter32LA(void *out, Imaging im, double xin, double yin) {
+ BILINEAR_HEAD(UINT8);
+ BILINEAR_BODY(UINT8, im->image, 4, 0);
+ ((UINT8 *)out)[0] = (UINT8)v1;
+ ((UINT8 *)out)[1] = (UINT8)v1;
+ ((UINT8 *)out)[2] = (UINT8)v1;
+ BILINEAR_BODY(UINT8, im->image, 4, 3);
+ ((UINT8 *)out)[3] = (UINT8)v1;
+ return 1;
+}
+
+static int
+bilinear_filter32RGB(void *out, Imaging im, double xin, double yin) {
+ int b;
+ BILINEAR_HEAD(UINT8);
+ for (b = 0; b < im->bands; b++) {
+ BILINEAR_BODY(UINT8, im->image, 4, b);
+ ((UINT8 *)out)[b] = (UINT8)v1;
+ }
+ return 1;
+}
+
+#undef BILINEAR
+#undef BILINEAR_HEAD
+#undef BILINEAR_BODY
+
+#define BICUBIC(v, v1, v2, v3, v4, d) \
+ { \
+ double p1 = v2; \
+ double p2 = -v1 + v3; \
+ double p3 = 2 * (v1 - v2) + v3 - v4; \
+ double p4 = -v1 + v2 - v3 + v4; \
+ v = p1 + (d) * (p2 + (d) * (p3 + (d)*p4)); \
+ }
+
+#define BICUBIC_HEAD(type) \
+ int x = FLOOR(xin); \
+ int y = FLOOR(yin); \
+ int x0, x1, x2, x3; \
+ double v1, v2, v3, v4; \
+ double dx, dy; \
+ type *in; \
+ if (xin < 0.0 || xin >= im->xsize || yin < 0.0 || yin >= im->ysize) { \
+ return 0; \
+ } \
+ xin -= 0.5; \
+ yin -= 0.5; \
+ x = FLOOR(xin); \
+ y = FLOOR(yin); \
+ dx = xin - x; \
+ dy = yin - y; \
+ x--; \
+ y--;
+
+#define BICUBIC_BODY(type, image, step, offset) \
+ { \
+ in = (type *)((image)[YCLIP(im, y)] + offset); \
+ x0 = XCLIP(im, x + 0) * step; \
+ x1 = XCLIP(im, x + 1) * step; \
+ x2 = XCLIP(im, x + 2) * step; \
+ x3 = XCLIP(im, x + 3) * step; \
+ BICUBIC(v1, in[x0], in[x1], in[x2], in[x3], dx); \
+ if (y + 1 >= 0 && y + 1 < im->ysize) { \
+ in = (type *)((image)[y + 1] + offset); \
+ BICUBIC(v2, in[x0], in[x1], in[x2], in[x3], dx); \
+ } else { \
+ v2 = v1; \
+ } \
+ if (y + 2 >= 0 && y + 2 < im->ysize) { \
+ in = (type *)((image)[y + 2] + offset); \
+ BICUBIC(v3, in[x0], in[x1], in[x2], in[x3], dx); \
+ } else { \
+ v3 = v2; \
+ } \
+ if (y + 3 >= 0 && y + 3 < im->ysize) { \
+ in = (type *)((image)[y + 3] + offset); \
+ BICUBIC(v4, in[x0], in[x1], in[x2], in[x3], dx); \
+ } else { \
+ v4 = v3; \
+ } \
+ BICUBIC(v1, v1, v2, v3, v4, dy); \
+ }
+
+static int
+bicubic_filter8(void *out, Imaging im, double xin, double yin) {
+ BICUBIC_HEAD(UINT8);
+ BICUBIC_BODY(UINT8, im->image8, 1, 0);
+ if (v1 <= 0.0) {
+ ((UINT8 *)out)[0] = 0;
+ } else if (v1 >= 255.0) {
+ ((UINT8 *)out)[0] = 255;
+ } else {
+ ((UINT8 *)out)[0] = (UINT8)v1;
+ }
+ return 1;
+}
+
+static int
+bicubic_filter32I(void *out, Imaging im, double xin, double yin) {
+ INT32 k;
+ BICUBIC_HEAD(INT32);
+ BICUBIC_BODY(INT32, im->image32, 1, 0);
+ k = v1;
+ memcpy(out, &k, sizeof(k));
+ return 1;
+}
+
+static int
+bicubic_filter32F(void *out, Imaging im, double xin, double yin) {
+ FLOAT32 k;
+ BICUBIC_HEAD(FLOAT32);
+ BICUBIC_BODY(FLOAT32, im->image32, 1, 0);
+ k = v1;
+ memcpy(out, &k, sizeof(k));
+ return 1;
+}
+
+static int
+bicubic_filter32LA(void *out, Imaging im, double xin, double yin) {
+ BICUBIC_HEAD(UINT8);
+ BICUBIC_BODY(UINT8, im->image, 4, 0);
+ if (v1 <= 0.0) {
+ ((UINT8 *)out)[0] = 0;
+ ((UINT8 *)out)[1] = 0;
+ ((UINT8 *)out)[2] = 0;
+ } else if (v1 >= 255.0) {
+ ((UINT8 *)out)[0] = 255;
+ ((UINT8 *)out)[1] = 255;
+ ((UINT8 *)out)[2] = 255;
+ } else {
+ ((UINT8 *)out)[0] = (UINT8)v1;
+ ((UINT8 *)out)[1] = (UINT8)v1;
+ ((UINT8 *)out)[2] = (UINT8)v1;
+ }
+ BICUBIC_BODY(UINT8, im->image, 4, 3);
+ if (v1 <= 0.0) {
+ ((UINT8 *)out)[3] = 0;
+ } else if (v1 >= 255.0) {
+ ((UINT8 *)out)[3] = 255;
+ } else {
+ ((UINT8 *)out)[3] = (UINT8)v1;
+ }
+ return 1;
+}
+
+static int
+bicubic_filter32RGB(void *out, Imaging im, double xin, double yin) {
+ int b;
+ BICUBIC_HEAD(UINT8);
+ for (b = 0; b < im->bands; b++) {
+ BICUBIC_BODY(UINT8, im->image, 4, b);
+ if (v1 <= 0.0) {
+ ((UINT8 *)out)[b] = 0;
+ } else if (v1 >= 255.0) {
+ ((UINT8 *)out)[b] = 255;
+ } else {
+ ((UINT8 *)out)[b] = (UINT8)v1;
+ }
+ }
+ return 1;
+}
+
+#undef BICUBIC
+#undef BICUBIC_HEAD
+#undef BICUBIC_BODY
+
+static ImagingTransformFilter
+getfilter(Imaging im, int filterid) {
+ switch (filterid) {
+ case IMAGING_TRANSFORM_NEAREST:
+ if (im->image8) {
+ switch (im->type) {
+ case IMAGING_TYPE_UINT8:
+ return nearest_filter8;
+ case IMAGING_TYPE_SPECIAL:
+ switch (im->pixelsize) {
+ case 1:
+ return nearest_filter8;
+ case 2:
+ return nearest_filter16;
+ case 4:
+ return nearest_filter32;
+ }
+ }
+ } else {
+ return nearest_filter32;
+ }
+ break;
+ case IMAGING_TRANSFORM_BILINEAR:
+ if (im->image8) {
+ return bilinear_filter8;
+ } else if (im->image32) {
+ switch (im->type) {
+ case IMAGING_TYPE_UINT8:
+ if (im->bands == 2) {
+ return bilinear_filter32LA;
+ } else {
+ return bilinear_filter32RGB;
+ }
+ case IMAGING_TYPE_INT32:
+ return bilinear_filter32I;
+ case IMAGING_TYPE_FLOAT32:
+ return bilinear_filter32F;
+ }
+ }
+ break;
+ case IMAGING_TRANSFORM_BICUBIC:
+ if (im->image8) {
+ return bicubic_filter8;
+ } else if (im->image32) {
+ switch (im->type) {
+ case IMAGING_TYPE_UINT8:
+ if (im->bands == 2) {
+ return bicubic_filter32LA;
+ } else {
+ return bicubic_filter32RGB;
+ }
+ case IMAGING_TYPE_INT32:
+ return bicubic_filter32I;
+ case IMAGING_TYPE_FLOAT32:
+ return bicubic_filter32F;
+ }
+ }
+ break;
+ }
+ /* no such filter */
+ return NULL;
+}
+
+/* transformation engines */
+
+Imaging
+ImagingGenericTransform(
+ Imaging imOut,
+ Imaging imIn,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ ImagingTransformMap transform,
+ void *transform_data,
+ int filterid,
+ int fill) {
+ /* slow generic transformation. use ImagingTransformAffine or
+ ImagingScaleAffine where possible. */
+
+ ImagingSectionCookie cookie;
+ int x, y;
+ char *out;
+ double xx, yy;
+
+ ImagingTransformFilter filter = getfilter(imIn, filterid);
+ if (!filter) {
+ return (Imaging)ImagingError_ValueError("bad filter number");
+ }
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+ ImagingSectionEnter(&cookie);
+
+ if (x0 < 0) {
+ x0 = 0;
+ }
+ if (y0 < 0) {
+ y0 = 0;
+ }
+ if (x1 > imOut->xsize) {
+ x1 = imOut->xsize;
+ }
+ if (y1 > imOut->ysize) {
+ y1 = imOut->ysize;
+ }
+
+ for (y = y0; y < y1; y++) {
+ out = imOut->image[y] + x0 * imOut->pixelsize;
+ for (x = x0; x < x1; x++) {
+ if (!transform(&xx, &yy, x - x0, y - y0, transform_data) ||
+ !filter(out, imIn, xx, yy)) {
+ if (fill) {
+ memset(out, 0, imOut->pixelsize);
+ }
+ }
+ out += imOut->pixelsize;
+ }
+ }
+
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
+
+static Imaging
+ImagingScaleAffine(
+ Imaging imOut,
+ Imaging imIn,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ double a[6],
+ int fill) {
+ /* scale, nearest neighbour resampling */
+
+ ImagingSectionCookie cookie;
+ int x, y;
+ int xin;
+ double xo, yo;
+ int xmin, xmax;
+ int *xintab;
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+ if (x0 < 0) {
+ x0 = 0;
+ }
+ if (y0 < 0) {
+ y0 = 0;
+ }
+ if (x1 > imOut->xsize) {
+ x1 = imOut->xsize;
+ }
+ if (y1 > imOut->ysize) {
+ y1 = imOut->ysize;
+ }
+
+ /* malloc check ok, uses calloc for overflow */
+ xintab = (int *)calloc(imOut->xsize, sizeof(int));
+ if (!xintab) {
+ ImagingDelete(imOut);
+ return (Imaging)ImagingError_MemoryError();
+ }
+
+ xo = a[2] + a[0] * 0.5;
+ yo = a[5] + a[4] * 0.5;
+
+ xmin = x1;
+ xmax = x0;
+
+ /* Pretabulate horizontal pixel positions */
+ for (x = x0; x < x1; x++) {
+ xin = COORD(xo);
+ if (xin >= 0 && xin < (int)imIn->xsize) {
+ xmax = x + 1;
+ if (x < xmin) {
+ xmin = x;
+ }
+ xintab[x] = xin;
+ }
+ xo += a[0];
+ }
+
+#define AFFINE_SCALE(pixel, image) \
+ for (y = y0; y < y1; y++) { \
+ int yi = COORD(yo); \
+ pixel *in, *out; \
+ out = imOut->image[y]; \
+ if (fill && x1 > x0) { \
+ memset(out + x0, 0, (x1 - x0) * sizeof(pixel)); \
+ } \
+ if (yi >= 0 && yi < imIn->ysize) { \
+ in = imIn->image[yi]; \
+ for (x = xmin; x < xmax; x++) { \
+ out[x] = in[xintab[x]]; \
+ } \
+ } \
+ yo += a[4]; \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ AFFINE_SCALE(UINT8, image8);
+ } else {
+ AFFINE_SCALE(INT32, image32);
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef AFFINE_SCALE
+
+ free(xintab);
+
+ return imOut;
+}
+
+static inline int
+check_fixed(double a[6], int x, int y) {
+ return (
+ fabs(x * a[0] + y * a[1] + a[2]) < 32768.0 &&
+ fabs(x * a[3] + y * a[4] + a[5]) < 32768.0);
+}
+
+static inline Imaging
+affine_fixed(
+ Imaging imOut,
+ Imaging imIn,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ double a[6],
+ int filterid,
+ int fill) {
+ /* affine transform, nearest neighbour resampling, fixed point
+ arithmetics */
+
+ ImagingSectionCookie cookie;
+ int x, y;
+ int xin, yin;
+ int xsize, ysize;
+ int xx, yy;
+ int a0, a1, a2, a3, a4, a5;
+
+ ImagingCopyPalette(imOut, imIn);
+
+ xsize = (int)imIn->xsize;
+ ysize = (int)imIn->ysize;
+
+/* use 16.16 fixed point arithmetics */
+#define FIX(v) FLOOR((v)*65536.0 + 0.5)
+
+ a0 = FIX(a[0]);
+ a1 = FIX(a[1]);
+ a3 = FIX(a[3]);
+ a4 = FIX(a[4]);
+ a2 = FIX(a[2] + a[0] * 0.5 + a[1] * 0.5);
+ a5 = FIX(a[5] + a[3] * 0.5 + a[4] * 0.5);
+
+#undef FIX
+
+#define AFFINE_TRANSFORM_FIXED(pixel, image) \
+ for (y = y0; y < y1; y++) { \
+ pixel *out; \
+ xx = a2; \
+ yy = a5; \
+ out = imOut->image[y]; \
+ if (fill && x1 > x0) { \
+ memset(out + x0, 0, (x1 - x0) * sizeof(pixel)); \
+ } \
+ for (x = x0; x < x1; x++, out++) { \
+ xin = xx >> 16; \
+ if (xin >= 0 && xin < xsize) { \
+ yin = yy >> 16; \
+ if (yin >= 0 && yin < ysize) { \
+ *out = imIn->image[yin][xin]; \
+ } \
+ } \
+ xx += a0; \
+ yy += a3; \
+ } \
+ a2 += a1; \
+ a5 += a4; \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ AFFINE_TRANSFORM_FIXED(UINT8, image8)
+ } else {
+ AFFINE_TRANSFORM_FIXED(INT32, image32)
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef AFFINE_TRANSFORM_FIXED
+
+ return imOut;
+}
+
+Imaging
+ImagingTransformAffine(
+ Imaging imOut,
+ Imaging imIn,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ double a[6],
+ int filterid,
+ int fill) {
+ /* affine transform, nearest neighbour resampling, floating point
+ arithmetics*/
+
+ ImagingSectionCookie cookie;
+ int x, y;
+ int xin, yin;
+ int xsize, ysize;
+ double xx, yy;
+ double xo, yo;
+
+ if (filterid || imIn->type == IMAGING_TYPE_SPECIAL) {
+ return ImagingGenericTransform(
+ imOut, imIn, x0, y0, x1, y1, affine_transform, a, filterid, fill);
+ }
+
+ if (a[1] == 0 && a[3] == 0) {
+ /* Scaling */
+ return ImagingScaleAffine(imOut, imIn, x0, y0, x1, y1, a, fill);
+ }
+
+ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ if (x0 < 0) {
+ x0 = 0;
+ }
+ if (y0 < 0) {
+ y0 = 0;
+ }
+ if (x1 > imOut->xsize) {
+ x1 = imOut->xsize;
+ }
+ if (y1 > imOut->ysize) {
+ y1 = imOut->ysize;
+ }
+
+ /* translate all four corners to check if they are within the
+ range that can be represented by the fixed point arithmetics */
+
+ if (check_fixed(a, 0, 0) && check_fixed(a, x1 - x0, y1 - y0) &&
+ check_fixed(a, 0, y1 - y0) && check_fixed(a, x1 - x0, 0)) {
+ return affine_fixed(imOut, imIn, x0, y0, x1, y1, a, filterid, fill);
+ }
+
+ /* FIXME: cannot really think of any reasonable case when the
+ following code is used. maybe we should fall back on the slow
+ generic transform engine in this case? */
+
+ ImagingCopyPalette(imOut, imIn);
+
+ xsize = (int)imIn->xsize;
+ ysize = (int)imIn->ysize;
+
+ xo = a[2] + a[1] * 0.5 + a[0] * 0.5;
+ yo = a[5] + a[4] * 0.5 + a[3] * 0.5;
+
+#define AFFINE_TRANSFORM(pixel, image) \
+ for (y = y0; y < y1; y++) { \
+ pixel *out; \
+ xx = xo; \
+ yy = yo; \
+ out = imOut->image[y]; \
+ if (fill && x1 > x0) { \
+ memset(out + x0, 0, (x1 - x0) * sizeof(pixel)); \
+ } \
+ for (x = x0; x < x1; x++, out++) { \
+ xin = COORD(xx); \
+ if (xin >= 0 && xin < xsize) { \
+ yin = COORD(yy); \
+ if (yin >= 0 && yin < ysize) { \
+ *out = imIn->image[yin][xin]; \
+ } \
+ } \
+ xx += a[0]; \
+ yy += a[3]; \
+ } \
+ xo += a[1]; \
+ yo += a[4]; \
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ if (imIn->image8) {
+ AFFINE_TRANSFORM(UINT8, image8)
+ } else {
+ AFFINE_TRANSFORM(INT32, image32)
+ }
+
+ ImagingSectionLeave(&cookie);
+
+#undef AFFINE_TRANSFORM
+
+ return imOut;
+}
+
+Imaging
+ImagingTransform(
+ Imaging imOut,
+ Imaging imIn,
+ int method,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ double a[8],
+ int filterid,
+ int fill) {
+ ImagingTransformMap transform;
+
+ switch (method) {
+ case IMAGING_TRANSFORM_AFFINE:
+ return ImagingTransformAffine(
+ imOut, imIn, x0, y0, x1, y1, a, filterid, fill);
+ break;
+ case IMAGING_TRANSFORM_PERSPECTIVE:
+ transform = perspective_transform;
+ break;
+ case IMAGING_TRANSFORM_QUAD:
+ transform = quad_transform;
+ break;
+ default:
+ return (Imaging)ImagingError_ValueError("bad transform method");
+ }
+
+ return ImagingGenericTransform(
+ imOut, imIn, x0, y0, x1, y1, transform, a, filterid, fill);
+}
diff --git a/contrib/python/Pillow/py3/libImaging/GetBBox.c b/contrib/python/Pillow/py3/libImaging/GetBBox.c
new file mode 100644
index 00000000000..86c687ca0a8
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/GetBBox.c
@@ -0,0 +1,356 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * helpers to bounding boxes, min/max values, number of colors, etc.
+ *
+ * history:
+ * 1996-07-22 fl Created
+ * 1996-12-30 fl Added projection stuff
+ * 1998-07-12 fl Added extrema stuff
+ * 2004-09-17 fl Added colors stuff
+ *
+ * Copyright (c) 1997-2004 by Secret Labs AB.
+ * Copyright (c) 1996-2004 by Fredrik Lundh.
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+int
+ImagingGetBBox(Imaging im, int bbox[4], int alpha_only) {
+ /* Get the bounding box for any non-zero data in the image.*/
+
+ int x, y;
+ int has_data;
+
+ /* Initialize bounding box to max values */
+ bbox[0] = im->xsize;
+ bbox[1] = -1;
+ bbox[2] = bbox[3] = 0;
+
+#define GETBBOX(image, mask) \
+ for (y = 0; y < im->ysize; y++) { \
+ has_data = 0; \
+ for (x = 0; x < im->xsize; x++) { \
+ if (im->image[y][x] & mask) { \
+ has_data = 1; \
+ if (x < bbox[0]) { \
+ bbox[0] = x; \
+ } \
+ if (x >= bbox[2]) { \
+ bbox[2] = x + 1; \
+ } \
+ } \
+ } \
+ if (has_data) { \
+ if (bbox[1] < 0) { \
+ bbox[1] = y; \
+ } \
+ bbox[3] = y + 1; \
+ } \
+ }
+
+ if (im->image8) {
+ GETBBOX(image8, 0xff);
+ } else {
+ INT32 mask = 0xffffffff;
+ if (im->bands == 3) {
+ ((UINT8 *)&mask)[3] = 0;
+ } else if (alpha_only && (
+ strcmp(im->mode, "RGBa") == 0 || strcmp(im->mode, "RGBA") == 0 ||
+ strcmp(im->mode, "La") == 0 || strcmp(im->mode, "LA") == 0 ||
+ strcmp(im->mode, "PA") == 0
+ )) {
+#ifdef WORDS_BIGENDIAN
+ mask = 0x000000ff;
+#else
+ mask = 0xff000000;
+#endif
+ }
+ GETBBOX(image32, mask);
+ }
+
+ /* Check that we got a box */
+ if (bbox[1] < 0) {
+ return 0; /* no data */
+ }
+
+ return 1; /* ok */
+}
+
+int
+ImagingGetProjection(Imaging im, UINT8 *xproj, UINT8 *yproj) {
+ /* Get projection arrays for non-zero data in the image.*/
+
+ int x, y;
+ int has_data;
+
+ /* Initialize projection arrays */
+ memset(xproj, 0, im->xsize);
+ memset(yproj, 0, im->ysize);
+
+#define GETPROJ(image, mask) \
+ for (y = 0; y < im->ysize; y++) { \
+ has_data = 0; \
+ for (x = 0; x < im->xsize; x++) { \
+ if (im->image[y][x] & mask) { \
+ has_data = 1; \
+ xproj[x] = 1; \
+ } \
+ } \
+ if (has_data) { \
+ yproj[y] = 1; \
+ } \
+ }
+
+ if (im->image8) {
+ GETPROJ(image8, 0xff);
+ } else {
+ INT32 mask = 0xffffffff;
+ if (im->bands == 3) {
+ ((UINT8 *)&mask)[3] = 0;
+ }
+ GETPROJ(image32, mask);
+ }
+
+ return 1; /* ok */
+}
+
+int
+ImagingGetExtrema(Imaging im, void *extrema) {
+ int x, y;
+ INT32 imin, imax;
+ FLOAT32 fmin, fmax;
+
+ if (im->bands != 1) {
+ (void)ImagingError_ModeError();
+ return -1; /* mismatch */
+ }
+
+ if (!im->xsize || !im->ysize) {
+ return 0; /* zero size */
+ }
+
+ switch (im->type) {
+ case IMAGING_TYPE_UINT8:
+ imin = imax = im->image8[0][0];
+ for (y = 0; y < im->ysize; y++) {
+ UINT8 *in = im->image8[y];
+ for (x = 0; x < im->xsize; x++) {
+ if (imin > in[x]) {
+ imin = in[x];
+ } else if (imax < in[x]) {
+ imax = in[x];
+ }
+ }
+ }
+ ((UINT8 *)extrema)[0] = (UINT8)imin;
+ ((UINT8 *)extrema)[1] = (UINT8)imax;
+ break;
+ case IMAGING_TYPE_INT32:
+ imin = imax = im->image32[0][0];
+ for (y = 0; y < im->ysize; y++) {
+ INT32 *in = im->image32[y];
+ for (x = 0; x < im->xsize; x++) {
+ if (imin > in[x]) {
+ imin = in[x];
+ } else if (imax < in[x]) {
+ imax = in[x];
+ }
+ }
+ }
+ memcpy(extrema, &imin, sizeof(imin));
+ memcpy(((char *)extrema) + sizeof(imin), &imax, sizeof(imax));
+ break;
+ case IMAGING_TYPE_FLOAT32:
+ fmin = fmax = ((FLOAT32 *)im->image32[0])[0];
+ for (y = 0; y < im->ysize; y++) {
+ FLOAT32 *in = (FLOAT32 *)im->image32[y];
+ for (x = 0; x < im->xsize; x++) {
+ if (fmin > in[x]) {
+ fmin = in[x];
+ } else if (fmax < in[x]) {
+ fmax = in[x];
+ }
+ }
+ }
+ memcpy(extrema, &fmin, sizeof(fmin));
+ memcpy(((char *)extrema) + sizeof(fmin), &fmax, sizeof(fmax));
+ break;
+ case IMAGING_TYPE_SPECIAL:
+ if (strcmp(im->mode, "I;16") == 0) {
+ UINT16 v;
+ UINT8 *pixel = *im->image8;
+#ifdef WORDS_BIGENDIAN
+ v = pixel[0] + (pixel[1] << 8);
+#else
+ memcpy(&v, pixel, sizeof(v));
+#endif
+ imin = imax = v;
+ for (y = 0; y < im->ysize; y++) {
+ for (x = 0; x < im->xsize; x++) {
+ pixel = (UINT8 *)im->image[y] + x * sizeof(v);
+#ifdef WORDS_BIGENDIAN
+ v = pixel[0] + (pixel[1] << 8);
+#else
+ memcpy(&v, pixel, sizeof(v));
+#endif
+ if (imin > v) {
+ imin = v;
+ } else if (imax < v) {
+ imax = v;
+ }
+ }
+ }
+ v = (UINT16)imin;
+ memcpy(extrema, &v, sizeof(v));
+ v = (UINT16)imax;
+ memcpy(((char *)extrema) + sizeof(v), &v, sizeof(v));
+ break;
+ }
+ /* FALL THROUGH */
+ default:
+ (void)ImagingError_ModeError();
+ return -1;
+ }
+ return 1; /* ok */
+}
+
+/* static ImagingColorItem* getcolors8(Imaging im, int maxcolors, int* size);*/
+static ImagingColorItem *
+getcolors32(Imaging im, int maxcolors, int *size);
+
+ImagingColorItem *
+ImagingGetColors(Imaging im, int maxcolors, int *size) {
+ /* FIXME: add support for 8-bit images */
+ return getcolors32(im, maxcolors, size);
+}
+
+static ImagingColorItem *
+getcolors32(Imaging im, int maxcolors, int *size) {
+ unsigned int h;
+ unsigned int i, incr;
+ int colors;
+ INT32 pixel_mask;
+ int x, y;
+ ImagingColorItem *table;
+ ImagingColorItem *v;
+
+ unsigned int code_size;
+ unsigned int code_poly;
+ unsigned int code_mask;
+
+ /* note: the hash algorithm used here is based on the dictionary
+ code in Python 2.1.3; the exact implementation is borrowed from
+ Python's Unicode property database (written by yours truly) /F */
+
+ static int SIZES[] = {
+ 4, 3, 8, 3, 16, 3, 32, 5, 64, 3,
+ 128, 3, 256, 29, 512, 17, 1024, 9, 2048, 5,
+ 4096, 83, 8192, 27, 16384, 43, 32768, 3, 65536, 45,
+ 131072, 9, 262144, 39, 524288, 39, 1048576, 9, 2097152, 5,
+ 4194304, 3, 8388608, 33, 16777216, 27, 33554432, 9, 67108864, 71,
+ 134217728, 39, 268435456, 9, 536870912, 5, 1073741824, 83, 0};
+
+ code_size = code_poly = code_mask = 0;
+
+ for (i = 0; SIZES[i]; i += 2) {
+ if (SIZES[i] > maxcolors) {
+ code_size = SIZES[i];
+ code_poly = SIZES[i + 1];
+ code_mask = code_size - 1;
+ break;
+ }
+ }
+
+ /* printf("code_size=%d\n", code_size); */
+ /* printf("code_poly=%d\n", code_poly); */
+
+ if (!code_size) {
+ return ImagingError_MemoryError(); /* just give up */
+ }
+
+ if (!im->image32) {
+ return ImagingError_ModeError();
+ }
+
+ table = calloc(code_size + 1, sizeof(ImagingColorItem));
+ if (!table) {
+ return ImagingError_MemoryError();
+ }
+
+ pixel_mask = 0xffffffff;
+ if (im->bands == 3) {
+ ((UINT8 *)&pixel_mask)[3] = 0;
+ }
+
+ colors = 0;
+
+ for (y = 0; y < im->ysize; y++) {
+ INT32 *p = im->image32[y];
+ for (x = 0; x < im->xsize; x++) {
+ INT32 pixel = p[x] & pixel_mask;
+ h = (pixel); /* null hashing */
+ i = (~h) & code_mask;
+ v = &table[i];
+ if (!v->count) {
+ /* add to table */
+ if (colors++ == maxcolors) {
+ goto overflow;
+ }
+ v->x = x;
+ v->y = y;
+ v->pixel = pixel;
+ v->count = 1;
+ continue;
+ } else if (v->pixel == pixel) {
+ v->count++;
+ continue;
+ }
+ incr = (h ^ (h >> 3)) & code_mask;
+ if (!incr) {
+ incr = code_mask;
+ }
+ for (;;) {
+ i = (i + incr) & code_mask;
+ v = &table[i];
+ if (!v->count) {
+ /* add to table */
+ if (colors++ == maxcolors) {
+ goto overflow;
+ }
+ v->x = x;
+ v->y = y;
+ v->pixel = pixel;
+ v->count = 1;
+ break;
+ } else if (v->pixel == pixel) {
+ v->count++;
+ break;
+ }
+ incr = incr << 1;
+ if (incr > code_mask) {
+ incr = incr ^ code_poly;
+ }
+ }
+ }
+ }
+
+overflow:
+
+ /* pack the table */
+ for (x = y = 0; x < (int)code_size; x++)
+ if (table[x].count) {
+ if (x != y) {
+ table[y] = table[x];
+ }
+ y++;
+ }
+ table[y].count = 0; /* mark end of table */
+
+ *size = colors;
+
+ return table;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Gif.h b/contrib/python/Pillow/py3/libImaging/Gif.h
new file mode 100644
index 00000000000..5d7e2bdaa96
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Gif.h
@@ -0,0 +1,100 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * Declarations for a fast, suspendable GIF decoder.
+ *
+ * Copyright (c) Fredrik Lundh 1995-96.
+ */
+
+/* Max size for a LZW code word. */
+
+#define GIFBITS 12
+
+#define GIFTABLE (1<<GIFBITS)
+#define GIFBUFFER (1<<GIFBITS)
+
+typedef struct {
+ /* CONFIGURATION */
+
+ /* Initial number of bits. The caller should clear all fields in
+ this structure and set this field before calling the decoder
+ the first time. */
+ int bits;
+
+ /* If set, this is an interlaced image. Process it the following way:
+ * 1st pass: start at top line, lines are 8 pixels high, step 8 pixels
+ * 2nd pass: start at line 4, lines are 4 pixels high, step 8 pixels
+ * 3rd pass: start at line 2, lines are 2 pixels high, step 4 pixels
+ * 4th pass: start at line 1, lines are 1 pixels high, step 2 pixels
+ */
+ int interlace;
+
+ /* The transparent palette index, or -1 for no transparency */
+ int transparency;
+
+ /* PRIVATE CONTEXT (set by decoder) */
+
+ /* Interlace parameters */
+ int step, repeat;
+
+ /* Input bit buffer */
+ INT32 bitbuffer;
+ int bitcount;
+ int blocksize;
+
+ /* Code buffer */
+ int codesize;
+ int codemask;
+
+ /* Constant symbol codes */
+ int clear, end;
+
+ /* Symbol history */
+ int lastcode;
+ unsigned char lastdata;
+
+ /* History buffer */
+ int bufferindex;
+ unsigned char buffer[GIFTABLE];
+
+ /* Symbol table */
+ UINT16 link[GIFTABLE];
+ unsigned char data[GIFTABLE];
+ int next;
+
+} GIFDECODERSTATE;
+
+/* For GIF LZW encoder. */
+#define TABLE_SIZE 8192
+
+typedef struct {
+ /* CONFIGURATION */
+
+ /* Initial number of bits. The caller should clear all fields in
+ this structure and set this field before calling the encoder
+ the first time. */
+ int bits;
+
+ /* NOTE: the expanding encoder ignores this field */
+
+ /* If set, write an interlaced image (see above) */
+ int interlace;
+
+ /* PRIVATE CONTEXT (set by encoder) */
+
+ /* Interlace parameters */
+ int step;
+
+ /* For GIF LZW encoder. */
+ UINT32 put_state;
+ UINT32 entry_state;
+ UINT32 clear_code, end_code, next_code, max_code;
+ UINT32 code_width, code_bits_left, buf_bits_left;
+ UINT32 code_buffer;
+ UINT32 head, tail;
+ int probe;
+ UINT32 code;
+ UINT32 codes[TABLE_SIZE];
+
+} GIFENCODERSTATE;
diff --git a/contrib/python/Pillow/py3/libImaging/GifDecode.c b/contrib/python/Pillow/py3/libImaging/GifDecode.c
new file mode 100644
index 00000000000..92b2607b4d9
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/GifDecode.c
@@ -0,0 +1,285 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * a fast, suspendable GIF decoder
+ *
+ * history:
+ * 95-09-03 fl Created
+ * 95-09-05 fl Fixed sign problem on 16-bit platforms
+ * 95-09-13 fl Added some storage shortcuts
+ * 96-03-28 fl Revised API, integrated with PIL
+ * 96-12-10 fl Added interlace support
+ * 96-12-16 fl Fixed premature termination bug introduced by last fix
+ * 97-01-05 fl Don't mess up on bogus configuration
+ * 97-01-17 fl Don't mess up on very small, interlaced files
+ * 99-02-07 fl Minor speedups
+ *
+ * Copyright (c) Secret Labs AB 1997-99.
+ * Copyright (c) Fredrik Lundh 1995-97.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#include <stdio.h>
+#include <memory.h> /* memcpy() */
+
+#include "Gif.h"
+
+#define NEWLINE(state, context) \
+ { \
+ state->x = 0; \
+ state->y += context->step; \
+ while (state->y >= state->ysize) switch (context->interlace) { \
+ case 1: \
+ context->repeat = state->y = 4; \
+ context->interlace = 2; \
+ break; \
+ case 2: \
+ context->step = 4; \
+ context->repeat = state->y = 2; \
+ context->interlace = 3; \
+ break; \
+ case 3: \
+ context->step = 2; \
+ context->repeat = state->y = 1; \
+ context->interlace = 0; \
+ break; \
+ default: \
+ return -1; \
+ } \
+ if (state->y < state->ysize) { \
+ out = im->image8[state->y + state->yoff] + state->xoff; \
+ } \
+ }
+
+int
+ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes) {
+ UINT8 *p;
+ UINT8 *out;
+ int c, i;
+ int thiscode;
+ GIFDECODERSTATE *context = (GIFDECODERSTATE *)state->context;
+
+ UINT8 *ptr = buffer;
+
+ if (!state->state) {
+ /* Initialise state */
+ if (context->bits < 0 || context->bits > 12) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+
+ /* Clear code */
+ context->clear = 1 << context->bits;
+
+ /* End code */
+ context->end = context->clear + 1;
+
+ /* Interlace */
+ if (context->interlace) {
+ context->interlace = 1;
+ context->step = context->repeat = 8;
+ } else {
+ context->step = 1;
+ }
+
+ state->state = 1;
+ }
+
+ out = im->image8[state->y + state->yoff] + state->xoff + state->x;
+
+ for (;;) {
+ if (state->state == 1) {
+ /* First free entry in table */
+ context->next = context->clear + 2;
+
+ /* Initial code size */
+ context->codesize = context->bits + 1;
+ context->codemask = (1 << context->codesize) - 1;
+
+ /* Buffer pointer. We fill the buffer from right, which
+ allows us to return all of it in one operation. */
+ context->bufferindex = GIFBUFFER;
+
+ state->state = 2;
+ }
+
+ if (context->bufferindex < GIFBUFFER) {
+ /* Return whole buffer in one chunk */
+ i = GIFBUFFER - context->bufferindex;
+ p = &context->buffer[context->bufferindex];
+
+ context->bufferindex = GIFBUFFER;
+
+ } else {
+ /* Get current symbol */
+
+ while (context->bitcount < context->codesize) {
+ if (context->blocksize > 0) {
+ /* Read next byte */
+ c = *ptr++;
+ bytes--;
+
+ context->blocksize--;
+
+ /* New bits are shifted in from the left. */
+ context->bitbuffer |= (INT32)c << context->bitcount;
+ context->bitcount += 8;
+
+ } else {
+ /* New GIF block */
+
+ /* We don't start decoding unless we have a full block */
+ if (bytes < 1) {
+ return ptr - buffer;
+ }
+ c = *ptr;
+ if (bytes < c + 1) {
+ return ptr - buffer;
+ }
+
+ context->blocksize = c;
+
+ ptr++;
+ bytes--;
+ }
+ }
+
+ /* Extract current symbol from bit buffer. */
+ c = (int)context->bitbuffer & context->codemask;
+
+ /* Adjust buffer */
+ context->bitbuffer >>= context->codesize;
+ context->bitcount -= context->codesize;
+
+ /* If c is less than "clear", it's a data byte. Otherwise,
+ it's either clear/end or a code symbol which should be
+ expanded. */
+
+ if (c == context->clear) {
+ if (state->state != 2) {
+ state->state = 1;
+ }
+ continue;
+ }
+
+ if (c == context->end) {
+ break;
+ }
+
+ i = 1;
+ p = &context->lastdata;
+
+ if (state->state == 2) {
+ /* First valid symbol after clear; use as is */
+ if (c > context->clear) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ context->lastdata = context->lastcode = c;
+ state->state = 3;
+
+ } else {
+ thiscode = c;
+
+ if (c > context->next) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ if (c == context->next) {
+ /* c == next is allowed. not sure why. */
+
+ if (context->bufferindex <= 0) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ context->buffer[--context->bufferindex] = context->lastdata;
+
+ c = context->lastcode;
+ }
+
+ while (c >= context->clear) {
+ /* Copy data string to buffer (beginning from right) */
+
+ if (context->bufferindex <= 0 || c >= GIFTABLE) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ context->buffer[--context->bufferindex] = context->data[c];
+
+ c = context->link[c];
+ }
+
+ context->lastdata = c;
+
+ if (context->next < GIFTABLE) {
+ /* We'll only add this symbol if we have room
+ for it (take the advice, Netscape!) */
+ context->data[context->next] = c;
+ context->link[context->next] = context->lastcode;
+
+ if (context->next == context->codemask &&
+ context->codesize < GIFBITS) {
+ /* Expand code size */
+ context->codesize++;
+ context->codemask = (1 << context->codesize) - 1;
+ }
+
+ context->next++;
+ }
+
+ context->lastcode = thiscode;
+ }
+ }
+
+ /* Copy the bytes into the image */
+ if (state->y >= state->ysize) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+
+ /* To squeeze some extra pixels out of this loop, we test for
+ some common cases and handle them separately. */
+
+ /* This cannot be used if there is transparency */
+ if (context->transparency == -1) {
+ if (i == 1) {
+ if (state->x < state->xsize - 1) {
+ /* Single pixel, not at the end of the line. */
+ *out++ = p[0];
+ state->x++;
+ continue;
+ }
+ } else if (state->x + i <= state->xsize) {
+ /* This string fits into current line. */
+ memcpy(out, p, i);
+ out += i;
+ state->x += i;
+ if (state->x == state->xsize) {
+ NEWLINE(state, context);
+ }
+ continue;
+ }
+ }
+
+ /* No shortcut, copy pixel by pixel */
+ for (c = 0; c < i; c++) {
+ if (p[c] != context->transparency) {
+ *out = p[c];
+ }
+ out++;
+ if (++state->x >= state->xsize) {
+ NEWLINE(state, context);
+ }
+ }
+ }
+
+ return ptr - buffer;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/GifEncode.c b/contrib/python/Pillow/py3/libImaging/GifEncode.c
new file mode 100644
index 00000000000..f232454052a
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/GifEncode.c
@@ -0,0 +1,361 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * encoder for uncompressed GIF data
+ *
+ * history:
+ * 97-01-05 fl created (writes uncompressed data)
+ * 97-08-27 fl fixed off-by-one error in buffer size test
+ * 98-07-09 fl added interlace write support
+ * 99-02-07 fl rewritten, now uses a run-length encoding strategy
+ * 99-02-08 fl improved run-length encoding for long runs
+ * 2020-12-12 rdg Reworked for LZW compression.
+ *
+ * Copyright (c) Secret Labs AB 1997-99.
+ * Copyright (c) Fredrik Lundh 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#include "Gif.h"
+
+enum { INIT, ENCODE, FINISH };
+
+/* GIF LZW encoder by Raymond Gardner. */
+/* Released here under PIL license. */
+
+/* This LZW encoder conforms to the GIF LZW format specified in the original
+ * Compuserve GIF 87a and GIF 89a specifications (see e.g.
+ * https://www.w3.org/Graphics/GIF/spec-gif87.txt Appendix C and
+ * https://www.w3.org/Graphics/GIF/spec-gif89a.txt Appendix F).
+ */
+
+/* Return values */
+#define GLZW_OK 0
+#define GLZW_NO_INPUT_AVAIL 1
+#define GLZW_NO_OUTPUT_AVAIL 2
+#define GLZW_INTERNAL_ERROR 3
+
+#define CODE_LIMIT 4096
+
+/* Values of entry_state */
+enum { LZW_INITIAL, LZW_TRY_IN1, LZW_TRY_IN2, LZW_TRY_OUT1, LZW_TRY_OUT2,
+ LZW_FINISHED };
+
+/* Values of control_state */
+enum { PUT_HEAD, PUT_INIT_CLEAR, PUT_CLEAR, PUT_LAST_HEAD, PUT_END };
+
+static void glzwe_reset(GIFENCODERSTATE *st) {
+ st->next_code = st->end_code + 1;
+ st->max_code = 2 * st->clear_code - 1;
+ st->code_width = st->bits + 1;
+ memset(st->codes, 0, sizeof(st->codes));
+}
+
+static void glzwe_init(GIFENCODERSTATE *st) {
+ st->clear_code = 1 << st->bits;
+ st->end_code = st->clear_code + 1;
+ glzwe_reset(st);
+ st->entry_state = LZW_INITIAL;
+ st->buf_bits_left = 8;
+ st->code_buffer = 0;
+}
+
+static int glzwe(GIFENCODERSTATE *st, const UINT8 *in_ptr, UINT8 *out_ptr,
+ UINT32 *in_avail, UINT32 *out_avail,
+ UINT32 end_of_data) {
+ switch (st->entry_state) {
+
+ case LZW_TRY_IN1:
+get_first_byte:
+ if (!*in_avail) {
+ if (end_of_data) {
+ goto end_of_data;
+ }
+ st->entry_state = LZW_TRY_IN1;
+ return GLZW_NO_INPUT_AVAIL;
+ }
+ st->head = *in_ptr++;
+ (*in_avail)--;
+
+ case LZW_TRY_IN2:
+encode_loop:
+ if (!*in_avail) {
+ if (end_of_data) {
+ st->code = st->head;
+ st->put_state = PUT_LAST_HEAD;
+ goto put_code;
+ }
+ st->entry_state = LZW_TRY_IN2;
+ return GLZW_NO_INPUT_AVAIL;
+ }
+ st->tail = *in_ptr++;
+ (*in_avail)--;
+
+ /* Knuth TAOCP vol 3 sec. 6.4 algorithm D. */
+ /* Hash found experimentally to be pretty good. */
+ /* This works ONLY with TABLE_SIZE a power of 2. */
+ st->probe = ((st->head ^ (st->tail << 6)) * 31) & (TABLE_SIZE - 1);
+ while (st->codes[st->probe]) {
+ if ((st->codes[st->probe] & 0xFFFFF) ==
+ ((st->head << 8) | st->tail)) {
+ st->head = st->codes[st->probe] >> 20;
+ goto encode_loop;
+ } else {
+ /* Reprobe decrement must be nonzero and relatively prime to table
+ * size. So, any odd positive number for power-of-2 size. */
+ if ((st->probe -= ((st->tail << 2) | 1)) < 0) {
+ st->probe += TABLE_SIZE;
+ }
+ }
+ }
+ /* Key not found, probe is at empty slot. */
+ st->code = st->head;
+ st->put_state = PUT_HEAD;
+ goto put_code;
+insert_code_or_clear: /* jump here after put_code */
+ if (st->next_code < CODE_LIMIT) {
+ st->codes[st->probe] = (st->next_code << 20) |
+ (st->head << 8) | st->tail;
+ if (st->next_code > st->max_code) {
+ st->max_code = st->max_code * 2 + 1;
+ st->code_width++;
+ }
+ st->next_code++;
+ } else {
+ st->code = st->clear_code;
+ st->put_state = PUT_CLEAR;
+ goto put_code;
+reset_after_clear: /* jump here after put_code */
+ glzwe_reset(st);
+ }
+ st->head = st->tail;
+ goto encode_loop;
+
+ case LZW_INITIAL:
+ glzwe_reset(st);
+ st->code = st->clear_code;
+ st->put_state = PUT_INIT_CLEAR;
+put_code:
+ st->code_bits_left = st->code_width;
+check_buf_bits:
+ if (!st->buf_bits_left) { /* out buffer full */
+
+ case LZW_TRY_OUT1:
+ if (!*out_avail) {
+ st->entry_state = LZW_TRY_OUT1;
+ return GLZW_NO_OUTPUT_AVAIL;
+ }
+ *out_ptr++ = st->code_buffer;
+ (*out_avail)--;
+ st->code_buffer = 0;
+ st->buf_bits_left = 8;
+ }
+ /* code bits to pack */
+ UINT32 n = st->buf_bits_left < st->code_bits_left
+ ? st->buf_bits_left : st->code_bits_left;
+ st->code_buffer |=
+ (st->code & ((1 << n) - 1)) << (8 - st->buf_bits_left);
+ st->code >>= n;
+ st->buf_bits_left -= n;
+ st->code_bits_left -= n;
+ if (st->code_bits_left) {
+ goto check_buf_bits;
+ }
+ switch (st->put_state) {
+ case PUT_INIT_CLEAR:
+ goto get_first_byte;
+ case PUT_HEAD:
+ goto insert_code_or_clear;
+ case PUT_CLEAR:
+ goto reset_after_clear;
+ case PUT_LAST_HEAD:
+ goto end_of_data;
+ case PUT_END:
+ goto flush_code_buffer;
+ default:
+ return GLZW_INTERNAL_ERROR;
+ }
+
+end_of_data:
+ st->code = st->end_code;
+ st->put_state = PUT_END;
+ goto put_code;
+flush_code_buffer: /* jump here after put_code */
+ if (st->buf_bits_left < 8) {
+
+ case LZW_TRY_OUT2:
+ if (!*out_avail) {
+ st->entry_state = LZW_TRY_OUT2;
+ return GLZW_NO_OUTPUT_AVAIL;
+ }
+ *out_ptr++ = st->code_buffer;
+ (*out_avail)--;
+ }
+ st->entry_state = LZW_FINISHED;
+ return GLZW_OK;
+
+ case LZW_FINISHED:
+ return GLZW_OK;
+
+ default:
+ return GLZW_INTERNAL_ERROR;
+ }
+}
+/* -END- GIF LZW encoder. */
+
+int
+ImagingGifEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes) {
+ UINT8* ptr;
+ UINT8* sub_block_ptr;
+ UINT8* sub_block_limit;
+ UINT8* buf_limit;
+ GIFENCODERSTATE *context = (GIFENCODERSTATE*) state->context;
+ int r;
+
+ UINT32 in_avail, in_used;
+ UINT32 out_avail, out_used;
+
+ if (state->state == INIT) {
+ state->state = ENCODE;
+ glzwe_init(context);
+
+ if (context->interlace) {
+ context->interlace = 1;
+ context->step = 8;
+ } else {
+ context->step = 1;
+ }
+
+ /* Need at least 2 bytes for data sub-block; 5 for empty image */
+ if (bytes < 5) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return 0;
+ }
+ /* sanity check */
+ if (state->xsize <= 0 || state->ysize <= 0) {
+ /* Is this better than an error return? */
+ /* This will handle any legal "LZW Minimum Code Size" */
+ memset(buf, 0, 5);
+ in_avail = 0;
+ out_avail = 5;
+ r = glzwe(context, (const UINT8 *)"", buf + 1, &in_avail, &out_avail, 1);
+ if (r == GLZW_OK) {
+ r = 5 - out_avail;
+ if (r < 1 || r > 3) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return 0;
+ }
+ buf[0] = r;
+ state->errcode = IMAGING_CODEC_END;
+ return r + 2;
+ } else {
+ /* Should not be possible unless something external to this
+ * routine messes with our state data */
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return 0;
+ }
+ }
+ /* Init state->x to make if() below true the first time through. */
+ state->x = state->xsize;
+ }
+
+ buf_limit = buf + bytes;
+ sub_block_limit = sub_block_ptr = ptr = buf;
+
+ /* On entry, buf is output buffer, bytes is space available in buf.
+ * Loop here getting input until buf is full or image is all encoded. */
+ for (;;) {
+ /* Set up sub-block ptr and limit. sub_block_ptr stays at beginning
+ * of sub-block until it is full. ptr will advance when any data is
+ * placed in buf.
+ */
+ if (ptr >= sub_block_limit) {
+ if (buf_limit - ptr < 2) { /* Need at least 2 for data sub-block */
+ return ptr - buf;
+ }
+ sub_block_ptr = ptr;
+ sub_block_limit = sub_block_ptr +
+ (256 < buf_limit - sub_block_ptr ?
+ 256 : buf_limit - sub_block_ptr);
+ *ptr++ = 0;
+ }
+
+ /* Get next row of pixels. */
+ /* This if() originally tested state->x==0 for the first time through.
+ * This no longer works, as the loop will not advance state->x if
+ * glzwe() does not consume any input; this would advance the row
+ * spuriously. Now pre-init state->x above for first time, and avoid
+ * entering if() when state->state is FINISH, or it will loop
+ * infinitely.
+ */
+ if (state->x >= state->xsize && state->state == ENCODE) {
+ if (!context->interlace && state->y >= state->ysize) {
+ state->state = FINISH;
+ continue;
+ }
+
+ /* get another line of data */
+ state->shuffle(
+ state->buffer,
+ (UINT8*) im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize, state->xsize
+ );
+ state->x = 0;
+
+ /* step forward, according to the interlace settings */
+ state->y += context->step;
+ while (context->interlace && state->y >= state->ysize) {
+ switch (context->interlace) {
+ case 1:
+ state->y = 4;
+ context->interlace = 2;
+ break;
+ case 2:
+ context->step = 4;
+ state->y = 2;
+ context->interlace = 3;
+ break;
+ case 3:
+ context->step = 2;
+ state->y = 1;
+ context->interlace = 0;
+ break;
+ default:
+ /* just make sure we don't loop forever */
+ context->interlace = 0;
+ }
+ }
+ }
+
+ in_avail = state->xsize - state->x; /* bytes left in line */
+ out_avail = sub_block_limit - ptr; /* bytes left in sub-block */
+ r = glzwe(context, &state->buffer[state->x], ptr, &in_avail,
+ &out_avail, state->state == FINISH);
+ out_used = sub_block_limit - ptr - out_avail;
+ *sub_block_ptr += out_used;
+ ptr += out_used;
+ in_used = state->xsize - state->x - in_avail;
+ state->x += in_used;
+
+ if (r == GLZW_OK) {
+ /* Should not be possible when end-of-data flag is false. */
+ state->errcode = IMAGING_CODEC_END;
+ return ptr - buf;
+ } else if (r == GLZW_NO_INPUT_AVAIL) {
+ /* Used all the input line; get another line */
+ continue;
+ } else if (r == GLZW_NO_OUTPUT_AVAIL) {
+ /* subblock is full */
+ continue;
+ } else {
+ /* Should not be possible unless something external to this
+ * routine messes with our state data */
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return 0;
+ }
+ }
+}
diff --git a/contrib/python/Pillow/py3/libImaging/HexDecode.c b/contrib/python/Pillow/py3/libImaging/HexDecode.c
new file mode 100644
index 00000000000..bd16cdbe1da
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/HexDecode.c
@@ -0,0 +1,63 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for hex encoded image data
+ *
+ * history:
+ * 96-05-16 fl Created
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#define HEX(v) \
+ ((v >= '0' && v <= '9') ? v - '0' \
+ : (v >= 'a' && v <= 'f') ? v - 'a' + 10 \
+ : (v >= 'A' && v <= 'F') ? v - 'A' + 10 \
+ : -1)
+
+int
+ImagingHexDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ UINT8 *ptr;
+ int a, b;
+
+ ptr = buf;
+
+ for (;;) {
+ if (bytes < 2) {
+ return ptr - buf;
+ }
+
+ a = HEX(ptr[0]);
+ b = HEX(ptr[1]);
+
+ if (a < 0 || b < 0) {
+ ptr++;
+ bytes--;
+
+ } else {
+ ptr += 2;
+ bytes -= 2;
+
+ state->buffer[state->x] = (a << 4) + b;
+
+ if (++state->x >= state->bytes) {
+ /* Got a full line, unpack it */
+ state->shuffle(
+ (UINT8 *)im->image[state->y], state->buffer, state->xsize);
+
+ state->x = 0;
+
+ if (++state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+ }
+ }
+ }
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Histo.c b/contrib/python/Pillow/py3/libImaging/Histo.c
new file mode 100644
index 00000000000..c5a547a647b
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Histo.c
@@ -0,0 +1,201 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * histogram support
+ *
+ * history:
+ * 1995-06-15 fl Created.
+ * 1996-04-05 fl Fixed histogram for multiband images.
+ * 1997-02-23 fl Added mask support
+ * 1998-07-01 fl Added basic 32-bit float/integer support
+ *
+ * Copyright (c) 1997-2003 by Secret Labs AB.
+ * Copyright (c) 1995-2003 by Fredrik Lundh.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+/* HISTOGRAM */
+/* --------------------------------------------------------------------
+ * Take a histogram of an image. Returns a histogram object containing
+ * 256 slots per band in the input image.
+ */
+
+void
+ImagingHistogramDelete(ImagingHistogram h) {
+ if (h) {
+ if (h->histogram) {
+ free(h->histogram);
+ }
+ free(h);
+ }
+}
+
+ImagingHistogram
+ImagingHistogramNew(Imaging im) {
+ ImagingHistogram h;
+
+ /* Create histogram descriptor */
+ h = calloc(1, sizeof(struct ImagingHistogramInstance));
+ if (!h) {
+ return (ImagingHistogram)ImagingError_MemoryError();
+ }
+ strncpy(h->mode, im->mode, IMAGING_MODE_LENGTH - 1);
+ h->mode[IMAGING_MODE_LENGTH - 1] = 0;
+
+ h->bands = im->bands;
+ h->histogram = calloc(im->pixelsize, 256 * sizeof(long));
+ if (!h->histogram) {
+ free(h);
+ return (ImagingHistogram)ImagingError_MemoryError();
+ }
+
+ return h;
+}
+
+ImagingHistogram
+ImagingGetHistogram(Imaging im, Imaging imMask, void *minmax) {
+ ImagingSectionCookie cookie;
+ int x, y, i;
+ ImagingHistogram h;
+ INT32 imin, imax;
+ FLOAT32 fmin, fmax, scale;
+
+ if (!im) {
+ return ImagingError_ModeError();
+ }
+
+ if (imMask) {
+ /* Validate mask */
+ if (im->xsize != imMask->xsize || im->ysize != imMask->ysize) {
+ return ImagingError_Mismatch();
+ }
+ if (strcmp(imMask->mode, "1") != 0 && strcmp(imMask->mode, "L") != 0) {
+ return ImagingError_ValueError("bad transparency mask");
+ }
+ }
+
+ h = ImagingHistogramNew(im);
+ if (!h) {
+ return NULL;
+ }
+
+ if (imMask) {
+ /* mask */
+ if (im->image8) {
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < im->ysize; y++) {
+ for (x = 0; x < im->xsize; x++) {
+ if (imMask->image8[y][x] != 0) {
+ h->histogram[im->image8[y][x]]++;
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ } else { /* yes, we need the braces. C isn't Python! */
+ if (im->type != IMAGING_TYPE_UINT8) {
+ ImagingHistogramDelete(h);
+ return ImagingError_ModeError();
+ }
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < im->ysize; y++) {
+ UINT8 *in = (UINT8 *)im->image32[y];
+ for (x = 0; x < im->xsize; x++) {
+ if (imMask->image8[y][x] != 0) {
+ h->histogram[(*in++)]++;
+ h->histogram[(*in++) + 256]++;
+ h->histogram[(*in++) + 512]++;
+ h->histogram[(*in++) + 768]++;
+ } else {
+ in += 4;
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ }
+ } else {
+ /* mask not given; process pixels in image */
+ if (im->image8) {
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < im->ysize; y++) {
+ for (x = 0; x < im->xsize; x++) {
+ h->histogram[im->image8[y][x]]++;
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ } else {
+ switch (im->type) {
+ case IMAGING_TYPE_UINT8:
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < im->ysize; y++) {
+ UINT8 *in = (UINT8 *)im->image[y];
+ for (x = 0; x < im->xsize; x++) {
+ h->histogram[(*in++)]++;
+ h->histogram[(*in++) + 256]++;
+ h->histogram[(*in++) + 512]++;
+ h->histogram[(*in++) + 768]++;
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ break;
+ case IMAGING_TYPE_INT32:
+ if (!minmax) {
+ ImagingHistogramDelete(h);
+ return ImagingError_ValueError("min/max not given");
+ }
+ if (!im->xsize || !im->ysize) {
+ break;
+ }
+ memcpy(&imin, minmax, sizeof(imin));
+ memcpy(&imax, ((char *)minmax) + sizeof(imin), sizeof(imax));
+ if (imin >= imax) {
+ break;
+ }
+ ImagingSectionEnter(&cookie);
+ scale = 255.0F / (imax - imin);
+ for (y = 0; y < im->ysize; y++) {
+ INT32 *in = im->image32[y];
+ for (x = 0; x < im->xsize; x++) {
+ i = (int)(((*in++) - imin) * scale);
+ if (i >= 0 && i < 256) {
+ h->histogram[i]++;
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ break;
+ case IMAGING_TYPE_FLOAT32:
+ if (!minmax) {
+ ImagingHistogramDelete(h);
+ return ImagingError_ValueError("min/max not given");
+ }
+ if (!im->xsize || !im->ysize) {
+ break;
+ }
+ memcpy(&fmin, minmax, sizeof(fmin));
+ memcpy(&fmax, ((char *)minmax) + sizeof(fmin), sizeof(fmax));
+ if (fmin >= fmax) {
+ break;
+ }
+ ImagingSectionEnter(&cookie);
+ scale = 255.0F / (fmax - fmin);
+ for (y = 0; y < im->ysize; y++) {
+ FLOAT32 *in = (FLOAT32 *)im->image32[y];
+ for (x = 0; x < im->xsize; x++) {
+ i = (int)(((*in++) - fmin) * scale);
+ if (i >= 0 && i < 256) {
+ h->histogram[i]++;
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ break;
+ }
+ }
+ }
+
+ return h;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/ImDib.h b/contrib/python/Pillow/py3/libImaging/ImDib.h
new file mode 100644
index 00000000000..91ff3f322ff
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/ImDib.h
@@ -0,0 +1,64 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * Windows DIB specifics
+ *
+ * Copyright (c) Secret Labs AB 1997-98.
+ * Copyright (c) Fredrik Lundh 1996.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#ifdef _WIN32
+
+#include "ImPlatform.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct ImagingDIBInstance {
+ /* Windows interface */
+ HDC dc;
+ HBITMAP bitmap;
+ HGDIOBJ old_bitmap;
+ BITMAPINFO *info;
+ UINT8 *bits;
+ HPALETTE palette;
+ /* Used by cut and paste */
+ char mode[4];
+ int xsize, ysize;
+ int pixelsize;
+ int linesize;
+ ImagingShuffler pack;
+ ImagingShuffler unpack;
+};
+
+typedef struct ImagingDIBInstance *ImagingDIB;
+
+extern char *
+ImagingGetModeDIB(int size_out[2]);
+
+extern ImagingDIB
+ImagingNewDIB(const char *mode, int xsize, int ysize);
+
+extern void
+ImagingDeleteDIB(ImagingDIB im);
+
+extern void
+ImagingDrawDIB(ImagingDIB dib, void *dc, int dst[4], int src[4]);
+extern void
+ImagingExposeDIB(ImagingDIB dib, void *dc);
+
+extern int
+ImagingQueryPaletteDIB(ImagingDIB dib, void *dc);
+
+extern void
+ImagingPasteDIB(ImagingDIB dib, Imaging im, int xy[4]);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/ImPlatform.h b/contrib/python/Pillow/py3/libImaging/ImPlatform.h
new file mode 100644
index 00000000000..f6e7fb6b921
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/ImPlatform.h
@@ -0,0 +1,98 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * platform declarations for the imaging core library
+ *
+ * Copyright (c) Fredrik Lundh 1995-2003.
+ */
+
+#include "Python.h"
+
+/* Check that we have an ANSI compliant compiler */
+#ifndef HAVE_PROTOTYPES
+#error Sorry, this library requires support for ANSI prototypes.
+#endif
+#ifndef STDC_HEADERS
+#error Sorry, this library requires ANSI header files.
+#endif
+
+#if defined(PIL_NO_INLINE)
+#define inline
+#else
+#if defined(_MSC_VER) && !defined(__GNUC__)
+#define inline __inline
+#endif
+#endif
+
+#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+#ifdef __CYGWIN__
+#undef _WIN64
+#undef _WIN32
+#undef __WIN32__
+#undef WIN32
+#endif
+
+#else /* not WIN */
+/* For System that are not Windows, we'll need to define these. */
+/* We have to define them instead of using typedef because the JPEG lib also
+ defines their own types with the same names, so we need to be able to undef
+ ours before including the JPEG code. */
+
+#if __STDC_VERSION__ >= 199901L /* C99+ */
+
+#include <stdint.h>
+
+#define INT8 int8_t
+#define UINT8 uint8_t
+#define INT16 int16_t
+#define UINT16 uint16_t
+#define INT32 int32_t
+#define UINT32 uint32_t
+
+#else /* < C99 */
+
+#define INT8 signed char
+
+#if SIZEOF_SHORT == 2
+#define INT16 short
+#elif SIZEOF_INT == 2
+#define INT16 int
+#else
+#error Cannot find required 16-bit integer type
+#endif
+
+#if SIZEOF_SHORT == 4
+#define INT32 short
+#elif SIZEOF_INT == 4
+#define INT32 int
+#elif SIZEOF_LONG == 4
+#define INT32 long
+#else
+#error Cannot find required 32-bit integer type
+#endif
+
+#define UINT8 unsigned char
+#define UINT16 unsigned INT16
+#define UINT32 unsigned INT32
+
+#endif /* < C99 */
+
+#endif /* not WIN */
+
+/* assume IEEE; tweak if necessary (patches are welcome) */
+#define FLOAT16 UINT16
+#define FLOAT32 float
+#define FLOAT64 double
+
+#ifdef _MSC_VER
+typedef signed __int64 int64_t;
+#endif
+
+#ifdef __GNUC__
+#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/Imaging.h b/contrib/python/Pillow/py3/libImaging/Imaging.h
new file mode 100644
index 00000000000..afcd2229bde
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Imaging.h
@@ -0,0 +1,693 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * declarations for the imaging core library
+ *
+ * Copyright (c) 1997-2005 by Secret Labs AB
+ * Copyright (c) 1995-2005 by Fredrik Lundh
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "ImPlatform.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef M_PI
+#define M_PI 3.1415926535897932384626433832795
+#endif
+
+/* -------------------------------------------------------------------- */
+
+/*
+ * Image data organization:
+ *
+ * mode bytes byte order
+ * -------------------------------
+ * 1 1 1
+ * L 1 L
+ * P 1 P
+ * I 4 I (32-bit integer, native byte order)
+ * F 4 F (32-bit IEEE float, native byte order)
+ * RGB 4 R, G, B, -
+ * RGBA 4 R, G, B, A
+ * CMYK 4 C, M, Y, K
+ * YCbCr 4 Y, Cb, Cr, -
+ * Lab 4 L, a, b, -
+ *
+ * experimental modes (incomplete):
+ * LA 4 L, -, -, A
+ * PA 4 P, -, -, A
+ * I;16 2 I (16-bit integer, native byte order)
+ *
+ * "P" is an 8-bit palette mode, which should be mapped through the
+ * palette member to get an output image. Check palette->mode to
+ * find the corresponding "real" mode.
+ *
+ * For information on how to access Imaging objects from your own C
+ * extensions, see http://www.effbot.org/zone/pil-extending.htm
+ */
+
+/* Handles */
+
+typedef struct ImagingMemoryInstance *Imaging;
+
+typedef struct ImagingAccessInstance *ImagingAccess;
+typedef struct ImagingHistogramInstance *ImagingHistogram;
+typedef struct ImagingOutlineInstance *ImagingOutline;
+typedef struct ImagingPaletteInstance *ImagingPalette;
+
+/* handle magics (used with PyCObject). */
+#define IMAGING_MAGIC "PIL Imaging"
+
+/* pixel types */
+#define IMAGING_TYPE_UINT8 0
+#define IMAGING_TYPE_INT32 1
+#define IMAGING_TYPE_FLOAT32 2
+#define IMAGING_TYPE_SPECIAL 3 /* check mode for details */
+
+#define IMAGING_MODE_LENGTH \
+ 6 + 1 /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", "YCbCr", "BGR;xy") */
+
+typedef struct {
+ char *ptr;
+ int size;
+} ImagingMemoryBlock;
+
+struct ImagingMemoryInstance {
+ /* Format */
+ char mode[IMAGING_MODE_LENGTH]; /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK",
+ "YCbCr", "BGR;xy") */
+ int type; /* Data type (IMAGING_TYPE_*) */
+ int depth; /* Depth (ignored in this version) */
+ int bands; /* Number of bands (1, 2, 3, or 4) */
+ int xsize; /* Image dimension. */
+ int ysize;
+
+ /* Colour palette (for "P" images only) */
+ ImagingPalette palette;
+
+ /* Data pointers */
+ UINT8 **image8; /* Set for 8-bit images (pixelsize=1). */
+ INT32 **image32; /* Set for 32-bit images (pixelsize=4). */
+
+ /* Internals */
+ char **image; /* Actual raster data. */
+ char *block; /* Set if data is allocated in a single block. */
+ ImagingMemoryBlock *blocks; /* Memory blocks for pixel storage */
+
+ int pixelsize; /* Size of a pixel, in bytes (1, 2 or 4) */
+ int linesize; /* Size of a line, in bytes (xsize * pixelsize) */
+
+ /* Virtual methods */
+ void (*destroy)(Imaging im);
+};
+
+#define IMAGING_PIXEL_1(im, x, y) ((im)->image8[(y)][(x)])
+#define IMAGING_PIXEL_L(im, x, y) ((im)->image8[(y)][(x)])
+#define IMAGING_PIXEL_LA(im, x, y) ((im)->image[(y)][(x)*4])
+#define IMAGING_PIXEL_P(im, x, y) ((im)->image8[(y)][(x)])
+#define IMAGING_PIXEL_PA(im, x, y) ((im)->image[(y)][(x)*4])
+#define IMAGING_PIXEL_I(im, x, y) ((im)->image32[(y)][(x)])
+#define IMAGING_PIXEL_F(im, x, y) (((FLOAT32 *)(im)->image32[y])[x])
+#define IMAGING_PIXEL_RGB(im, x, y) ((im)->image[(y)][(x)*4])
+#define IMAGING_PIXEL_RGBA(im, x, y) ((im)->image[(y)][(x)*4])
+#define IMAGING_PIXEL_CMYK(im, x, y) ((im)->image[(y)][(x)*4])
+#define IMAGING_PIXEL_YCbCr(im, x, y) ((im)->image[(y)][(x)*4])
+
+#define IMAGING_PIXEL_UINT8(im, x, y) ((im)->image8[(y)][(x)])
+#define IMAGING_PIXEL_INT32(im, x, y) ((im)->image32[(y)][(x)])
+#define IMAGING_PIXEL_FLOAT32(im, x, y) (((FLOAT32 *)(im)->image32[y])[x])
+
+struct ImagingAccessInstance {
+ const char *mode;
+ void (*get_pixel)(Imaging im, int x, int y, void *pixel);
+ void (*put_pixel)(Imaging im, int x, int y, const void *pixel);
+};
+
+struct ImagingHistogramInstance {
+ /* Format */
+ char mode[IMAGING_MODE_LENGTH]; /* Band names (of corresponding source image) */
+ int bands; /* Number of bands (1, 3, or 4) */
+
+ /* Data */
+ long *histogram; /* Histogram (bands*256 longs) */
+};
+
+struct ImagingPaletteInstance {
+ /* Format */
+ char mode[IMAGING_MODE_LENGTH]; /* Band names */
+
+ /* Data */
+ int size;
+ UINT8 palette[1024]; /* Palette data (same format as image data) */
+
+ INT16 *cache; /* Palette cache (used for predefined palettes) */
+ int keep_cache; /* This palette will be reused; keep cache */
+};
+
+typedef struct ImagingMemoryArena {
+ int alignment; /* Alignment in memory of each line of an image */
+ int block_size; /* Preferred block size, bytes */
+ int blocks_max; /* Maximum number of cached blocks */
+ int blocks_cached; /* Current number of blocks not associated with images */
+ ImagingMemoryBlock *blocks_pool;
+ int stats_new_count; /* Number of new allocated images */
+ int stats_allocated_blocks; /* Number of allocated blocks */
+ int stats_reused_blocks; /* Number of blocks which were retrieved from a pool */
+ int stats_reallocated_blocks; /* Number of blocks which were actually reallocated
+ after retrieving */
+ int stats_freed_blocks; /* Number of freed blocks */
+} * ImagingMemoryArena;
+
+/* Objects */
+/* ------- */
+
+extern struct ImagingMemoryArena ImagingDefaultArena;
+extern int
+ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max);
+extern void
+ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size);
+
+extern Imaging
+ImagingNew(const char *mode, int xsize, int ysize);
+extern Imaging
+ImagingNewDirty(const char *mode, int xsize, int ysize);
+extern Imaging
+ImagingNew2Dirty(const char *mode, Imaging imOut, Imaging imIn);
+extern void
+ImagingDelete(Imaging im);
+
+extern Imaging
+ImagingNewBlock(const char *mode, int xsize, int ysize);
+
+extern Imaging
+ImagingNewPrologue(const char *mode, int xsize, int ysize);
+extern Imaging
+ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int structure_size);
+
+extern void
+ImagingCopyPalette(Imaging destination, Imaging source);
+
+extern void
+ImagingHistogramDelete(ImagingHistogram histogram);
+
+extern void
+ImagingAccessInit(void);
+extern ImagingAccess
+ImagingAccessNew(Imaging im);
+extern void
+_ImagingAccessDelete(Imaging im, ImagingAccess access);
+#define ImagingAccessDelete(im, access) /* nop, for now */
+
+extern ImagingPalette
+ImagingPaletteNew(const char *mode);
+extern ImagingPalette
+ImagingPaletteNewBrowser(void);
+extern ImagingPalette
+ImagingPaletteDuplicate(ImagingPalette palette);
+extern void
+ImagingPaletteDelete(ImagingPalette palette);
+
+extern int
+ImagingPaletteCachePrepare(ImagingPalette palette);
+extern void
+ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b);
+extern void
+ImagingPaletteCacheDelete(ImagingPalette palette);
+
+#define ImagingPaletteCache(p, r, g, b) \
+ p->cache[(r >> 2) + (g >> 2) * 64 + (b >> 2) * 64 * 64]
+
+extern Imaging
+ImagingQuantize(Imaging im, int colours, int mode, int kmeans);
+
+/* Threading */
+/* --------- */
+
+typedef void *ImagingSectionCookie;
+
+extern void
+ImagingSectionEnter(ImagingSectionCookie *cookie);
+extern void
+ImagingSectionLeave(ImagingSectionCookie *cookie);
+
+/* Exceptions */
+/* ---------- */
+
+extern void *
+ImagingError_OSError(void);
+extern void *
+ImagingError_MemoryError(void);
+extern void *
+ImagingError_ModeError(void); /* maps to ValueError by default */
+extern void *
+ImagingError_Mismatch(void); /* maps to ValueError by default */
+extern void *
+ImagingError_ValueError(const char *message);
+extern void
+ImagingError_Clear(void);
+
+/* Transform callbacks */
+/* ------------------- */
+
+/* standard transforms */
+#define IMAGING_TRANSFORM_AFFINE 0
+#define IMAGING_TRANSFORM_PERSPECTIVE 2
+#define IMAGING_TRANSFORM_QUAD 3
+
+/* standard filters */
+#define IMAGING_TRANSFORM_NEAREST 0
+#define IMAGING_TRANSFORM_BOX 4
+#define IMAGING_TRANSFORM_BILINEAR 2
+#define IMAGING_TRANSFORM_HAMMING 5
+#define IMAGING_TRANSFORM_BICUBIC 3
+#define IMAGING_TRANSFORM_LANCZOS 1
+
+typedef int (*ImagingTransformMap)(double *X, double *Y, int x, int y, void *data);
+typedef int (*ImagingTransformFilter)(void *out, Imaging im, double x, double y);
+
+/* Image Manipulation Methods */
+/* -------------------------- */
+
+extern Imaging
+ImagingAlphaComposite(Imaging imIn1, Imaging imIn2);
+extern Imaging
+ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha);
+extern Imaging
+ImagingCopy(Imaging im);
+extern Imaging
+ImagingConvert(Imaging im, const char *mode, ImagingPalette palette, int dither);
+extern Imaging
+ImagingConvertInPlace(Imaging im, const char *mode);
+extern Imaging
+ImagingConvertMatrix(Imaging im, const char *mode, float m[]);
+extern Imaging
+ImagingConvertTransparent(Imaging im, const char *mode, int r, int g, int b);
+extern Imaging
+ImagingCrop(Imaging im, int x0, int y0, int x1, int y1);
+extern Imaging
+ImagingExpand(Imaging im, int x, int y);
+extern Imaging
+ImagingFill(Imaging im, const void *ink);
+extern int
+ImagingFill2(
+ Imaging into, const void *ink, Imaging mask, int x0, int y0, int x1, int y1);
+extern Imaging
+ImagingFillBand(Imaging im, int band, int color);
+extern Imaging
+ImagingFillLinearGradient(const char *mode);
+extern Imaging
+ImagingFillRadialGradient(const char *mode);
+extern Imaging
+ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32 *kernel, FLOAT32 offset);
+extern Imaging
+ImagingFlipLeftRight(Imaging imOut, Imaging imIn);
+extern Imaging
+ImagingFlipTopBottom(Imaging imOut, Imaging imIn);
+extern Imaging
+ImagingGaussianBlur(Imaging imOut, Imaging imIn, float xradius, float yradius, int passes);
+extern Imaging
+ImagingGetBand(Imaging im, int band);
+extern Imaging
+ImagingMerge(const char *mode, Imaging bands[4]);
+extern int
+ImagingSplit(Imaging im, Imaging bands[4]);
+extern int
+ImagingGetBBox(Imaging im, int bbox[4], int alpha_only);
+typedef struct {
+ int x, y;
+ INT32 count;
+ INT32 pixel;
+} ImagingColorItem;
+extern ImagingColorItem *
+ImagingGetColors(Imaging im, int maxcolors, int *colors);
+extern int
+ImagingGetExtrema(Imaging im, void *extrema);
+extern int
+ImagingGetProjection(Imaging im, UINT8 *xproj, UINT8 *yproj);
+extern ImagingHistogram
+ImagingGetHistogram(Imaging im, Imaging mask, void *extrema);
+extern Imaging
+ImagingModeFilter(Imaging im, int size);
+extern Imaging
+ImagingNegative(Imaging im);
+extern Imaging
+ImagingOffset(Imaging im, int xoffset, int yoffset);
+extern int
+ImagingPaste(Imaging into, Imaging im, Imaging mask, int x0, int y0, int x1, int y1);
+extern Imaging
+ImagingPoint(Imaging im, const char *tablemode, const void *table);
+extern Imaging
+ImagingPointTransform(Imaging imIn, double scale, double offset);
+extern Imaging
+ImagingPutBand(Imaging im, Imaging imIn, int band);
+extern Imaging
+ImagingRankFilter(Imaging im, int size, int rank);
+extern Imaging
+ImagingRotate90(Imaging imOut, Imaging imIn);
+extern Imaging
+ImagingRotate180(Imaging imOut, Imaging imIn);
+extern Imaging
+ImagingRotate270(Imaging imOut, Imaging imIn);
+extern Imaging
+ImagingTranspose(Imaging imOut, Imaging imIn);
+extern Imaging
+ImagingTransverse(Imaging imOut, Imaging imIn);
+extern Imaging
+ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]);
+extern Imaging
+ImagingReduce(Imaging imIn, int xscale, int yscale, int box[4]);
+extern Imaging
+ImagingTransform(
+ Imaging imOut,
+ Imaging imIn,
+ int method,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ double a[8],
+ int filter,
+ int fill);
+extern Imaging
+ImagingUnsharpMask(Imaging imOut, Imaging im, float radius, int percent, int threshold);
+extern Imaging
+ImagingBoxBlur(Imaging imOut, Imaging imIn, float xradius, float yradius, int n);
+extern Imaging
+ImagingColorLUT3D_linear(
+ Imaging imOut,
+ Imaging imIn,
+ int table_channels,
+ int size1D,
+ int size2D,
+ int size3D,
+ INT16 *table);
+
+extern Imaging
+ImagingCopy2(Imaging imOut, Imaging imIn);
+extern Imaging
+ImagingConvert2(Imaging imOut, Imaging imIn);
+
+/* Channel operations */
+/* any mode, except "F" */
+extern Imaging
+ImagingChopLighter(Imaging imIn1, Imaging imIn2);
+extern Imaging
+ImagingChopDarker(Imaging imIn1, Imaging imIn2);
+extern Imaging
+ImagingChopDifference(Imaging imIn1, Imaging imIn2);
+extern Imaging
+ImagingChopMultiply(Imaging imIn1, Imaging imIn2);
+extern Imaging
+ImagingChopScreen(Imaging imIn1, Imaging imIn2);
+extern Imaging
+ImagingChopAdd(Imaging imIn1, Imaging imIn2, float scale, int offset);
+extern Imaging
+ImagingChopSubtract(Imaging imIn1, Imaging imIn2, float scale, int offset);
+extern Imaging
+ImagingChopAddModulo(Imaging imIn1, Imaging imIn2);
+extern Imaging
+ImagingChopSubtractModulo(Imaging imIn1, Imaging imIn2);
+extern Imaging
+ImagingChopSoftLight(Imaging imIn1, Imaging imIn2);
+extern Imaging
+ImagingChopHardLight(Imaging imIn1, Imaging imIn2);
+extern Imaging
+ImagingOverlay(Imaging imIn1, Imaging imIn2);
+
+/* "1" images only */
+extern Imaging
+ImagingChopAnd(Imaging imIn1, Imaging imIn2);
+extern Imaging
+ImagingChopOr(Imaging imIn1, Imaging imIn2);
+extern Imaging
+ImagingChopXor(Imaging imIn1, Imaging imIn2);
+
+/* Graphics */
+extern int
+ImagingDrawArc(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ float start,
+ float end,
+ const void *ink,
+ int width,
+ int op);
+extern int
+ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap, const void *ink, int op);
+extern int
+ImagingDrawChord(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ float start,
+ float end,
+ const void *ink,
+ int fill,
+ int width,
+ int op);
+extern int
+ImagingDrawEllipse(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ const void *ink,
+ int fill,
+ int width,
+ int op);
+extern int
+ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void *ink, int op);
+extern int
+ImagingDrawWideLine(
+ Imaging im, int x0, int y0, int x1, int y1, const void *ink, int width, int op);
+extern int
+ImagingDrawPieslice(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ float start,
+ float end,
+ const void *ink,
+ int fill,
+ int width,
+ int op);
+extern int
+ImagingDrawPoint(Imaging im, int x, int y, const void *ink, int op);
+extern int
+ImagingDrawPolygon(Imaging im, int points, int *xy, const void *ink, int fill, int width, int op);
+extern int
+ImagingDrawRectangle(
+ Imaging im,
+ int x0,
+ int y0,
+ int x1,
+ int y1,
+ const void *ink,
+ int fill,
+ int width,
+ int op);
+
+/* Level 2 graphics (WORK IN PROGRESS) */
+extern ImagingOutline
+ImagingOutlineNew(void);
+extern void
+ImagingOutlineDelete(ImagingOutline outline);
+
+extern int
+ImagingDrawOutline(
+ Imaging im, ImagingOutline outline, const void *ink, int fill, int op);
+
+extern int
+ImagingOutlineMove(ImagingOutline outline, float x, float y);
+extern int
+ImagingOutlineLine(ImagingOutline outline, float x, float y);
+extern int
+ImagingOutlineCurve(
+ ImagingOutline outline, float x1, float y1, float x2, float y2, float x3, float y3);
+extern int
+ImagingOutlineTransform(ImagingOutline outline, double a[6]);
+
+extern int
+ImagingOutlineClose(ImagingOutline outline);
+
+/* Special effects */
+extern Imaging
+ImagingEffectSpread(Imaging imIn, int distance);
+extern Imaging
+ImagingEffectNoise(int xsize, int ysize, float sigma);
+extern Imaging
+ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality);
+
+/* File I/O */
+/* -------- */
+
+/* Built-in drivers */
+extern Imaging
+ImagingOpenPPM(const char *filename);
+extern int
+ImagingSavePPM(Imaging im, const char *filename);
+
+/* Codecs */
+typedef struct ImagingCodecStateInstance *ImagingCodecState;
+typedef int (*ImagingCodec)(
+ Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes);
+
+extern int
+ImagingBcnDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingBitDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingEpsEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes);
+extern int
+ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingGifEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes);
+extern int
+ImagingHexDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+#ifdef HAVE_LIBJPEG
+extern int
+ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingJpegDecodeCleanup(ImagingCodecState state);
+extern int
+ImagingJpegUseJCSExtensions(void);
+
+extern int
+ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes);
+#endif
+#ifdef HAVE_OPENJPEG
+extern int
+ImagingJpeg2KDecode(
+ Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingJpeg2KDecodeCleanup(ImagingCodecState state);
+extern int
+ImagingJpeg2KEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes);
+extern int
+ImagingJpeg2KEncodeCleanup(ImagingCodecState state);
+#endif
+#ifdef HAVE_LIBTIFF
+extern int
+ImagingLibTiffDecode(
+ Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes);
+#endif
+#ifdef HAVE_LIBMPEG
+extern int
+ImagingMpegDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+#endif
+extern int
+ImagingMspDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingPackbitsDecode(
+ Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingPcdDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes);
+extern int
+ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingRawEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes);
+extern int
+ImagingSgiRleDecode(
+ Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingSunRleDecode(
+ Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingTgaRleDecode(
+ Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingTgaRleEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes);
+extern int
+ImagingXbmDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingXbmEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes);
+#ifdef HAVE_LIBZ
+extern int
+ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes);
+extern int
+ImagingZipDecodeCleanup(ImagingCodecState state);
+extern int
+ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes);
+extern int
+ImagingZipEncodeCleanup(ImagingCodecState state);
+#endif
+
+typedef void (*ImagingShuffler)(UINT8 *out, const UINT8 *in, int pixels);
+
+/* Public shufflers */
+extern void
+ImagingPackBGR(UINT8 *out, const UINT8 *in, int pixels);
+extern void
+ImagingUnpackYCC(UINT8 *out, const UINT8 *in, int pixels);
+extern void
+ImagingUnpackYCCA(UINT8 *out, const UINT8 *in, int pixels);
+
+extern void
+ImagingConvertRGB2YCbCr(UINT8 *out, const UINT8 *in, int pixels);
+extern void
+ImagingConvertYCbCr2RGB(UINT8 *out, const UINT8 *in, int pixels);
+
+extern ImagingShuffler
+ImagingFindUnpacker(const char *mode, const char *rawmode, int *bits_out);
+extern ImagingShuffler
+ImagingFindPacker(const char *mode, const char *rawmode, int *bits_out);
+
+struct ImagingCodecStateInstance {
+ int count;
+ int state;
+ int errcode;
+ int x, y;
+ int ystep;
+ int xsize, ysize, xoff, yoff;
+ ImagingShuffler shuffle;
+ int bits, bytes;
+ UINT8 *buffer;
+ void *context;
+ PyObject *fd;
+};
+
+/* Codec read/write python fd */
+extern Py_ssize_t
+_imaging_read_pyFd(PyObject *fd, char *dest, Py_ssize_t bytes);
+extern Py_ssize_t
+_imaging_write_pyFd(PyObject *fd, char *src, Py_ssize_t bytes);
+extern int
+_imaging_seek_pyFd(PyObject *fd, Py_ssize_t offset, int whence);
+extern Py_ssize_t
+_imaging_tell_pyFd(PyObject *fd);
+
+/* Errcodes */
+#define IMAGING_CODEC_END 1
+#define IMAGING_CODEC_OVERRUN -1
+#define IMAGING_CODEC_BROKEN -2
+#define IMAGING_CODEC_UNKNOWN -3
+#define IMAGING_CODEC_CONFIG -8
+#define IMAGING_CODEC_MEMORY -9
+
+#include "ImagingUtils.h"
+extern UINT8 *clip8_lookups;
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/ImagingUtils.h b/contrib/python/Pillow/py3/libImaging/ImagingUtils.h
new file mode 100644
index 00000000000..0c0c1eda917
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/ImagingUtils.h
@@ -0,0 +1,42 @@
+#ifdef WORDS_BIGENDIAN
+#define MAKE_UINT32(u0, u1, u2, u3) \
+ ((UINT32)(u3) | ((UINT32)(u2) << 8) | ((UINT32)(u1) << 16) | ((UINT32)(u0) << 24))
+#define MASK_UINT32_CHANNEL_0 0xff000000
+#define MASK_UINT32_CHANNEL_1 0x00ff0000
+#define MASK_UINT32_CHANNEL_2 0x0000ff00
+#define MASK_UINT32_CHANNEL_3 0x000000ff
+#else
+#define MAKE_UINT32(u0, u1, u2, u3) \
+ ((UINT32)(u0) | ((UINT32)(u1) << 8) | ((UINT32)(u2) << 16) | ((UINT32)(u3) << 24))
+#define MASK_UINT32_CHANNEL_0 0x000000ff
+#define MASK_UINT32_CHANNEL_1 0x0000ff00
+#define MASK_UINT32_CHANNEL_2 0x00ff0000
+#define MASK_UINT32_CHANNEL_3 0xff000000
+#endif
+
+#define SHIFTFORDIV255(a) ((((a) >> 8) + a) >> 8)
+
+/* like (a * b + 127) / 255), but much faster on most platforms */
+#define MULDIV255(a, b, tmp) (tmp = (a) * (b) + 128, SHIFTFORDIV255(tmp))
+
+#define DIV255(a, tmp) (tmp = (a) + 128, SHIFTFORDIV255(tmp))
+
+#define BLEND(mask, in1, in2, tmp1) DIV255(in1 *(255 - mask) + in2 * mask, tmp1)
+
+#define PREBLEND(mask, in1, in2, tmp1) (MULDIV255(in1, (255 - mask), tmp1) + in2)
+
+#define CLIP8(v) ((v) <= 0 ? 0 : (v) < 256 ? (v) : 255)
+
+/* This is to work around a bug in GCC prior 4.9 in 64 bit mode.
+ GCC generates code with partial dependency which is 3 times slower.
+ See: https://stackoverflow.com/a/26588074/253146 */
+#if defined(__x86_64__) && defined(__SSE__) && !defined(__NO_INLINE__) && \
+ !defined(__clang__) && defined(GCC_VERSION) && (GCC_VERSION < 40900)
+static float __attribute__((always_inline)) inline _i2f(int v) {
+ float x;
+ __asm__("xorps %0, %0; cvtsi2ss %1, %0" : "=x"(x) : "r"(v));
+ return x;
+}
+#else
+static float inline _i2f(int v) { return (float)v; }
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/Jpeg.h b/contrib/python/Pillow/py3/libImaging/Jpeg.h
new file mode 100644
index 00000000000..1d755081871
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Jpeg.h
@@ -0,0 +1,116 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * declarations for the IJG JPEG codec interface.
+ *
+ * Copyright (c) 1995-2001 by Secret Labs AB
+ * Copyright (c) 1995-1996 by Fredrik Lundh
+ */
+
+#include "jpeglib.h"
+
+#include <setjmp.h>
+
+typedef struct {
+ struct jpeg_error_mgr pub; /* "public" fields */
+ jmp_buf setjmp_buffer; /* for return to caller */
+} JPEGERROR;
+
+/* -------------------------------------------------------------------- */
+/* Decoder */
+
+typedef struct {
+ struct jpeg_source_mgr pub;
+ int skip;
+} JPEGSOURCE;
+
+typedef struct {
+ /* CONFIGURATION */
+
+ /* Jpeg file mode (empty if not known) */
+ char jpegmode[8 + 1];
+
+ /* Converter output mode (input to the shuffler). If empty,
+ convert conversions are disabled */
+ char rawmode[8 + 1];
+
+ /* If set, trade quality for speed */
+ int draft;
+
+ /* Scale factor (1, 2, 4, 8) */
+ int scale;
+
+ /* PRIVATE CONTEXT (set by decoder) */
+
+ struct jpeg_decompress_struct cinfo;
+
+ JPEGERROR error;
+
+ JPEGSOURCE source;
+
+} JPEGSTATE;
+
+/* -------------------------------------------------------------------- */
+/* Encoder */
+
+typedef struct {
+ struct jpeg_destination_mgr pub;
+ /* might add something some other day */
+} JPEGDESTINATION;
+
+typedef struct {
+ /* CONFIGURATION */
+
+ /* Quality (0-100, -1 means default) */
+ int quality;
+
+ /* Progressive mode */
+ int progressive;
+
+ /* Smoothing factor (1-100, 0 means none) */
+ int smooth;
+
+ /* Optimize Huffman tables (slow) */
+ int optimize;
+
+ /* Stream type (0=full, 1=tables only, 2=image only) */
+ int streamtype;
+
+ /* DPI setting (0=square pixels, otherwise DPI) */
+ int xdpi, ydpi;
+
+ /* Chroma Subsampling (-1=default, 0=none, 1=medium, 2=high) */
+ int subsampling;
+
+ /* Converter input mode (input to the shuffler) */
+ char rawmode[8 + 1];
+
+ /* Custom quantization tables () */
+ unsigned int *qtables;
+
+ /* in factors of DCTSIZE2 */
+ int qtablesLen;
+
+ /* Comment */
+ char *comment;
+ size_t comment_size;
+
+ /* Extra data (to be injected after header) */
+ char *extra;
+ int extra_size;
+
+ /* PRIVATE CONTEXT (set by encoder) */
+
+ struct jpeg_compress_struct cinfo;
+
+ JPEGERROR error;
+
+ JPEGDESTINATION destination;
+
+ int extra_offset;
+
+ size_t rawExifLen; /* EXIF data length */
+ char *rawExif; /* EXIF buffer pointer */
+
+} JPEGENCODERSTATE;
diff --git a/contrib/python/Pillow/py3/libImaging/Jpeg2K.h b/contrib/python/Pillow/py3/libImaging/Jpeg2K.h
new file mode 100644
index 00000000000..e8d92f7b6bc
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Jpeg2K.h
@@ -0,0 +1,113 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * declarations for the OpenJPEG codec interface.
+ *
+ * Copyright (c) 2014 by Coriolis Systems Limited
+ * Copyright (c) 2014 by Alastair Houghton
+ */
+
+#include <openjpeg.h>
+
+/* 1MB for now */
+#define BUFFER_SIZE OPJ_J2K_STREAM_CHUNK_SIZE
+
+/* -------------------------------------------------------------------- */
+/* Decoder */
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+ /* CONFIGURATION */
+
+ /* File descriptor, if available; otherwise, -1 */
+ int fd;
+
+ /* File pointer, when opened */
+ FILE *pfile;
+
+ /* Length of data, if available; otherwise, -1 */
+ off_t length;
+
+ /* Specify the desired format */
+ OPJ_CODEC_FORMAT format;
+
+ /* Set to divide image resolution by 2**reduce. */
+ int reduce;
+
+ /* Set to limit the number of quality layers to decode (0 = all layers) */
+ int layers;
+
+ /* PRIVATE CONTEXT (set by decoder) */
+ const char *error_msg;
+
+} JPEG2KDECODESTATE;
+
+/* -------------------------------------------------------------------- */
+/* Encoder */
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+ /* CONFIGURATION */
+
+ /* File descriptor, if available; otherwise, -1 */
+ int fd;
+
+ /* File pointer, when opened */
+ FILE *pfile;
+
+ /* Specify the desired format */
+ OPJ_CODEC_FORMAT format;
+
+ /* Image offset */
+ int offset_x, offset_y;
+
+ /* Tile information */
+ int tile_offset_x, tile_offset_y;
+ int tile_size_x, tile_size_y;
+
+ /* Quality layers (a sequence of numbers giving *either* rates or dB) */
+ int quality_is_in_db;
+ PyObject *quality_layers;
+
+ /* Number of resolutions (DWT decompositions + 1 */
+ int num_resolutions;
+
+ /* Code block size */
+ int cblk_width, cblk_height;
+
+ /* Precinct size */
+ int precinct_width, precinct_height;
+
+ /* Compression style */
+ int irreversible;
+
+ /* Set multiple component transformation */
+ char mct;
+
+ /* Signed */
+ int sgnd;
+
+ /* Progression order (LRCP/RLCP/RPCL/PCRL/CPRL) */
+ OPJ_PROG_ORDER progression;
+
+ /* Cinema mode */
+ OPJ_CINEMA_MODE cinema_mode;
+
+ /* PRIVATE CONTEXT (set by decoder) */
+ const char *error_msg;
+
+ /* Custom comment */
+ char *comment;
+
+ /* Include PLT marker segment */
+ int plt;
+
+} JPEG2KENCODESTATE;
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * End:
+ *
+ */
diff --git a/contrib/python/Pillow/py3/libImaging/Jpeg2KDecode.c b/contrib/python/Pillow/py3/libImaging/Jpeg2KDecode.c
new file mode 100644
index 00000000000..cff30e2d0bf
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Jpeg2KDecode.c
@@ -0,0 +1,999 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for JPEG2000 image data.
+ *
+ * history:
+ * 2014-03-12 ajh Created
+ *
+ * Copyright (c) 2014 Coriolis Systems Limited
+ * Copyright (c) 2014 Alastair Houghton
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#ifdef HAVE_OPENJPEG
+
+#include <stdlib.h>
+#include "Jpeg2K.h"
+
+typedef struct {
+ OPJ_UINT32 tile_index;
+ OPJ_UINT32 data_size;
+ OPJ_INT32 x0, y0, x1, y1;
+ OPJ_UINT32 nb_comps;
+} JPEG2KTILEINFO;
+
+/* -------------------------------------------------------------------- */
+/* Error handler */
+/* -------------------------------------------------------------------- */
+
+static void
+j2k_error(const char *msg, void *client_data) {
+ JPEG2KDECODESTATE *state = (JPEG2KDECODESTATE *)client_data;
+ free((void *)state->error_msg);
+ state->error_msg = strdup(msg);
+}
+
+/* -------------------------------------------------------------------- */
+/* Buffer input stream */
+/* -------------------------------------------------------------------- */
+
+static OPJ_SIZE_T
+j2k_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) {
+ ImagingCodecState state = (ImagingCodecState)p_user_data;
+
+ size_t len = _imaging_read_pyFd(state->fd, p_buffer, p_nb_bytes);
+
+ return len ? len : (OPJ_SIZE_T)-1;
+}
+
+static OPJ_OFF_T
+j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data) {
+ off_t pos;
+ ImagingCodecState state = (ImagingCodecState)p_user_data;
+
+ _imaging_seek_pyFd(state->fd, p_nb_bytes, SEEK_CUR);
+ pos = _imaging_tell_pyFd(state->fd);
+
+ return pos ? pos : (OPJ_OFF_T)-1;
+}
+
+/* -------------------------------------------------------------------- */
+/* Unpackers */
+/* -------------------------------------------------------------------- */
+
+typedef void (*j2k_unpacker_t)(
+ opj_image_t *in, const JPEG2KTILEINFO *tileInfo, const UINT8 *data, Imaging im);
+
+struct j2k_decode_unpacker {
+ const char *mode;
+ OPJ_COLOR_SPACE color_space;
+ unsigned components;
+ /* bool indicating if unpacker supports subsampling */
+ int subsampling;
+ j2k_unpacker_t unpacker;
+};
+
+static inline unsigned
+j2ku_shift(unsigned x, int n) {
+ if (n < 0) {
+ return x >> -n;
+ } else {
+ return x << n;
+ }
+}
+
+static void
+j2ku_gray_l(
+ opj_image_t *in,
+ const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata,
+ Imaging im) {
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shift = 8 - in->comps[0].prec;
+ int offset = in->comps[0].sgnd ? 1 << (in->comps[0].prec - 1) : 0;
+ int csiz = (in->comps[0].prec + 7) >> 3;
+
+ unsigned x, y;
+
+ if (csiz == 3) {
+ csiz = 4;
+ }
+
+ if (shift < 0) {
+ offset += 1 << (-shift - 1);
+ }
+
+ /* csiz*h*w + offset = tileinfo.datasize */
+ switch (csiz) {
+ case 1:
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data = &tiledata[y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x) {
+ *row++ = j2ku_shift(offset + *data++, shift);
+ }
+ }
+ break;
+ case 2:
+ for (y = 0; y < h; ++y) {
+ const UINT16 *data = (const UINT16 *)&tiledata[2 * y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x) {
+ *row++ = j2ku_shift(offset + *data++, shift);
+ }
+ }
+ break;
+ case 4:
+ for (y = 0; y < h; ++y) {
+ const UINT32 *data = (const UINT32 *)&tiledata[4 * y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x) {
+ *row++ = j2ku_shift(offset + *data++, shift);
+ }
+ }
+ break;
+ }
+}
+
+static void
+j2ku_gray_i(
+ opj_image_t *in,
+ const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata,
+ Imaging im) {
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shift = 16 - in->comps[0].prec;
+ int offset = in->comps[0].sgnd ? 1 << (in->comps[0].prec - 1) : 0;
+ int csiz = (in->comps[0].prec + 7) >> 3;
+
+ unsigned x, y;
+
+ if (csiz == 3) {
+ csiz = 4;
+ }
+
+ if (shift < 0) {
+ offset += 1 << (-shift - 1);
+ }
+
+ switch (csiz) {
+ case 1:
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data = &tiledata[y * w];
+ UINT16 *row = (UINT16 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x) {
+ *row++ = j2ku_shift(offset + *data++, shift);
+ }
+ }
+ break;
+ case 2:
+ for (y = 0; y < h; ++y) {
+ const UINT16 *data = (const UINT16 *)&tiledata[2 * y * w];
+ UINT16 *row = (UINT16 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x) {
+ UINT16 pixel = j2ku_shift(offset + *data++, shift);
+ #ifdef WORDS_BIGENDIAN
+ pixel = (pixel >> 8) | (pixel << 8);
+ #endif
+ *row++ = pixel;
+ }
+ }
+ break;
+ case 4:
+ for (y = 0; y < h; ++y) {
+ const UINT32 *data = (const UINT32 *)&tiledata[4 * y * w];
+ UINT16 *row = (UINT16 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x) {
+ *row++ = j2ku_shift(offset + *data++, shift);
+ }
+ }
+ break;
+ }
+}
+
+static void
+j2ku_gray_rgb(
+ opj_image_t *in,
+ const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata,
+ Imaging im) {
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shift = 8 - in->comps[0].prec;
+ int offset = in->comps[0].sgnd ? 1 << (in->comps[0].prec - 1) : 0;
+ int csiz = (in->comps[0].prec + 7) >> 3;
+
+ unsigned x, y;
+
+ if (shift < 0) {
+ offset += 1 << (-shift - 1);
+ }
+
+ if (csiz == 3) {
+ csiz = 4;
+ }
+
+ switch (csiz) {
+ case 1:
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data = &tiledata[y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x) {
+ UINT8 byte = j2ku_shift(offset + *data++, shift);
+ row[0] = row[1] = row[2] = byte;
+ row[3] = 0xff;
+ row += 4;
+ }
+ }
+ break;
+ case 2:
+ for (y = 0; y < h; ++y) {
+ const UINT16 *data = (UINT16 *)&tiledata[2 * y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x) {
+ UINT8 byte = j2ku_shift(offset + *data++, shift);
+ row[0] = row[1] = row[2] = byte;
+ row[3] = 0xff;
+ row += 4;
+ }
+ }
+ break;
+ case 4:
+ for (y = 0; y < h; ++y) {
+ const UINT32 *data = (UINT32 *)&tiledata[4 * y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0;
+ for (x = 0; x < w; ++x) {
+ UINT8 byte = j2ku_shift(offset + *data++, shift);
+ row[0] = row[1] = row[2] = byte;
+ row[3] = 0xff;
+ row += 4;
+ }
+ }
+ break;
+ }
+}
+
+static void
+j2ku_graya_la(
+ opj_image_t *in,
+ const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata,
+ Imaging im) {
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shift = 8 - in->comps[0].prec;
+ int offset = in->comps[0].sgnd ? 1 << (in->comps[0].prec - 1) : 0;
+ int csiz = (in->comps[0].prec + 7) >> 3;
+ int ashift = 8 - in->comps[1].prec;
+ int aoffset = in->comps[1].sgnd ? 1 << (in->comps[1].prec - 1) : 0;
+ int acsiz = (in->comps[1].prec + 7) >> 3;
+ const UINT8 *atiledata;
+
+ unsigned x, y;
+
+ if (csiz == 3) {
+ csiz = 4;
+ }
+ if (acsiz == 3) {
+ acsiz = 4;
+ }
+
+ if (shift < 0) {
+ offset += 1 << (-shift - 1);
+ }
+ if (ashift < 0) {
+ aoffset += 1 << (-ashift - 1);
+ }
+
+ atiledata = tiledata + csiz * w * h;
+
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data = &tiledata[csiz * y * w];
+ const UINT8 *adata = &atiledata[acsiz * y * w];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
+ for (x = 0; x < w; ++x) {
+ UINT32 word = 0, aword = 0, byte;
+
+ switch (csiz) {
+ case 1:
+ word = *data++;
+ break;
+ case 2:
+ word = *(const UINT16 *)data;
+ data += 2;
+ break;
+ case 4:
+ word = *(const UINT32 *)data;
+ data += 4;
+ break;
+ }
+
+ switch (acsiz) {
+ case 1:
+ aword = *adata++;
+ break;
+ case 2:
+ aword = *(const UINT16 *)adata;
+ adata += 2;
+ break;
+ case 4:
+ aword = *(const UINT32 *)adata;
+ adata += 4;
+ break;
+ }
+
+ byte = j2ku_shift(offset + word, shift);
+ row[0] = row[1] = row[2] = byte;
+ row[3] = j2ku_shift(aoffset + aword, ashift);
+ row += 4;
+ }
+ }
+}
+
+static void
+j2ku_srgb_rgb(
+ opj_image_t *in,
+ const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata,
+ Imaging im) {
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shifts[3], offsets[3], csiz[3];
+ unsigned dx[3], dy[3];
+ const UINT8 *cdata[3];
+ const UINT8 *cptr = tiledata;
+ unsigned n, x, y;
+
+ for (n = 0; n < 3; ++n) {
+ cdata[n] = cptr;
+ shifts[n] = 8 - in->comps[n].prec;
+ offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0;
+ csiz[n] = (in->comps[n].prec + 7) >> 3;
+ dx[n] = (in->comps[n].dx);
+ dy[n] = (in->comps[n].dy);
+
+ if (csiz[n] == 3) {
+ csiz[n] = 4;
+ }
+
+ if (shifts[n] < 0) {
+ offsets[n] += 1 << (-shifts[n] - 1);
+ }
+
+ cptr += csiz[n] * (w / dx[n]) * (h / dy[n]);
+ }
+
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data[3];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
+ for (n = 0; n < 3; ++n) {
+ data[n] = &cdata[n][csiz[n] * (y / dy[n]) * (w / dx[n])];
+ }
+
+ for (x = 0; x < w; ++x) {
+ for (n = 0; n < 3; ++n) {
+ UINT32 word = 0;
+
+ switch (csiz[n]) {
+ case 1:
+ word = data[n][x / dx[n]];
+ break;
+ case 2:
+ word = ((const UINT16 *)data[n])[x / dx[n]];
+ break;
+ case 4:
+ word = ((const UINT32 *)data[n])[x / dx[n]];
+ break;
+ }
+
+ row[n] = j2ku_shift(offsets[n] + word, shifts[n]);
+ }
+ row[3] = 0xff;
+ row += 4;
+ }
+ }
+}
+
+static void
+j2ku_sycc_rgb(
+ opj_image_t *in,
+ const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata,
+ Imaging im) {
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shifts[3], offsets[3], csiz[3];
+ unsigned dx[3], dy[3];
+ const UINT8 *cdata[3];
+ const UINT8 *cptr = tiledata;
+ unsigned n, x, y;
+
+ for (n = 0; n < 3; ++n) {
+ cdata[n] = cptr;
+ shifts[n] = 8 - in->comps[n].prec;
+ offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0;
+ csiz[n] = (in->comps[n].prec + 7) >> 3;
+ dx[n] = (in->comps[n].dx);
+ dy[n] = (in->comps[n].dy);
+
+ if (csiz[n] == 3) {
+ csiz[n] = 4;
+ }
+
+ if (shifts[n] < 0) {
+ offsets[n] += 1 << (-shifts[n] - 1);
+ }
+
+ cptr += csiz[n] * (w / dx[n]) * (h / dy[n]);
+ }
+
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data[3];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
+ UINT8 *row_start = row;
+ for (n = 0; n < 3; ++n) {
+ data[n] = &cdata[n][csiz[n] * (y / dy[n]) * (w / dx[n])];
+ }
+
+ for (x = 0; x < w; ++x) {
+ for (n = 0; n < 3; ++n) {
+ UINT32 word = 0;
+
+ switch (csiz[n]) {
+ case 1:
+ word = data[n][x / dx[n]];
+ break;
+ case 2:
+ word = ((const UINT16 *)data[n])[x / dx[n]];
+ break;
+ case 4:
+ word = ((const UINT32 *)data[n])[x / dx[n]];
+ break;
+ }
+
+ row[n] = j2ku_shift(offsets[n] + word, shifts[n]);
+ }
+ row[3] = 0xff;
+ row += 4;
+ }
+
+ ImagingConvertYCbCr2RGB(row_start, row_start, w);
+ }
+}
+
+static void
+j2ku_srgba_rgba(
+ opj_image_t *in,
+ const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata,
+ Imaging im) {
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shifts[4], offsets[4], csiz[4];
+ unsigned dx[4], dy[4];
+ const UINT8 *cdata[4];
+ const UINT8 *cptr = tiledata;
+ unsigned n, x, y;
+
+ for (n = 0; n < 4; ++n) {
+ cdata[n] = cptr;
+ shifts[n] = 8 - in->comps[n].prec;
+ offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0;
+ csiz[n] = (in->comps[n].prec + 7) >> 3;
+ dx[n] = (in->comps[n].dx);
+ dy[n] = (in->comps[n].dy);
+
+ if (csiz[n] == 3) {
+ csiz[n] = 4;
+ }
+
+ if (shifts[n] < 0) {
+ offsets[n] += 1 << (-shifts[n] - 1);
+ }
+
+ cptr += csiz[n] * (w / dx[n]) * (h / dy[n]);
+ }
+
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data[4];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
+ for (n = 0; n < 4; ++n) {
+ data[n] = &cdata[n][csiz[n] * (y / dy[n]) * (w / dx[n])];
+ }
+
+ for (x = 0; x < w; ++x) {
+ for (n = 0; n < 4; ++n) {
+ UINT32 word = 0;
+
+ switch (csiz[n]) {
+ case 1:
+ word = data[n][x / dx[n]];
+ break;
+ case 2:
+ word = ((const UINT16 *)data[n])[x / dx[n]];
+ break;
+ case 4:
+ word = ((const UINT32 *)data[n])[x / dx[n]];
+ break;
+ }
+
+ row[n] = j2ku_shift(offsets[n] + word, shifts[n]);
+ }
+ row += 4;
+ }
+ }
+}
+
+static void
+j2ku_sycca_rgba(
+ opj_image_t *in,
+ const JPEG2KTILEINFO *tileinfo,
+ const UINT8 *tiledata,
+ Imaging im) {
+ unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0;
+ unsigned w = tileinfo->x1 - tileinfo->x0;
+ unsigned h = tileinfo->y1 - tileinfo->y0;
+
+ int shifts[4], offsets[4], csiz[4];
+ unsigned dx[4], dy[4];
+ const UINT8 *cdata[4];
+ const UINT8 *cptr = tiledata;
+ unsigned n, x, y;
+
+ for (n = 0; n < 4; ++n) {
+ cdata[n] = cptr;
+ shifts[n] = 8 - in->comps[n].prec;
+ offsets[n] = in->comps[n].sgnd ? 1 << (in->comps[n].prec - 1) : 0;
+ csiz[n] = (in->comps[n].prec + 7) >> 3;
+ dx[n] = (in->comps[n].dx);
+ dy[n] = (in->comps[n].dy);
+
+ if (csiz[n] == 3) {
+ csiz[n] = 4;
+ }
+
+ if (shifts[n] < 0) {
+ offsets[n] += 1 << (-shifts[n] - 1);
+ }
+
+ cptr += csiz[n] * (w / dx[n]) * (h / dy[n]);
+ }
+
+ for (y = 0; y < h; ++y) {
+ const UINT8 *data[4];
+ UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4;
+ UINT8 *row_start = row;
+ for (n = 0; n < 4; ++n) {
+ data[n] = &cdata[n][csiz[n] * (y / dy[n]) * (w / dx[n])];
+ }
+
+ for (x = 0; x < w; ++x) {
+ for (n = 0; n < 4; ++n) {
+ UINT32 word = 0;
+
+ switch (csiz[n]) {
+ case 1:
+ word = data[n][x / dx[n]];
+ break;
+ case 2:
+ word = ((const UINT16 *)data[n])[x / dx[n]];
+ break;
+ case 4:
+ word = ((const UINT32 *)data[n])[x / dx[n]];
+ break;
+ }
+
+ row[n] = j2ku_shift(offsets[n] + word, shifts[n]);
+ }
+ row += 4;
+ }
+
+ ImagingConvertYCbCr2RGB(row_start, row_start, w);
+ }
+}
+
+static const struct j2k_decode_unpacker j2k_unpackers[] = {
+ {"L", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_l},
+ {"I;16", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_i},
+ {"I;16B", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_i},
+ {"LA", OPJ_CLRSPC_GRAY, 2, 0, j2ku_graya_la},
+ {"RGB", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_rgb},
+ {"RGB", OPJ_CLRSPC_GRAY, 2, 0, j2ku_gray_rgb},
+ {"RGB", OPJ_CLRSPC_SRGB, 3, 1, j2ku_srgb_rgb},
+ {"RGB", OPJ_CLRSPC_SYCC, 3, 1, j2ku_sycc_rgb},
+ {"RGB", OPJ_CLRSPC_SRGB, 4, 1, j2ku_srgb_rgb},
+ {"RGB", OPJ_CLRSPC_SYCC, 4, 1, j2ku_sycc_rgb},
+ {"RGBA", OPJ_CLRSPC_GRAY, 1, 0, j2ku_gray_rgb},
+ {"RGBA", OPJ_CLRSPC_GRAY, 2, 0, j2ku_graya_la},
+ {"RGBA", OPJ_CLRSPC_SRGB, 3, 1, j2ku_srgb_rgb},
+ {"RGBA", OPJ_CLRSPC_SYCC, 3, 1, j2ku_sycc_rgb},
+ {"RGBA", OPJ_CLRSPC_SRGB, 4, 1, j2ku_srgba_rgba},
+ {"RGBA", OPJ_CLRSPC_SYCC, 4, 1, j2ku_sycca_rgba},
+};
+
+/* -------------------------------------------------------------------- */
+/* Decoder */
+/* -------------------------------------------------------------------- */
+
+enum {
+ J2K_STATE_START = 0,
+ J2K_STATE_DECODING = 1,
+ J2K_STATE_DONE = 2,
+ J2K_STATE_FAILED = 3,
+};
+
+static int
+j2k_decode_entry(Imaging im, ImagingCodecState state) {
+ JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *)state->context;
+ opj_stream_t *stream = NULL;
+ opj_image_t *image = NULL;
+ opj_codec_t *codec = NULL;
+ opj_dparameters_t params;
+ OPJ_COLOR_SPACE color_space;
+ j2k_unpacker_t unpack = NULL;
+ size_t buffer_size = 0, tile_bytes = 0;
+ unsigned n, tile_height, tile_width;
+ int subsampling;
+ int total_component_width = 0;
+
+ stream = opj_stream_create(BUFFER_SIZE, OPJ_TRUE);
+
+ if (!stream) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ opj_stream_set_read_function(stream, j2k_read);
+ opj_stream_set_skip_function(stream, j2k_skip);
+
+ /* OpenJPEG 2.0 doesn't have OPJ_VERSION_MAJOR */
+#ifndef OPJ_VERSION_MAJOR
+ opj_stream_set_user_data(stream, state);
+#else
+ opj_stream_set_user_data(stream, state, NULL);
+
+ /* Hack: if we don't know the length, the largest file we can
+ possibly support is 4GB. We can't go larger than this, because
+ OpenJPEG truncates this value for the final box in the file, and
+ the box lengths in OpenJPEG are currently 32 bit. */
+ if (context->length < 0) {
+ opj_stream_set_user_data_length(stream, 0xffffffff);
+ } else {
+ opj_stream_set_user_data_length(stream, context->length);
+ }
+#endif
+
+ /* Setup decompression context */
+ context->error_msg = NULL;
+
+ opj_set_default_decoder_parameters(&params);
+ params.cp_reduce = context->reduce;
+ params.cp_layer = context->layers;
+
+ codec = opj_create_decompress(context->format);
+
+ if (!codec) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ opj_set_error_handler(codec, j2k_error, context);
+ opj_setup_decoder(codec, &params);
+
+ if (!opj_read_header(stream, codec, &image)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ /* Check that this image is something we can handle */
+ if (image->numcomps < 1 || image->numcomps > 4 ||
+ image->color_space == OPJ_CLRSPC_UNKNOWN) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ /*
+ * Find first component with subsampling.
+ *
+ * This is a heuristic to determine the colorspace if unspecified.
+ */
+ subsampling = -1;
+ for (n = 0; n < image->numcomps; ++n) {
+ if (image->comps[n].dx != 1 || image->comps[n].dy != 1) {
+ subsampling = n;
+ break;
+ }
+ }
+
+ /*
+ Colorspace Number of components PIL mode
+ ------------------------------------------------------
+ sRGB 3 RGB
+ sRGB 4 RGBA
+ gray 1 L or I
+ gray 2 LA
+ YCC 3 YCbCr
+
+
+ If colorspace is unspecified, we assume:
+
+ Number of components Subsampling Colorspace
+ -------------------------------------------------------
+ 1 Any gray
+ 2 Any gray (+ alpha)
+ 3 -1, 0 sRGB
+ 3 1, 2 YCbCr
+ 4 -1, 0, 3 sRGB (+ alpha)
+ 4 1, 2 YCbCr (+ alpha)
+
+ */
+
+ /* Find the correct unpacker */
+ color_space = image->color_space;
+
+ if (color_space == OPJ_CLRSPC_UNSPECIFIED) {
+ switch (image->numcomps) {
+ case 1:
+ case 2:
+ color_space = OPJ_CLRSPC_GRAY;
+ break;
+ case 3:
+ case 4:
+ switch (subsampling) {
+ case -1:
+ case 0:
+ case 3:
+ color_space = OPJ_CLRSPC_SRGB;
+ break;
+ case 1:
+ case 2:
+ color_space = OPJ_CLRSPC_SYCC;
+ break;
+ }
+ break;
+ }
+ }
+
+ for (n = 0; n < sizeof(j2k_unpackers) / sizeof(j2k_unpackers[0]); ++n) {
+ if (color_space == j2k_unpackers[n].color_space &&
+ image->numcomps == j2k_unpackers[n].components &&
+ (j2k_unpackers[n].subsampling || (subsampling == -1)) &&
+ strcmp(im->mode, j2k_unpackers[n].mode) == 0) {
+ unpack = j2k_unpackers[n].unpacker;
+ break;
+ }
+ }
+
+ if (!unpack) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ /* Decode the image tile-by-tile; this means we only need use as much
+ memory as is required for one tile's worth of components. */
+ for (;;) {
+ JPEG2KTILEINFO tile_info;
+ OPJ_BOOL should_continue;
+ unsigned correction = (1 << params.cp_reduce) - 1;
+
+ if (!opj_read_tile_header(
+ codec,
+ stream,
+ &tile_info.tile_index,
+ &tile_info.data_size,
+ &tile_info.x0,
+ &tile_info.y0,
+ &tile_info.x1,
+ &tile_info.y1,
+ &tile_info.nb_comps,
+ &should_continue)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ if (!should_continue) {
+ break;
+ }
+
+ /* Adjust the tile co-ordinates based on the reduction (OpenJPEG
+ doesn't do this for us) */
+ tile_info.x0 = (tile_info.x0 + correction) >> context->reduce;
+ tile_info.y0 = (tile_info.y0 + correction) >> context->reduce;
+ tile_info.x1 = (tile_info.x1 + correction) >> context->reduce;
+ tile_info.y1 = (tile_info.y1 + correction) >> context->reduce;
+
+ /* Check the tile bounds; if the tile is outside the image area,
+ or if it has a negative width or height (i.e. the coordinates are
+ swapped), bail. */
+ if (tile_info.x0 >= tile_info.x1 || tile_info.y0 >= tile_info.y1 ||
+ tile_info.x0 < 0 || tile_info.y0 < 0 ||
+ (OPJ_UINT32)tile_info.x0 < image->x0 ||
+ (OPJ_UINT32)tile_info.y0 < image->y0 ||
+ (OPJ_INT32)(tile_info.x1 - image->x0) > im->xsize ||
+ (OPJ_INT32)(tile_info.y1 - image->y0) > im->ysize) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ if (tile_info.nb_comps != image->numcomps) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ /* Sometimes the tile_info.datasize we get back from openjpeg
+ is less than sum(comp_bytes)*w*h, and we overflow in the
+ shuffle stage */
+
+ tile_width = tile_info.x1 - tile_info.x0;
+ tile_height = tile_info.y1 - tile_info.y0;
+
+ /* Total component width = sum (component_width) e.g, it's
+ legal for an la file to have a 1 byte width for l, and 4 for
+ a, and then a malicious file could have a smaller tile_bytes
+ */
+
+ for (n=0; n < tile_info.nb_comps; n++) {
+ // see csize /acsize calcs
+ int csize = (image->comps[n].prec + 7) >> 3;
+ csize = (csize == 3) ? 4 : csize;
+ total_component_width += csize;
+ }
+ if ((tile_width > UINT_MAX / total_component_width) ||
+ (tile_height > UINT_MAX / total_component_width) ||
+ (tile_width > UINT_MAX / (tile_height * total_component_width)) ||
+ (tile_height > UINT_MAX / (tile_width * total_component_width))) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ tile_bytes = tile_width * tile_height * total_component_width;
+
+ if (tile_bytes > tile_info.data_size) {
+ tile_info.data_size = tile_bytes;
+ }
+
+ if (buffer_size < tile_info.data_size) {
+ /* malloc check ok, overflow and tile size sanity check above */
+ UINT8 *new = realloc(state->buffer, tile_info.data_size);
+ if (!new) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+ /* Undefined behavior, sometimes decode_tile_data doesn't
+ fill the buffer and we do things with it later, leading
+ to valgrind errors. */
+ memset(new, 0, tile_info.data_size);
+ state->buffer = new;
+ buffer_size = tile_info.data_size;
+ }
+
+ if (!opj_decode_tile_data(
+ codec,
+ tile_info.tile_index,
+ (OPJ_BYTE *)state->buffer,
+ tile_info.data_size,
+ stream)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ unpack(image, &tile_info, state->buffer, im);
+ }
+
+ if (!opj_end_decompress(codec, stream)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ state->state = J2K_STATE_DONE;
+ state->errcode = IMAGING_CODEC_END;
+
+ if (context->pfile) {
+ if (fclose(context->pfile)) {
+ context->pfile = NULL;
+ }
+ }
+
+quick_exit:
+ if (codec) {
+ opj_destroy_codec(codec);
+ }
+ if (image) {
+ opj_image_destroy(image);
+ }
+ if (stream) {
+ opj_stream_destroy(stream);
+ }
+
+ return -1;
+}
+
+int
+ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ if (bytes) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ return -1;
+ }
+
+ if (state->state == J2K_STATE_DONE || state->state == J2K_STATE_FAILED) {
+ return -1;
+ }
+
+ if (state->state == J2K_STATE_START) {
+ state->state = J2K_STATE_DECODING;
+
+ return j2k_decode_entry(im, state);
+ }
+
+ if (state->state == J2K_STATE_DECODING) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ return -1;
+ }
+ return -1;
+}
+
+/* -------------------------------------------------------------------- */
+/* Cleanup */
+/* -------------------------------------------------------------------- */
+
+int
+ImagingJpeg2KDecodeCleanup(ImagingCodecState state) {
+ JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *)state->context;
+
+ if (context->error_msg) {
+ free((void *)context->error_msg);
+ }
+
+ context->error_msg = NULL;
+
+ return -1;
+}
+
+const char *
+ImagingJpeg2KVersion(void) {
+ return opj_version();
+}
+
+#endif /* HAVE_OPENJPEG */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * End:
+ *
+ */
diff --git a/contrib/python/Pillow/py3/libImaging/Jpeg2KEncode.c b/contrib/python/Pillow/py3/libImaging/Jpeg2KEncode.c
new file mode 100644
index 00000000000..3295373fd64
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Jpeg2KEncode.c
@@ -0,0 +1,659 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for JPEG2000 image data.
+ *
+ * history:
+ * 2014-03-12 ajh Created
+ *
+ * Copyright (c) 2014 Coriolis Systems Limited
+ * Copyright (c) 2014 Alastair Houghton
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#ifdef HAVE_OPENJPEG
+
+#include "Jpeg2K.h"
+
+#define CINEMA_24_CS_LENGTH 1302083
+#define CINEMA_48_CS_LENGTH 651041
+#define COMP_24_CS_MAX_LENGTH 1041666
+#define COMP_48_CS_MAX_LENGTH 520833
+
+/* -------------------------------------------------------------------- */
+/* Error handler */
+/* -------------------------------------------------------------------- */
+
+static void
+j2k_error(const char *msg, void *client_data) {
+ JPEG2KENCODESTATE *state = (JPEG2KENCODESTATE *)client_data;
+ free((void *)state->error_msg);
+ state->error_msg = strdup(msg);
+}
+
+static void
+j2k_warn(const char *msg, void *client_data) {
+ // Null handler
+}
+
+/* -------------------------------------------------------------------- */
+/* Buffer output stream */
+/* -------------------------------------------------------------------- */
+
+static OPJ_SIZE_T
+j2k_write(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) {
+ ImagingCodecState state = (ImagingCodecState)p_user_data;
+ unsigned int result;
+
+ result = _imaging_write_pyFd(state->fd, p_buffer, p_nb_bytes);
+
+ return result ? result : (OPJ_SIZE_T)-1;
+}
+
+static OPJ_OFF_T
+j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data) {
+ ImagingCodecState state = (ImagingCodecState)p_user_data;
+ char *buffer;
+ int result;
+
+ /* Explicitly write zeros */
+ buffer = calloc(p_nb_bytes, 1);
+ if (!buffer) {
+ return (OPJ_OFF_T)-1;
+ }
+
+ result = _imaging_write_pyFd(state->fd, buffer, p_nb_bytes);
+
+ free(buffer);
+
+ return result ? result : p_nb_bytes;
+}
+
+static OPJ_BOOL
+j2k_seek(OPJ_OFF_T p_nb_bytes, void *p_user_data) {
+ ImagingCodecState state = (ImagingCodecState)p_user_data;
+ off_t pos = 0;
+
+ _imaging_seek_pyFd(state->fd, p_nb_bytes, SEEK_SET);
+ pos = _imaging_tell_pyFd(state->fd);
+
+ return pos == p_nb_bytes;
+}
+
+/* -------------------------------------------------------------------- */
+/* Encoder */
+/* -------------------------------------------------------------------- */
+
+typedef void (*j2k_pack_tile_t)(
+ Imaging im, UINT8 *buf, unsigned x0, unsigned y0, unsigned w, unsigned h);
+
+static void
+j2k_pack_l(Imaging im, UINT8 *buf, unsigned x0, unsigned y0, unsigned w, unsigned h) {
+ UINT8 *ptr = buf;
+ unsigned x, y;
+ for (y = 0; y < h; ++y) {
+ UINT8 *data = (UINT8 *)(im->image[y + y0] + x0);
+ for (x = 0; x < w; ++x) {
+ *ptr++ = *data++;
+ }
+ }
+}
+
+static void
+j2k_pack_i16(Imaging im, UINT8 *buf, unsigned x0, unsigned y0, unsigned w, unsigned h) {
+ UINT8 *ptr = buf;
+ unsigned x, y;
+ for (y = 0; y < h; ++y) {
+ UINT8 *data = (UINT8 *)(im->image[y + y0] + x0);
+ for (x = 0; x < w; ++x) {
+#ifdef WORDS_BIGENDIAN
+ ptr[0] = data[1];
+ ptr[1] = data[0];
+#else
+ ptr[0] = data[0];
+ ptr[1] = data[1];
+#endif
+ ptr += 2;
+ data += 2;
+ }
+ }
+}
+
+static void
+j2k_pack_la(Imaging im, UINT8 *buf, unsigned x0, unsigned y0, unsigned w, unsigned h) {
+ UINT8 *ptr = buf;
+ UINT8 *ptra = buf + w * h;
+ unsigned x, y;
+ for (y = 0; y < h; ++y) {
+ UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0);
+ for (x = 0; x < w; ++x) {
+ *ptr++ = data[0];
+ *ptra++ = data[3];
+ data += 4;
+ }
+ }
+}
+
+static void
+j2k_pack_rgb(Imaging im, UINT8 *buf, unsigned x0, unsigned y0, unsigned w, unsigned h) {
+ UINT8 *pr = buf;
+ UINT8 *pg = pr + w * h;
+ UINT8 *pb = pg + w * h;
+ unsigned x, y;
+ for (y = 0; y < h; ++y) {
+ UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0);
+ for (x = 0; x < w; ++x) {
+ *pr++ = data[0];
+ *pg++ = data[1];
+ *pb++ = data[2];
+ data += 4;
+ }
+ }
+}
+
+static void
+j2k_pack_rgba(
+ Imaging im, UINT8 *buf, unsigned x0, unsigned y0, unsigned w, unsigned h) {
+ UINT8 *pr = buf;
+ UINT8 *pg = pr + w * h;
+ UINT8 *pb = pg + w * h;
+ UINT8 *pa = pb + w * h;
+ unsigned x, y;
+ for (y = 0; y < h; ++y) {
+ UINT8 *data = (UINT8 *)(im->image[y + y0] + 4 * x0);
+ for (x = 0; x < w; ++x) {
+ *pr++ = *data++;
+ *pg++ = *data++;
+ *pb++ = *data++;
+ *pa++ = *data++;
+ }
+ }
+}
+
+enum {
+ J2K_STATE_START = 0,
+ J2K_STATE_ENCODING = 1,
+ J2K_STATE_DONE = 2,
+ J2K_STATE_FAILED = 3,
+};
+
+static void
+j2k_set_cinema_params(Imaging im, int components, opj_cparameters_t *params) {
+ float rate;
+ int n;
+
+ /* These settings have been copied from opj_compress in the OpenJPEG
+ sources. */
+
+ params->tile_size_on = OPJ_FALSE;
+ params->cp_tdx = params->cp_tdy = 1;
+ params->tp_flag = 'C';
+ params->tp_on = 1;
+ params->cp_tx0 = params->cp_ty0 = 0;
+ params->image_offset_x0 = params->image_offset_y0 = 0;
+ params->cblockw_init = 32;
+ params->cblockh_init = 32;
+ params->csty |= 0x01;
+ params->prog_order = OPJ_CPRL;
+ params->roi_compno = -1;
+ params->subsampling_dx = params->subsampling_dy = 1;
+ params->irreversible = 1;
+
+ if (params->cp_cinema == OPJ_CINEMA4K_24) {
+ float max_rate =
+ ((float)(components * im->xsize * im->ysize * 8) /
+ (CINEMA_24_CS_LENGTH * 8));
+
+ params->POC[0].tile = 1;
+ params->POC[0].resno0 = 0;
+ params->POC[0].compno0 = 0;
+ params->POC[0].layno1 = 1;
+ params->POC[0].resno1 = params->numresolution - 1;
+ params->POC[0].compno1 = 3;
+ params->POC[0].prg1 = OPJ_CPRL;
+ params->POC[1].tile = 1;
+ params->POC[1].resno0 = 0;
+ params->POC[1].compno0 = 0;
+ params->POC[1].layno1 = 1;
+ params->POC[1].resno1 = params->numresolution - 1;
+ params->POC[1].compno1 = 3;
+ params->POC[1].prg1 = OPJ_CPRL;
+ params->numpocs = 2;
+
+ for (n = 0; n < params->tcp_numlayers; ++n) {
+ rate = 0;
+ if (params->tcp_rates[0] == 0) {
+ params->tcp_rates[n] = max_rate;
+ } else {
+ rate =
+ ((float)(components * im->xsize * im->ysize * 8) /
+ (params->tcp_rates[n] * 8));
+ if (rate > CINEMA_24_CS_LENGTH) {
+ params->tcp_rates[n] = max_rate;
+ }
+ }
+ }
+
+ params->max_comp_size = COMP_24_CS_MAX_LENGTH;
+ } else {
+ float max_rate =
+ ((float)(components * im->xsize * im->ysize * 8) /
+ (CINEMA_48_CS_LENGTH * 8));
+
+ for (n = 0; n < params->tcp_numlayers; ++n) {
+ rate = 0;
+ if (params->tcp_rates[0] == 0) {
+ params->tcp_rates[n] = max_rate;
+ } else {
+ rate =
+ ((float)(components * im->xsize * im->ysize * 8) /
+ (params->tcp_rates[n] * 8));
+ if (rate > CINEMA_48_CS_LENGTH) {
+ params->tcp_rates[n] = max_rate;
+ }
+ }
+ }
+
+ params->max_comp_size = COMP_48_CS_MAX_LENGTH;
+ }
+}
+
+static int
+j2k_encode_entry(Imaging im, ImagingCodecState state) {
+ JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
+ opj_stream_t *stream = NULL;
+ opj_image_t *image = NULL;
+ opj_codec_t *codec = NULL;
+ opj_cparameters_t params;
+ unsigned components;
+ OPJ_COLOR_SPACE color_space;
+ opj_image_cmptparm_t image_params[4];
+ unsigned xsiz, ysiz;
+ unsigned tile_width, tile_height;
+ unsigned tiles_x, tiles_y;
+ unsigned x, y, tile_ndx;
+ unsigned n;
+ j2k_pack_tile_t pack;
+ int ret = -1;
+
+ unsigned prec = 8;
+ unsigned _overflow_scale_factor;
+
+ stream = opj_stream_create(BUFFER_SIZE, OPJ_FALSE);
+
+ if (!stream) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ opj_stream_set_write_function(stream, j2k_write);
+ opj_stream_set_skip_function(stream, j2k_skip);
+ opj_stream_set_seek_function(stream, j2k_seek);
+
+ /* OpenJPEG 2.0 doesn't have OPJ_VERSION_MAJOR */
+#ifndef OPJ_VERSION_MAJOR
+ opj_stream_set_user_data(stream, state);
+#else
+ opj_stream_set_user_data(stream, state, NULL);
+#endif
+
+ /* Setup an opj_image */
+ if (strcmp(im->mode, "L") == 0) {
+ components = 1;
+ color_space = OPJ_CLRSPC_GRAY;
+ pack = j2k_pack_l;
+ } else if (strcmp(im->mode, "I;16") == 0 || strcmp(im->mode, "I;16B") == 0) {
+ components = 1;
+ color_space = OPJ_CLRSPC_GRAY;
+ pack = j2k_pack_i16;
+ prec = 16;
+ } else if (strcmp(im->mode, "LA") == 0) {
+ components = 2;
+ color_space = OPJ_CLRSPC_GRAY;
+ pack = j2k_pack_la;
+ } else if (strcmp(im->mode, "RGB") == 0) {
+ components = 3;
+ color_space = OPJ_CLRSPC_SRGB;
+ pack = j2k_pack_rgb;
+ } else if (strcmp(im->mode, "YCbCr") == 0) {
+ components = 3;
+ color_space = OPJ_CLRSPC_SYCC;
+ pack = j2k_pack_rgb;
+ } else if (strcmp(im->mode, "RGBA") == 0) {
+ components = 4;
+ color_space = OPJ_CLRSPC_SRGB;
+ pack = j2k_pack_rgba;
+ } else {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ for (n = 0; n < components; ++n) {
+ image_params[n].dx = image_params[n].dy = 1;
+ image_params[n].w = im->xsize;
+ image_params[n].h = im->ysize;
+ image_params[n].x0 = image_params[n].y0 = 0;
+ image_params[n].prec = prec;
+ image_params[n].sgnd = context->sgnd == 0 ? 0 : 1;
+ }
+
+ image = opj_image_create(components, image_params, color_space);
+ if (!image) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ /* Setup compression context */
+ context->error_msg = NULL;
+
+ opj_set_default_encoder_parameters(&params);
+
+ params.image_offset_x0 = context->offset_x;
+ params.image_offset_y0 = context->offset_y;
+
+ if (context->tile_size_x && context->tile_size_y) {
+ params.tile_size_on = OPJ_TRUE;
+ params.cp_tx0 = context->tile_offset_x;
+ params.cp_ty0 = context->tile_offset_y;
+ params.cp_tdx = context->tile_size_x;
+ params.cp_tdy = context->tile_size_y;
+
+ tile_width = params.cp_tdx;
+ tile_height = params.cp_tdy;
+ } else {
+ params.cp_tx0 = 0;
+ params.cp_ty0 = 0;
+ params.cp_tdx = 1;
+ params.cp_tdy = 1;
+
+ tile_width = im->xsize;
+ tile_height = im->ysize;
+ }
+
+ if (context->quality_layers && PySequence_Check(context->quality_layers)) {
+ Py_ssize_t len = PySequence_Length(context->quality_layers);
+ Py_ssize_t n;
+ float *pq;
+
+ if (len > 0) {
+ if ((size_t)len >
+ sizeof(params.tcp_rates) / sizeof(params.tcp_rates[0])) {
+ len = sizeof(params.tcp_rates) / sizeof(params.tcp_rates[0]);
+ }
+
+ params.tcp_numlayers = (int)len;
+
+ if (context->quality_is_in_db) {
+ params.cp_disto_alloc = params.cp_fixed_alloc = 0;
+ params.cp_fixed_quality = 1;
+ pq = params.tcp_distoratio;
+ } else {
+ params.cp_disto_alloc = 1;
+ params.cp_fixed_alloc = params.cp_fixed_quality = 0;
+ pq = params.tcp_rates;
+ }
+
+ for (n = 0; n < len; ++n) {
+ PyObject *obj = PySequence_ITEM(context->quality_layers, n);
+ pq[n] = PyFloat_AsDouble(obj);
+ }
+ }
+ } else {
+ params.tcp_numlayers = 1;
+ params.tcp_rates[0] = 0;
+ params.cp_disto_alloc = 1;
+ }
+
+ if (context->num_resolutions) {
+ params.numresolution = context->num_resolutions;
+ }
+
+ if (context->cblk_width >= 4 && context->cblk_width <= 1024 &&
+ context->cblk_height >= 4 && context->cblk_height <= 1024 &&
+ context->cblk_width * context->cblk_height <= 4096) {
+ params.cblockw_init = context->cblk_width;
+ params.cblockh_init = context->cblk_height;
+ }
+
+ if (context->precinct_width >= 4 && context->precinct_height >= 4 &&
+ context->precinct_width >= context->cblk_width &&
+ context->precinct_height > context->cblk_height) {
+ params.prcw_init[0] = context->precinct_width;
+ params.prch_init[0] = context->precinct_height;
+ params.res_spec = 1;
+ params.csty |= 0x01;
+ }
+
+ params.irreversible = context->irreversible;
+ if (components == 3) {
+ params.tcp_mct = context->mct;
+ }
+
+ if (context->comment) {
+ params.cp_comment = context->comment;
+ }
+
+ params.prog_order = context->progression;
+
+ params.cp_cinema = context->cinema_mode;
+
+ switch (params.cp_cinema) {
+ case OPJ_OFF:
+ params.cp_rsiz = OPJ_STD_RSIZ;
+ break;
+ case OPJ_CINEMA2K_24:
+ case OPJ_CINEMA2K_48:
+ params.cp_rsiz = OPJ_CINEMA2K;
+ if (params.numresolution > 6) {
+ params.numresolution = 6;
+ }
+ break;
+ case OPJ_CINEMA4K_24:
+ params.cp_rsiz = OPJ_CINEMA4K;
+ if (params.numresolution > 7) {
+ params.numresolution = 7;
+ }
+ break;
+ }
+
+ if (!context->num_resolutions) {
+ while (tile_width < (1U << (params.numresolution - 1U)) || tile_height < (1U << (params.numresolution - 1U))) {
+ params.numresolution -= 1;
+ }
+ }
+
+ if (context->cinema_mode != OPJ_OFF) {
+ j2k_set_cinema_params(im, components, &params);
+ }
+
+ /* Set up the reference grid in the image */
+ image->x0 = params.image_offset_x0;
+ image->y0 = params.image_offset_y0;
+ image->x1 = xsiz = im->xsize + params.image_offset_x0;
+ image->y1 = ysiz = im->ysize + params.image_offset_y0;
+
+ /* Create the compressor */
+ codec = opj_create_compress(context->format);
+
+ if (!codec) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ if (strcmp(im->mode, "RGBA") == 0) {
+ image->comps[3].alpha = 1;
+ } else if (strcmp(im->mode, "LA") == 0) {
+ image->comps[1].alpha = 1;
+ }
+
+ opj_set_error_handler(codec, j2k_error, context);
+ opj_set_info_handler(codec, j2k_warn, context);
+ opj_set_warning_handler(codec, j2k_warn, context);
+ opj_setup_encoder(codec, &params, image);
+
+ /* Enabling PLT markers only supported in OpenJPEG 2.4.0 and up */
+#if ((OPJ_VERSION_MAJOR == 2 && OPJ_VERSION_MINOR >= 4) || OPJ_VERSION_MAJOR > 2)
+ if (context->plt) {
+ const char *plt_option[2] = {"PLT=YES", NULL};
+ opj_encoder_set_extra_options(codec, plt_option);
+ }
+#endif
+
+ /* Start encoding */
+ if (!opj_start_compress(codec, image, stream)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ /* Write each tile */
+ tiles_x = (im->xsize + (params.image_offset_x0 - params.cp_tx0) + tile_width - 1) /
+ tile_width;
+ tiles_y = (im->ysize + (params.image_offset_y0 - params.cp_ty0) + tile_height - 1) /
+ tile_height;
+
+ /* check for integer overflow for the malloc line, checking any expression
+ that may multiply either tile_width or tile_height */
+ _overflow_scale_factor = components * prec;
+ if ((tile_width > UINT_MAX / _overflow_scale_factor) ||
+ (tile_height > UINT_MAX / _overflow_scale_factor) ||
+ (tile_width > UINT_MAX / (tile_height * _overflow_scale_factor)) ||
+ (tile_height > UINT_MAX / (tile_width * _overflow_scale_factor))) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+ /* malloc check ok, checked for overflow above */
+ state->buffer = malloc(tile_width * tile_height * components * prec / 8);
+ if (!state->buffer) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ tile_ndx = 0;
+ for (y = 0; y < tiles_y; ++y) {
+ int ty0 = params.cp_ty0 + y * tile_height;
+ unsigned ty1 = ty0 + tile_height;
+ unsigned pixy, pixh;
+
+ if (ty0 < params.image_offset_y0) {
+ ty0 = params.image_offset_y0;
+ }
+ if (ty1 > ysiz) {
+ ty1 = ysiz;
+ }
+
+ pixy = ty0 - params.image_offset_y0;
+ pixh = ty1 - ty0;
+
+ for (x = 0; x < tiles_x; ++x) {
+ int tx0 = params.cp_tx0 + x * tile_width;
+ unsigned tx1 = tx0 + tile_width;
+ unsigned pixx, pixw;
+ unsigned data_size;
+
+ if (tx0 < params.image_offset_x0) {
+ tx0 = params.image_offset_x0;
+ }
+ if (tx1 > xsiz) {
+ tx1 = xsiz;
+ }
+
+ pixx = tx0 - params.image_offset_x0;
+ pixw = tx1 - tx0;
+
+ pack(im, state->buffer, pixx, pixy, pixw, pixh);
+
+ data_size = pixw * pixh * components * prec / 8;
+
+ if (!opj_write_tile(codec, tile_ndx++, state->buffer, data_size, stream)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+ }
+ }
+
+ if (!opj_end_compress(codec, stream)) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ state->state = J2K_STATE_FAILED;
+ goto quick_exit;
+ }
+
+ state->errcode = IMAGING_CODEC_END;
+ state->state = J2K_STATE_DONE;
+ ret = -1;
+
+quick_exit:
+ if (codec) {
+ opj_destroy_codec(codec);
+ }
+ if (image) {
+ opj_image_destroy(image);
+ }
+ if (stream) {
+ opj_stream_destroy(stream);
+ }
+
+ return ret;
+}
+
+int
+ImagingJpeg2KEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
+ if (state->state == J2K_STATE_FAILED) {
+ return -1;
+ }
+
+ if (state->state == J2K_STATE_START) {
+ state->state = J2K_STATE_ENCODING;
+
+ return j2k_encode_entry(im, state);
+ }
+
+ return -1;
+}
+
+/* -------------------------------------------------------------------- */
+/* Cleanup */
+/* -------------------------------------------------------------------- */
+
+int
+ImagingJpeg2KEncodeCleanup(ImagingCodecState state) {
+ JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
+
+ if (context->quality_layers) {
+ Py_XDECREF(context->quality_layers);
+ context->quality_layers = NULL;
+ }
+
+ if (context->error_msg) {
+ free((void *)context->error_msg);
+ }
+
+ if (context->comment) {
+ free((void *)context->comment);
+ }
+
+ context->error_msg = NULL;
+ context->comment = NULL;
+
+ return -1;
+}
+
+#endif /* HAVE_OPENJPEG */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * End:
+ *
+ */
diff --git a/contrib/python/Pillow/py3/libImaging/JpegDecode.c b/contrib/python/Pillow/py3/libImaging/JpegDecode.c
new file mode 100644
index 00000000000..55d10a81aec
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/JpegDecode.c
@@ -0,0 +1,304 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for JPEG image data.
+ *
+ * history:
+ * 1996-05-02 fl Created
+ * 1996-05-05 fl Handle small JPEG files correctly
+ * 1996-05-28 fl Added "draft mode" support
+ * 1997-01-25 fl Added colour conversion override
+ * 1998-01-31 fl Adapted to libjpeg 6a
+ * 1998-07-12 fl Extended YCbCr support
+ * 1998-12-29 fl Added new state to handle suspension in multipass modes
+ * 2000-10-12 fl Suppress warnings
+ * 2000-12-04 fl Suppress errors beyond end of image data
+ *
+ * Copyright (c) 1998-2000 Secret Labs AB
+ * Copyright (c) 1996-2000 Fredrik Lundh
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#ifdef HAVE_LIBJPEG
+
+#undef HAVE_PROTOTYPES
+#undef HAVE_STDLIB_H
+#undef HAVE_STDDEF_H
+#undef UINT8
+#undef UINT16
+#undef UINT32
+#undef INT16
+#undef INT32
+
+#include "Jpeg.h"
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+
+// There is no way to compare versions on compile time,
+// so we have to do that in runtime.
+#ifdef LIBJPEG_TURBO_VERSION
+char *libjpeg_turbo_version = TOSTRING(LIBJPEG_TURBO_VERSION);
+#else
+char *libjpeg_turbo_version = NULL;
+#endif
+
+int
+ImagingJpegUseJCSExtensions() {
+ int use_jcs_extensions = 0;
+#ifdef JCS_EXTENSIONS
+#if defined(LIBJPEG_TURBO_VERSION_NUMBER)
+#if LIBJPEG_TURBO_VERSION_NUMBER >= 1002010
+ use_jcs_extensions = 1;
+#endif
+#else
+ if (libjpeg_turbo_version) {
+ use_jcs_extensions = strcmp(libjpeg_turbo_version, "1.2.1") >= 0;
+ }
+#endif
+#endif
+ return use_jcs_extensions;
+}
+
+/* -------------------------------------------------------------------- */
+/* Suspending input handler */
+/* -------------------------------------------------------------------- */
+
+METHODDEF(void)
+stub(j_decompress_ptr cinfo) { /* empty */ }
+
+METHODDEF(boolean)
+fill_input_buffer(j_decompress_ptr cinfo) {
+ /* Suspension */
+ return FALSE;
+}
+
+METHODDEF(void)
+skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
+ JPEGSOURCE *source = (JPEGSOURCE *)cinfo->src;
+
+ if (num_bytes > (long)source->pub.bytes_in_buffer) {
+ /* We need to skip more data than we have in the buffer.
+ This will force the JPEG library to suspend decoding. */
+ source->skip = num_bytes - source->pub.bytes_in_buffer;
+ source->pub.next_input_byte += source->pub.bytes_in_buffer;
+ source->pub.bytes_in_buffer = 0;
+ } else {
+ /* Skip portion of the buffer */
+ source->pub.bytes_in_buffer -= num_bytes;
+ source->pub.next_input_byte += num_bytes;
+ source->skip = 0;
+ }
+}
+
+GLOBAL(void)
+jpeg_buffer_src(j_decompress_ptr cinfo, JPEGSOURCE *source) {
+ cinfo->src = (void *)source;
+
+ /* Prepare for suspending reader */
+ source->pub.init_source = stub;
+ source->pub.fill_input_buffer = fill_input_buffer;
+ source->pub.skip_input_data = skip_input_data;
+ source->pub.resync_to_restart = jpeg_resync_to_restart;
+ source->pub.term_source = stub;
+ source->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+
+ source->skip = 0;
+}
+
+/* -------------------------------------------------------------------- */
+/* Error handler */
+/* -------------------------------------------------------------------- */
+
+METHODDEF(void)
+error(j_common_ptr cinfo) {
+ JPEGERROR *error;
+ error = (JPEGERROR *)cinfo->err;
+ longjmp(error->setjmp_buffer, 1);
+}
+
+METHODDEF(void)
+output(j_common_ptr cinfo) { /* nothing */ }
+
+/* -------------------------------------------------------------------- */
+/* Decoder */
+/* -------------------------------------------------------------------- */
+
+int
+ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ JPEGSTATE *context = (JPEGSTATE *)state->context;
+ int ok;
+
+ if (setjmp(context->error.setjmp_buffer)) {
+ /* JPEG error handler */
+ jpeg_destroy_decompress(&context->cinfo);
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ if (!state->state) {
+ /* Setup decompression context */
+ context->cinfo.err = jpeg_std_error(&context->error.pub);
+ context->error.pub.error_exit = error;
+ context->error.pub.output_message = output;
+ jpeg_create_decompress(&context->cinfo);
+ jpeg_buffer_src(&context->cinfo, &context->source);
+
+ /* Ready to decode */
+ state->state = 1;
+ }
+
+ /* Load the source buffer */
+ context->source.pub.next_input_byte = buf;
+ context->source.pub.bytes_in_buffer = bytes;
+
+ if (context->source.skip > 0) {
+ skip_input_data(&context->cinfo, context->source.skip);
+ if (context->source.skip > 0) {
+ return context->source.pub.next_input_byte - buf;
+ }
+ }
+
+ switch (state->state) {
+ case 1:
+
+ /* Read JPEG header, until we find an image body. */
+ do {
+ /* Note that we cannot return unless we have decoded
+ as much data as possible. */
+ ok = jpeg_read_header(&context->cinfo, FALSE);
+
+ } while (ok == JPEG_HEADER_TABLES_ONLY);
+
+ if (ok == JPEG_SUSPENDED) {
+ break;
+ }
+
+ /* Decoder settings */
+
+ /* jpegmode indicates whats in the file; if not set, we'll
+ trust the decoder */
+ if (strcmp(context->jpegmode, "L") == 0) {
+ context->cinfo.jpeg_color_space = JCS_GRAYSCALE;
+ } else if (strcmp(context->jpegmode, "RGB") == 0) {
+ context->cinfo.jpeg_color_space = JCS_RGB;
+ } else if (strcmp(context->jpegmode, "CMYK") == 0) {
+ context->cinfo.jpeg_color_space = JCS_CMYK;
+ } else if (strcmp(context->jpegmode, "YCbCr") == 0) {
+ context->cinfo.jpeg_color_space = JCS_YCbCr;
+ } else if (strcmp(context->jpegmode, "YCbCrK") == 0) {
+ context->cinfo.jpeg_color_space = JCS_YCCK;
+ }
+
+ /* rawmode indicates what we want from the decoder. if not
+ set, conversions are disabled */
+ if (strcmp(context->rawmode, "L") == 0) {
+ context->cinfo.out_color_space = JCS_GRAYSCALE;
+ } else if (strcmp(context->rawmode, "RGB") == 0) {
+ context->cinfo.out_color_space = JCS_RGB;
+ }
+#ifdef JCS_EXTENSIONS
+ else if (strcmp(context->rawmode, "RGBX") == 0) {
+ context->cinfo.out_color_space = JCS_EXT_RGBX;
+ }
+#endif
+ else if (
+ strcmp(context->rawmode, "CMYK") == 0 ||
+ strcmp(context->rawmode, "CMYK;I") == 0) {
+ context->cinfo.out_color_space = JCS_CMYK;
+ } else if (strcmp(context->rawmode, "YCbCr") == 0) {
+ context->cinfo.out_color_space = JCS_YCbCr;
+ } else if (strcmp(context->rawmode, "YCbCrK") == 0) {
+ context->cinfo.out_color_space = JCS_YCCK;
+ } else {
+ /* Disable decoder conversions */
+ context->cinfo.jpeg_color_space = JCS_UNKNOWN;
+ context->cinfo.out_color_space = JCS_UNKNOWN;
+ }
+
+ if (context->scale > 1) {
+ context->cinfo.scale_num = 1;
+ context->cinfo.scale_denom = context->scale;
+ }
+ if (context->draft) {
+ context->cinfo.do_fancy_upsampling = FALSE;
+ context->cinfo.dct_method = JDCT_FASTEST;
+ }
+
+ state->state++;
+ /* fall through */
+
+ case 2:
+
+ /* Set things up for decompression (this processes the entire
+ file if necessary to return data line by line) */
+ if (!jpeg_start_decompress(&context->cinfo)) {
+ break;
+ }
+
+ state->state++;
+ /* fall through */
+
+ case 3:
+
+ /* Decompress a single line of data */
+ ok = 1;
+ while (state->y < state->ysize) {
+ ok = jpeg_read_scanlines(&context->cinfo, &state->buffer, 1);
+ if (ok != 1) {
+ break;
+ }
+ state->shuffle(
+ (UINT8 *)im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->buffer,
+ state->xsize);
+ state->y++;
+ }
+ if (ok != 1) {
+ break;
+ }
+ state->state++;
+ /* fall through */
+
+ case 4:
+
+ /* Finish decompression */
+ if (!jpeg_finish_decompress(&context->cinfo)) {
+ /* FIXME: add strictness mode test */
+ if (state->y < state->ysize) {
+ break;
+ }
+ }
+
+ /* Clean up */
+ jpeg_destroy_decompress(&context->cinfo);
+ /* if (jerr.pub.num_warnings) return BROKEN; */
+ return -1;
+ }
+
+ /* Return number of bytes consumed */
+ return context->source.pub.next_input_byte - buf;
+}
+
+/* -------------------------------------------------------------------- */
+/* Cleanup */
+/* -------------------------------------------------------------------- */
+
+int
+ImagingJpegDecodeCleanup(ImagingCodecState state) {
+ /* called to free the decompression engine when the decode terminates
+ due to a corrupt or truncated image
+ */
+ JPEGSTATE *context = (JPEGSTATE *)state->context;
+
+ /* Clean up */
+ jpeg_destroy_decompress(&context->cinfo);
+ return -1;
+}
+
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/JpegEncode.c b/contrib/python/Pillow/py3/libImaging/JpegEncode.c
new file mode 100644
index 00000000000..2a24eff39ca
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/JpegEncode.c
@@ -0,0 +1,354 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * coder for JPEG data
+ *
+ * history:
+ * 1996-05-06 fl created
+ * 1996-07-16 fl don't drop last block of encoded data
+ * 1996-12-30 fl added quality and progressive settings
+ * 1997-01-08 fl added streamtype settings
+ * 1998-01-31 fl adapted to libjpeg 6a
+ * 1998-07-12 fl added YCbCr support
+ * 2001-04-16 fl added DPI write support
+ *
+ * Copyright (c) 1997-2001 by Secret Labs AB
+ * Copyright (c) 1995-1997 by Fredrik Lundh
+ *
+ * See the README file for details on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#ifdef HAVE_LIBJPEG
+
+#undef HAVE_PROTOTYPES
+#undef HAVE_STDLIB_H
+#undef HAVE_STDDEF_H
+#undef UINT8
+#undef UINT16
+#undef UINT32
+#undef INT16
+#undef INT32
+
+#include "Jpeg.h"
+
+/* -------------------------------------------------------------------- */
+/* Suspending output handler */
+/* -------------------------------------------------------------------- */
+
+METHODDEF(void)
+stub(j_compress_ptr cinfo) { /* empty */ }
+
+METHODDEF(boolean)
+empty_output_buffer(j_compress_ptr cinfo) {
+ /* Suspension */
+ return FALSE;
+}
+
+GLOBAL(void)
+jpeg_buffer_dest(j_compress_ptr cinfo, JPEGDESTINATION *destination) {
+ cinfo->dest = (void *)destination;
+
+ destination->pub.init_destination = stub;
+ destination->pub.empty_output_buffer = empty_output_buffer;
+ destination->pub.term_destination = stub;
+}
+
+/* -------------------------------------------------------------------- */
+/* Error handler */
+/* -------------------------------------------------------------------- */
+
+METHODDEF(void)
+error(j_common_ptr cinfo) {
+ JPEGERROR *error;
+ error = (JPEGERROR *)cinfo->err;
+ (*cinfo->err->output_message)(cinfo);
+ longjmp(error->setjmp_buffer, 1);
+}
+
+/* -------------------------------------------------------------------- */
+/* Encoder */
+/* -------------------------------------------------------------------- */
+
+int
+ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
+ JPEGENCODERSTATE *context = (JPEGENCODERSTATE *)state->context;
+ int ok;
+
+ if (setjmp(context->error.setjmp_buffer)) {
+ /* JPEG error handler */
+ jpeg_destroy_compress(&context->cinfo);
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ if (!state->state) {
+ /* Setup compression context (very similar to the decoder) */
+ context->cinfo.err = jpeg_std_error(&context->error.pub);
+ context->error.pub.error_exit = error;
+ jpeg_create_compress(&context->cinfo);
+ jpeg_buffer_dest(&context->cinfo, &context->destination);
+
+ context->extra_offset = 0;
+
+ /* Ready to encode */
+ state->state = 1;
+ }
+
+ /* Load the destination buffer */
+ context->destination.pub.next_output_byte = buf;
+ context->destination.pub.free_in_buffer = bytes;
+
+ switch (state->state) {
+ case 1:
+
+ context->cinfo.image_width = state->xsize;
+ context->cinfo.image_height = state->ysize;
+
+ switch (state->bits) {
+ case 8:
+ context->cinfo.input_components = 1;
+ context->cinfo.in_color_space = JCS_GRAYSCALE;
+ break;
+ case 24:
+ context->cinfo.input_components = 3;
+ if (strcmp(im->mode, "YCbCr") == 0) {
+ context->cinfo.in_color_space = JCS_YCbCr;
+ } else {
+ context->cinfo.in_color_space = JCS_RGB;
+ }
+ break;
+ case 32:
+ context->cinfo.input_components = 4;
+ context->cinfo.in_color_space = JCS_CMYK;
+#ifdef JCS_EXTENSIONS
+ if (strcmp(context->rawmode, "RGBX") == 0) {
+ context->cinfo.in_color_space = JCS_EXT_RGBX;
+ }
+#endif
+ break;
+ default:
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+
+ /* Compressor configuration */
+ jpeg_set_defaults(&context->cinfo);
+
+ /* Use custom quantization tables */
+ if (context->qtables) {
+ int i;
+ int quality = 100;
+ int last_q = 0;
+ if (context->quality != -1) {
+ quality = context->quality;
+ }
+ for (i = 0; i < context->qtablesLen; i++) {
+ jpeg_add_quant_table(
+ &context->cinfo,
+ i,
+ &context->qtables[i * DCTSIZE2],
+ quality,
+ FALSE);
+ context->cinfo.comp_info[i].quant_tbl_no = i;
+ last_q = i;
+ }
+ if (context->qtablesLen == 1) {
+ // jpeg_set_defaults created two qtables internally, but we only
+ // wanted one.
+ jpeg_add_quant_table(
+ &context->cinfo, 1, &context->qtables[0], quality, FALSE);
+ }
+ for (i = last_q; i < context->cinfo.num_components; i++) {
+ context->cinfo.comp_info[i].quant_tbl_no = last_q;
+ }
+ } else if (context->quality != -1) {
+ jpeg_set_quality(&context->cinfo, context->quality, TRUE);
+ }
+
+ /* Set subsampling options */
+ switch (context->subsampling) {
+ case 0: /* 1x1 1x1 1x1 (4:4:4) : None */
+ {
+ context->cinfo.comp_info[0].h_samp_factor = 1;
+ context->cinfo.comp_info[0].v_samp_factor = 1;
+ context->cinfo.comp_info[1].h_samp_factor = 1;
+ context->cinfo.comp_info[1].v_samp_factor = 1;
+ context->cinfo.comp_info[2].h_samp_factor = 1;
+ context->cinfo.comp_info[2].v_samp_factor = 1;
+ break;
+ }
+ case 1: /* 2x1, 1x1, 1x1 (4:2:2) : Medium */
+ {
+ context->cinfo.comp_info[0].h_samp_factor = 2;
+ context->cinfo.comp_info[0].v_samp_factor = 1;
+ context->cinfo.comp_info[1].h_samp_factor = 1;
+ context->cinfo.comp_info[1].v_samp_factor = 1;
+ context->cinfo.comp_info[2].h_samp_factor = 1;
+ context->cinfo.comp_info[2].v_samp_factor = 1;
+ break;
+ }
+ case 2: /* 2x2, 1x1, 1x1 (4:2:0) : High */
+ {
+ context->cinfo.comp_info[0].h_samp_factor = 2;
+ context->cinfo.comp_info[0].v_samp_factor = 2;
+ context->cinfo.comp_info[1].h_samp_factor = 1;
+ context->cinfo.comp_info[1].v_samp_factor = 1;
+ context->cinfo.comp_info[2].h_samp_factor = 1;
+ context->cinfo.comp_info[2].v_samp_factor = 1;
+ break;
+ }
+ default: {
+ /* Use the lib's default */
+ break;
+ }
+ }
+ if (context->progressive) {
+ jpeg_simple_progression(&context->cinfo);
+ }
+ context->cinfo.smoothing_factor = context->smooth;
+ context->cinfo.optimize_coding = (boolean)context->optimize;
+ if (context->xdpi > 0 && context->ydpi > 0) {
+ context->cinfo.write_JFIF_header = TRUE;
+ context->cinfo.density_unit = 1; /* dots per inch */
+ context->cinfo.X_density = context->xdpi;
+ context->cinfo.Y_density = context->ydpi;
+ }
+ switch (context->streamtype) {
+ case 1:
+ /* tables only -- not yet implemented */
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ case 2:
+ /* image only */
+ jpeg_suppress_tables(&context->cinfo, TRUE);
+ jpeg_start_compress(&context->cinfo, FALSE);
+ /* suppress extra section */
+ context->extra_offset = context->extra_size;
+ break;
+ default:
+ /* interchange stream */
+ jpeg_start_compress(&context->cinfo, TRUE);
+ break;
+ }
+ state->state++;
+ /* fall through */
+
+ case 2:
+ // check for exif len + 'APP1' header bytes
+ if (context->rawExifLen + 5 > context->destination.pub.free_in_buffer) {
+ break;
+ }
+ // add exif header
+ if (context->rawExifLen > 0) {
+ jpeg_write_marker(
+ &context->cinfo,
+ JPEG_APP0 + 1,
+ (unsigned char *)context->rawExif,
+ context->rawExifLen);
+ }
+
+ state->state++;
+ /* fall through */
+ case 3:
+
+ if (context->extra) {
+ /* copy extra buffer to output buffer */
+ unsigned int n = context->extra_size - context->extra_offset;
+ if (n > context->destination.pub.free_in_buffer) {
+ n = context->destination.pub.free_in_buffer;
+ }
+ memcpy(
+ context->destination.pub.next_output_byte,
+ context->extra + context->extra_offset,
+ n);
+ context->destination.pub.next_output_byte += n;
+ context->destination.pub.free_in_buffer -= n;
+ context->extra_offset += n;
+ if (context->extra_offset >= context->extra_size) {
+ state->state++;
+ } else {
+ break;
+ }
+ } else {
+ state->state++;
+ }
+
+ case 4:
+
+ if (context->comment) {
+ jpeg_write_marker(&context->cinfo, JPEG_COM, (unsigned char *)context->comment, context->comment_size);
+ }
+ state->state++;
+
+ case 5:
+ if (1024 > context->destination.pub.free_in_buffer) {
+ break;
+ }
+
+ ok = 1;
+ while (state->y < state->ysize) {
+ state->shuffle(
+ state->buffer,
+ (UINT8 *)im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->xsize);
+ ok = jpeg_write_scanlines(&context->cinfo, &state->buffer, 1);
+ if (ok != 1) {
+ break;
+ }
+ state->y++;
+ }
+
+ if (ok != 1) {
+ break;
+ }
+ state->state++;
+ /* fall through */
+
+ case 6:
+
+ /* Finish compression */
+ if (context->destination.pub.free_in_buffer < 100) {
+ break;
+ }
+ jpeg_finish_compress(&context->cinfo);
+
+ /* Clean up */
+ if (context->comment) {
+ free(context->comment);
+ context->comment = NULL;
+ }
+ if (context->extra) {
+ free(context->extra);
+ context->extra = NULL;
+ }
+ if (context->rawExif) {
+ free(context->rawExif);
+ context->rawExif = NULL;
+ }
+ if (context->qtables) {
+ free(context->qtables);
+ context->qtables = NULL;
+ }
+
+ jpeg_destroy_compress(&context->cinfo);
+ /* if (jerr.pub.num_warnings) return BROKEN; */
+ state->errcode = IMAGING_CODEC_END;
+ break;
+ }
+
+ /* Return number of bytes in output buffer */
+ return context->destination.pub.next_output_byte - buf;
+}
+
+const char *
+ImagingJpegVersion(void) {
+ static char version[20];
+ sprintf(version, "%d.%d", JPEG_LIB_VERSION / 10, JPEG_LIB_VERSION % 10);
+ return version;
+}
+
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/Matrix.c b/contrib/python/Pillow/py3/libImaging/Matrix.c
new file mode 100644
index 00000000000..182eb62a7e6
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Matrix.c
@@ -0,0 +1,78 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * colour and luminance matrix transforms
+ *
+ * history:
+ * 1996-05-18 fl: created (brute force implementation)
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#define CLIPF(v) ((v <= 0.0) ? 0 : (v >= 255.0F) ? 255 : (UINT8)v)
+
+Imaging
+ImagingConvertMatrix(Imaging im, const char *mode, float m[]) {
+ Imaging imOut;
+ int x, y;
+ ImagingSectionCookie cookie;
+
+ /* Assume there's enough data in the buffer */
+ if (!im) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ if (strcmp(mode, "L") == 0 && im->bands == 3) {
+ imOut = ImagingNewDirty("L", im->xsize, im->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < im->ysize; y++) {
+ UINT8 *in = (UINT8 *)im->image[y];
+ UINT8 *out = (UINT8 *)imOut->image[y];
+
+ for (x = 0; x < im->xsize; x++) {
+ float v = m[0] * in[0] + m[1] * in[1] + m[2] * in[2] + m[3] + 0.5;
+ out[x] = CLIPF(v);
+ in += 4;
+ }
+ }
+ ImagingSectionLeave(&cookie);
+
+ } else if (strlen(mode) == 3 && im->bands == 3) {
+ imOut = ImagingNewDirty(mode, im->xsize, im->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ for (y = 0; y < im->ysize; y++) {
+ UINT8 *in = (UINT8 *)im->image[y];
+ UINT8 *out = (UINT8 *)imOut->image[y];
+
+ ImagingSectionEnter(&cookie);
+ for (x = 0; x < im->xsize; x++) {
+ float v0 = m[0] * in[0] + m[1] * in[1] + m[2] * in[2] + m[3] + 0.5;
+ float v1 = m[4] * in[0] + m[5] * in[1] + m[6] * in[2] + m[7] + 0.5;
+ float v2 = m[8] * in[0] + m[9] * in[1] + m[10] * in[2] + m[11] + 0.5;
+ out[0] = CLIPF(v0);
+ out[1] = CLIPF(v1);
+ out[2] = CLIPF(v2);
+ in += 4;
+ out += 4;
+ }
+ ImagingSectionLeave(&cookie);
+ }
+ } else {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/ModeFilter.c b/contrib/python/Pillow/py3/libImaging/ModeFilter.c
new file mode 100644
index 00000000000..757cbc3fb86
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/ModeFilter.c
@@ -0,0 +1,81 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * mode filter
+ *
+ * history:
+ * 2002-06-08 fl Created (based on code from IFUNC95)
+ * 2004-10-05 fl Rewritten; use a simpler brute-force algorithm
+ *
+ * Copyright (c) Secret Labs AB 2002-2004. All rights reserved.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+Imaging
+ImagingModeFilter(Imaging im, int size) {
+ Imaging imOut;
+ int x, y, i;
+ int xx, yy;
+ int maxcount;
+ UINT8 maxpixel;
+ int histogram[256];
+
+ if (!im || im->bands != 1 || im->type != IMAGING_TYPE_UINT8) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ size = size / 2;
+
+ for (y = 0; y < imOut->ysize; y++) {
+ UINT8 *out = &IMAGING_PIXEL_L(imOut, 0, y);
+ for (x = 0; x < imOut->xsize; x++) {
+ /* calculate histogram over current area */
+
+ /* FIXME: brute force! to improve, update the histogram
+ incrementally. may also add a "frequent list", like in
+ the old implementation, but I'm not sure that's worth
+ the added complexity... */
+
+ memset(histogram, 0, sizeof(histogram));
+ for (yy = y - size; yy <= y + size; yy++) {
+ if (yy >= 0 && yy < imOut->ysize) {
+ UINT8 *in = &IMAGING_PIXEL_L(im, 0, yy);
+ for (xx = x - size; xx <= x + size; xx++) {
+ if (xx >= 0 && xx < imOut->xsize) {
+ histogram[in[xx]]++;
+ }
+ }
+ }
+ }
+
+ /* find most frequent pixel value in this region */
+ maxpixel = 0;
+ maxcount = histogram[maxpixel];
+ for (i = 1; i < 256; i++) {
+ if (histogram[i] > maxcount) {
+ maxcount = histogram[i];
+ maxpixel = (UINT8)i;
+ }
+ }
+
+ if (maxcount > 2) {
+ out[x] = maxpixel;
+ } else {
+ out[x] = IMAGING_PIXEL_L(im, x, y);
+ }
+ }
+ }
+
+ ImagingCopyPalette(imOut, im);
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Negative.c b/contrib/python/Pillow/py3/libImaging/Negative.c
new file mode 100644
index 00000000000..70b96c39772
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Negative.c
@@ -0,0 +1,42 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * negate image
+ *
+ * to do:
+ * FIXME: Maybe this should be implemented using ImagingPoint()
+ *
+ * history:
+ * 95-11-27 fl: Created
+ *
+ * Copyright (c) Fredrik Lundh 1995.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+Imaging
+ImagingNegative(Imaging im) {
+ Imaging imOut;
+ int x, y;
+
+ if (!im) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ for (y = 0; y < im->ysize; y++) {
+ for (x = 0; x < im->linesize; x++) {
+ imOut->image[y][x] = ~im->image[y][x];
+ }
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Offset.c b/contrib/python/Pillow/py3/libImaging/Offset.c
new file mode 100644
index 00000000000..91ee91083cc
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Offset.c
@@ -0,0 +1,64 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * offset an image in x and y directions
+ *
+ * history:
+ * 96-07-22 fl: Created
+ * 98-11-01 [email protected]: Fixed negative-array index bug
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+Imaging
+ImagingOffset(Imaging im, int xoffset, int yoffset) {
+ int x, y;
+ Imaging imOut;
+
+ if (!im) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ ImagingCopyPalette(imOut, im);
+
+ /* make offsets positive to avoid negative coordinates */
+ xoffset %= im->xsize;
+ xoffset = im->xsize - xoffset;
+ if (xoffset < 0) {
+ xoffset += im->xsize;
+ }
+
+ yoffset %= im->ysize;
+ yoffset = im->ysize - yoffset;
+ if (yoffset < 0) {
+ yoffset += im->ysize;
+ }
+
+#define OFFSET(image) \
+ for (y = 0; y < im->ysize; y++) { \
+ for (x = 0; x < im->xsize; x++) { \
+ int yi = (y + yoffset) % im->ysize; \
+ int xi = (x + xoffset) % im->xsize; \
+ imOut->image[y][x] = im->image[yi][xi]; \
+ } \
+ }
+
+ if (im->image8) {
+ OFFSET(image8)
+ } else {
+ OFFSET(image32)
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Pack.c b/contrib/python/Pillow/py3/libImaging/Pack.c
new file mode 100644
index 00000000000..14c8f1461aa
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Pack.c
@@ -0,0 +1,693 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * code to pack raw data
+ *
+ * history:
+ * 1996-04-30 fl Created
+ * 1996-05-12 fl Published a few RGB packers
+ * 1996-11-01 fl More RGB packers (Tk booster stuff)
+ * 1996-12-30 fl Added P;1, P;2 and P;4 packers
+ * 1997-06-02 fl Added F (F;32NF) packer
+ * 1997-08-28 fl Added 1 as L packer
+ * 1998-02-08 fl Added I packer
+ * 1998-03-09 fl Added mode field, RGBA/RGBX as RGB packers
+ * 1998-07-01 fl Added YCbCr support
+ * 1998-07-12 fl Added I 16 packer
+ * 1999-02-03 fl Added BGR packers
+ * 2003-09-26 fl Added LA/PA packers
+ * 2006-06-22 fl Added CMYK;I packer
+ *
+ * Copyright (c) 1997-2006 by Secret Labs AB.
+ * Copyright (c) 1996-1997 by Fredrik Lundh.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#define R 0
+#define G 1
+#define B 2
+#define X 3
+#define A 3
+
+#define C 0
+#define M 1
+#define Y 2
+#define K 3
+
+/* byte swapping macros */
+
+#define C16N (out[0] = tmp[0], out[1] = tmp[1]);
+#define C16S (out[1] = tmp[0], out[0] = tmp[1]);
+#define C32N (out[0] = tmp[0], out[1] = tmp[1], out[2] = tmp[2], out[3] = tmp[3]);
+#define C32S (out[3] = tmp[0], out[2] = tmp[1], out[1] = tmp[2], out[0] = tmp[3]);
+#define C64N \
+ (out[0] = tmp[0], \
+ out[1] = tmp[1], \
+ out[2] = tmp[2], \
+ out[3] = tmp[3], \
+ out[4] = tmp[4], \
+ out[5] = tmp[5], \
+ out[6] = tmp[6], \
+ out[7] = tmp[7]);
+#define C64S \
+ (out[7] = tmp[0], \
+ out[6] = tmp[1], \
+ out[5] = tmp[2], \
+ out[4] = tmp[3], \
+ out[3] = tmp[4], \
+ out[2] = tmp[5], \
+ out[1] = tmp[6], \
+ out[0] = tmp[7]);
+
+#ifdef WORDS_BIGENDIAN
+#define C16B C16N
+#define C16L C16S
+#define C32B C32N
+#define C32L C32S
+#define C64B C64N
+#define C64L C64S
+#else
+#define C16B C16S
+#define C16L C16N
+#define C32B C32S
+#define C32L C32N
+#define C64B C64S
+#define C64L C64N
+#endif
+
+static void
+pack1(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, m, b;
+ /* bilevel (black is 0) */
+ b = 0;
+ m = 128;
+ for (i = 0; i < pixels; i++) {
+ if (in[i] != 0) {
+ b |= m;
+ }
+ m >>= 1;
+ if (m == 0) {
+ *out++ = b;
+ b = 0;
+ m = 128;
+ }
+ }
+ if (m != 128) {
+ *out++ = b;
+ }
+}
+
+static void
+pack1I(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, m, b;
+ /* bilevel (black is 1) */
+ b = 0;
+ m = 128;
+ for (i = 0; i < pixels; i++) {
+ if (in[i] == 0) {
+ b |= m;
+ }
+ m >>= 1;
+ if (m == 0) {
+ *out++ = b;
+ b = 0;
+ m = 128;
+ }
+ }
+ if (m != 128) {
+ *out++ = b;
+ }
+}
+
+static void
+pack1R(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, m, b;
+ /* bilevel, lsb first (black is 0) */
+ b = 0;
+ m = 1;
+ for (i = 0; i < pixels; i++) {
+ if (in[i] != 0) {
+ b |= m;
+ }
+ m <<= 1;
+ if (m == 256) {
+ *out++ = b;
+ b = 0;
+ m = 1;
+ }
+ }
+ if (m != 1) {
+ *out++ = b;
+ }
+}
+
+static void
+pack1IR(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, m, b;
+ /* bilevel, lsb first (black is 1) */
+ b = 0;
+ m = 1;
+ for (i = 0; i < pixels; i++) {
+ if (in[i] == 0) {
+ b |= m;
+ }
+ m <<= 1;
+ if (m == 256) {
+ *out++ = b;
+ b = 0;
+ m = 1;
+ }
+ }
+ if (m != 1) {
+ *out++ = b;
+ }
+}
+
+static void
+pack1L(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* bilevel, stored as bytes */
+ for (i = 0; i < pixels; i++) {
+ out[i] = (in[i] != 0) ? 255 : 0;
+ }
+}
+
+static void
+packP4(UINT8 *out, const UINT8 *in, int pixels) {
+ while (pixels >= 2) {
+ *out++ = (in[0] << 4) | (in[1] & 15);
+ in += 2;
+ pixels -= 2;
+ }
+
+ if (pixels) {
+ out[0] = (in[0] << 4);
+ }
+}
+
+static void
+packP2(UINT8 *out, const UINT8 *in, int pixels) {
+ while (pixels >= 4) {
+ *out++ = (in[0] << 6) | ((in[1] & 3) << 4) | ((in[2] & 3) << 2) | (in[3] & 3);
+ in += 4;
+ pixels -= 4;
+ }
+
+ switch (pixels) {
+ case 3:
+ out[0] = (in[0] << 6) | ((in[1] & 3) << 4) | ((in[2] & 3) << 2);
+ break;
+ case 2:
+ out[0] = (in[0] << 6) | ((in[1] & 3) << 4);
+ break;
+ case 1:
+ out[0] = (in[0] << 6);
+ }
+}
+
+static void
+packL16(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* L -> L;16, e.g: \xff77 -> \x00\xff\x00\x77 */
+ for (i = 0; i < pixels; i++) {
+ out[0] = 0;
+ out[1] = in[i];
+ out += 2;
+ }
+}
+
+static void
+packL16B(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* L -> L;16B, e.g: \xff77 -> \xff\x00\x77\x00 */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[i];
+ out[1] = 0;
+ out += 2;
+ }
+}
+
+static void
+packLA(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* LA, pixel interleaved */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[R];
+ out[1] = in[A];
+ out += 2;
+ in += 4;
+ }
+}
+
+static void
+packLAL(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* LA, line interleaved */
+ for (i = 0; i < pixels; i++) {
+ out[i] = in[R];
+ out[i + pixels] = in[A];
+ in += 4;
+ }
+}
+
+void
+ImagingPackRGB(UINT8 *out, const UINT8 *in, int pixels) {
+ int i = 0;
+ /* RGB triplets */
+#ifdef __sparc
+ /* SPARC CPUs cannot read integers from nonaligned addresses. */
+ for (; i < pixels; i++) {
+ out[0] = in[R];
+ out[1] = in[G];
+ out[2] = in[B];
+ out += 3;
+ in += 4;
+ }
+#else
+ for (; i < pixels - 1; i++) {
+ memcpy(out, in + i * 4, 4);
+ out += 3;
+ }
+ for (; i < pixels; i++) {
+ out[0] = in[i * 4 + R];
+ out[1] = in[i * 4 + G];
+ out[2] = in[i * 4 + B];
+ out += 3;
+ }
+#endif
+}
+
+void
+ImagingPackXRGB(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* XRGB, triplets with left padding */
+ for (i = 0; i < pixels; i++) {
+ out[0] = 0;
+ out[1] = in[R];
+ out[2] = in[G];
+ out[3] = in[B];
+ out += 4;
+ in += 4;
+ }
+}
+
+void
+ImagingPackBGR(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGB, reversed bytes */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[B];
+ out[1] = in[G];
+ out[2] = in[R];
+ out += 3;
+ in += 4;
+ }
+}
+
+void
+ImagingPackBGRX(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* BGRX, reversed bytes with right padding */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[B];
+ out[1] = in[G];
+ out[2] = in[R];
+ out[3] = 0;
+ out += 4;
+ in += 4;
+ }
+}
+
+void
+ImagingPackXBGR(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* XBGR, reversed bytes with left padding */
+ for (i = 0; i < pixels; i++) {
+ out[0] = 0;
+ out[1] = in[B];
+ out[2] = in[G];
+ out[3] = in[R];
+ out += 4;
+ in += 4;
+ }
+}
+
+void
+ImagingPackBGRA(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* BGRX, reversed bytes with right padding */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[B];
+ out[1] = in[G];
+ out[2] = in[R];
+ out[3] = in[A];
+ out += 4;
+ in += 4;
+ }
+}
+
+void
+ImagingPackABGR(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* XBGR, reversed bytes with left padding */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[A];
+ out[1] = in[B];
+ out[2] = in[G];
+ out[3] = in[R];
+ out += 4;
+ in += 4;
+ }
+}
+
+void
+ImagingPackBGRa(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* BGRa, reversed bytes with premultiplied alpha */
+ for (i = 0; i < pixels; i++) {
+ int alpha = out[3] = in[A];
+ int tmp;
+ out[0] = MULDIV255(in[B], alpha, tmp);
+ out[1] = MULDIV255(in[G], alpha, tmp);
+ out[2] = MULDIV255(in[R], alpha, tmp);
+ out += 4;
+ in += 4;
+ }
+}
+
+static void
+packRGBL(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGB, line interleaved */
+ for (i = 0; i < pixels; i++) {
+ out[i] = in[R];
+ out[i + pixels] = in[G];
+ out[i + pixels + pixels] = in[B];
+ in += 4;
+ }
+}
+
+static void
+packRGBXL(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGBX, line interleaved */
+ for (i = 0; i < pixels; i++) {
+ out[i] = in[R];
+ out[i + pixels] = in[G];
+ out[i + pixels + pixels] = in[B];
+ out[i + pixels + pixels + pixels] = in[X];
+ in += 4;
+ }
+}
+
+static void
+packI16B(UINT8 *out, const UINT8 *in_, int pixels) {
+ int i;
+ UINT16 tmp_;
+ UINT8 *tmp = (UINT8 *)&tmp_;
+ for (i = 0; i < pixels; i++) {
+ INT32 in;
+ memcpy(&in, in_, sizeof(in));
+ if (in <= 0) {
+ tmp_ = 0;
+ } else if (in > 65535) {
+ tmp_ = 65535;
+ } else {
+ tmp_ = in;
+ }
+ C16B;
+ out += 2;
+ in_ += sizeof(in);
+ }
+}
+
+static void
+packI16N_I16B(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ UINT8 *tmp = (UINT8 *)in;
+ for (i = 0; i < pixels; i++) {
+ C16B;
+ out += 2;
+ tmp += 2;
+ }
+}
+static void
+packI16N_I16(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ UINT8 *tmp = (UINT8 *)in;
+ for (i = 0; i < pixels; i++) {
+ C16L;
+ out += 2;
+ tmp += 2;
+ }
+}
+
+static void
+packI32S(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ UINT8 *tmp = (UINT8 *)in;
+ for (i = 0; i < pixels; i++) {
+ C32L;
+ out += 4;
+ tmp += 4;
+ }
+}
+
+void
+ImagingPackLAB(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* LAB triplets */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[0];
+ out[1] = in[1] ^ 128; /* signed in outside world */
+ out[2] = in[2] ^ 128;
+ out += 3;
+ in += 4;
+ }
+}
+
+static void
+copy1(UINT8 *out, const UINT8 *in, int pixels) {
+ /* L, P */
+ memcpy(out, in, pixels);
+}
+
+static void
+copy2(UINT8 *out, const UINT8 *in, int pixels) {
+ /* I;16, etc */
+ memcpy(out, in, pixels * 2);
+}
+
+static void
+copy3(UINT8 *out, const UINT8 *in, int pixels) {
+ /* BGR;24, etc */
+ memcpy(out, in, pixels * 3);
+}
+
+static void
+copy4(UINT8 *out, const UINT8 *in, int pixels) {
+ /* RGBA, CMYK quadruples */
+ memcpy(out, in, 4 * pixels);
+}
+
+static void
+copy4I(UINT8 *out, const UINT8 *in, int pixels) {
+ /* RGBA, CMYK quadruples, inverted */
+ int i;
+ for (i = 0; i < pixels * 4; i++) {
+ out[i] = ~in[i];
+ }
+}
+
+static void
+band0(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ for (i = 0; i < pixels; i++, in += 4) {
+ out[i] = in[0];
+ }
+}
+
+static void
+band1(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ for (i = 0; i < pixels; i++, in += 4) {
+ out[i] = in[1];
+ }
+}
+
+static void
+band2(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ for (i = 0; i < pixels; i++, in += 4) {
+ out[i] = in[2];
+ }
+}
+
+static void
+band3(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ for (i = 0; i < pixels; i++, in += 4) {
+ out[i] = in[3];
+ }
+}
+
+static struct {
+ const char *mode;
+ const char *rawmode;
+ int bits;
+ ImagingShuffler pack;
+} packers[] = {
+
+ /* bilevel */
+ {"1", "1", 1, pack1},
+ {"1", "1;I", 1, pack1I},
+ {"1", "1;R", 1, pack1R},
+ {"1", "1;IR", 1, pack1IR},
+ {"1", "L", 8, pack1L},
+
+ /* greyscale */
+ {"L", "L", 8, copy1},
+ {"L", "L;16", 16, packL16},
+ {"L", "L;16B", 16, packL16B},
+
+ /* greyscale w. alpha */
+ {"LA", "LA", 16, packLA},
+ {"LA", "LA;L", 16, packLAL},
+
+ /* greyscale w. alpha premultiplied */
+ {"La", "La", 16, packLA},
+
+ /* palette */
+ {"P", "P;1", 1, pack1},
+ {"P", "P;2", 2, packP2},
+ {"P", "P;4", 4, packP4},
+ {"P", "P", 8, copy1},
+
+ /* palette w. alpha */
+ {"PA", "PA", 16, packLA},
+ {"PA", "PA;L", 16, packLAL},
+
+ /* true colour */
+ {"RGB", "RGB", 24, ImagingPackRGB},
+ {"RGB", "RGBX", 32, copy4},
+ {"RGB", "RGBA", 32, copy4},
+ {"RGB", "XRGB", 32, ImagingPackXRGB},
+ {"RGB", "BGR", 24, ImagingPackBGR},
+ {"RGB", "BGRX", 32, ImagingPackBGRX},
+ {"RGB", "XBGR", 32, ImagingPackXBGR},
+ {"RGB", "RGB;L", 24, packRGBL},
+ {"RGB", "R", 8, band0},
+ {"RGB", "G", 8, band1},
+ {"RGB", "B", 8, band2},
+
+ /* true colour w. alpha */
+ {"RGBA", "RGBA", 32, copy4},
+ {"RGBA", "RGBA;L", 32, packRGBXL},
+ {"RGBA", "RGB", 24, ImagingPackRGB},
+ {"RGBA", "BGR", 24, ImagingPackBGR},
+ {"RGBA", "BGRA", 32, ImagingPackBGRA},
+ {"RGBA", "ABGR", 32, ImagingPackABGR},
+ {"RGBA", "BGRa", 32, ImagingPackBGRa},
+ {"RGBA", "R", 8, band0},
+ {"RGBA", "G", 8, band1},
+ {"RGBA", "B", 8, band2},
+ {"RGBA", "A", 8, band3},
+
+ /* true colour w. alpha premultiplied */
+ {"RGBa", "RGBa", 32, copy4},
+ {"RGBa", "BGRa", 32, ImagingPackBGRA},
+ {"RGBa", "aBGR", 32, ImagingPackABGR},
+
+ /* true colour w. padding */
+ {"RGBX", "RGBX", 32, copy4},
+ {"RGBX", "RGBX;L", 32, packRGBXL},
+ {"RGBX", "RGB", 24, ImagingPackRGB},
+ {"RGBX", "BGR", 24, ImagingPackBGR},
+ {"RGBX", "BGRX", 32, ImagingPackBGRX},
+ {"RGBX", "XBGR", 32, ImagingPackXBGR},
+ {"RGBX", "R", 8, band0},
+ {"RGBX", "G", 8, band1},
+ {"RGBX", "B", 8, band2},
+ {"RGBX", "X", 8, band3},
+
+ /* colour separation */
+ {"CMYK", "CMYK", 32, copy4},
+ {"CMYK", "CMYK;I", 32, copy4I},
+ {"CMYK", "CMYK;L", 32, packRGBXL},
+ {"CMYK", "C", 8, band0},
+ {"CMYK", "M", 8, band1},
+ {"CMYK", "Y", 8, band2},
+ {"CMYK", "K", 8, band3},
+
+ /* video (YCbCr) */
+ {"YCbCr", "YCbCr", 24, ImagingPackRGB},
+ {"YCbCr", "YCbCr;L", 24, packRGBL},
+ {"YCbCr", "YCbCrX", 32, copy4},
+ {"YCbCr", "YCbCrK", 32, copy4},
+ {"YCbCr", "Y", 8, band0},
+ {"YCbCr", "Cb", 8, band1},
+ {"YCbCr", "Cr", 8, band2},
+
+ /* LAB Color */
+ {"LAB", "LAB", 24, ImagingPackLAB},
+ {"LAB", "L", 8, band0},
+ {"LAB", "A", 8, band1},
+ {"LAB", "B", 8, band2},
+
+ /* HSV */
+ {"HSV", "HSV", 24, ImagingPackRGB},
+ {"HSV", "H", 8, band0},
+ {"HSV", "S", 8, band1},
+ {"HSV", "V", 8, band2},
+
+ /* integer */
+ {"I", "I", 32, copy4},
+ {"I", "I;16B", 16, packI16B},
+ {"I", "I;32S", 32, packI32S},
+ {"I", "I;32NS", 32, copy4},
+
+ /* floating point */
+ {"F", "F", 32, copy4},
+ {"F", "F;32F", 32, packI32S},
+ {"F", "F;32NF", 32, copy4},
+
+ /* storage modes */
+ {"I;16", "I;16", 16, copy2},
+#ifdef WORDS_BIGENDIAN
+ {"I;16", "I;16B", 16, packI16N_I16},
+#else
+ {"I;16", "I;16B", 16, packI16N_I16B},
+#endif
+ {"I;16B", "I;16B", 16, copy2},
+ {"I;16L", "I;16L", 16, copy2},
+ {"I;16N", "I;16N", 16, copy2},
+ {"I;16", "I;16N", 16, packI16N_I16}, // LibTiff native->image endian.
+ {"I;16L", "I;16N", 16, packI16N_I16},
+ {"I;16B", "I;16N", 16, packI16N_I16B},
+ {"BGR;15", "BGR;15", 16, copy2},
+ {"BGR;16", "BGR;16", 16, copy2},
+ {"BGR;24", "BGR;24", 24, copy3},
+
+ {NULL} /* sentinel */
+};
+
+ImagingShuffler
+ImagingFindPacker(const char *mode, const char *rawmode, int *bits_out) {
+ int i;
+
+ /* find a suitable pixel packer */
+ for (i = 0; packers[i].rawmode; i++) {
+ if (strcmp(packers[i].mode, mode) == 0 &&
+ strcmp(packers[i].rawmode, rawmode) == 0) {
+ if (bits_out) {
+ *bits_out = packers[i].bits;
+ }
+ return packers[i].pack;
+ }
+ }
+ return NULL;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/PackDecode.c b/contrib/python/Pillow/py3/libImaging/PackDecode.c
new file mode 100644
index 00000000000..7dd432b91c2
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/PackDecode.c
@@ -0,0 +1,92 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for PackBits image data.
+ *
+ * history:
+ * 96-04-19 fl Created
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+int
+ImagingPackbitsDecode(
+ Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ UINT8 n;
+ UINT8 *ptr;
+ int i;
+
+ ptr = buf;
+
+ for (;;) {
+ if (bytes < 1) {
+ return ptr - buf;
+ }
+
+ if (ptr[0] & 0x80) {
+ if (ptr[0] == 0x80) {
+ /* Nop */
+ ptr++;
+ bytes--;
+ continue;
+ }
+
+ /* Run */
+ if (bytes < 2) {
+ return ptr - buf;
+ }
+
+ for (n = 257 - ptr[0]; n > 0; n--) {
+ if (state->x >= state->bytes) {
+ /* state->errcode = IMAGING_CODEC_OVERRUN; */
+ break;
+ }
+ state->buffer[state->x++] = ptr[1];
+ }
+
+ ptr += 2;
+ bytes -= 2;
+
+ } else {
+ /* Literal */
+ n = ptr[0] + 2;
+
+ if (bytes < n) {
+ return ptr - buf;
+ }
+
+ for (i = 1; i < n; i++) {
+ if (state->x >= state->bytes) {
+ /* state->errcode = IMAGING_CODEC_OVERRUN; */
+ break;
+ }
+ state->buffer[state->x++] = ptr[i];
+ }
+
+ ptr += n;
+ bytes -= n;
+ }
+
+ if (state->x >= state->bytes) {
+ /* Got a full line, unpack it */
+ state->shuffle(
+ (UINT8 *)im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->buffer,
+ state->xsize);
+
+ state->x = 0;
+
+ if (++state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+ }
+ }
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Palette.c b/contrib/python/Pillow/py3/libImaging/Palette.c
new file mode 100644
index 00000000000..059d7b72aca
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Palette.c
@@ -0,0 +1,307 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * imaging palette object
+ *
+ * history:
+ * 1996-05-05 fl Added to library
+ * 1996-05-27 fl Added colour mapping stuff
+ * 1997-05-12 fl Support RGBA palettes
+ * 2005-02-09 fl Removed grayscale entries from web palette
+ *
+ * Copyright (c) Secret Labs AB 1997-2005. All rights reserved.
+ * Copyright (c) Fredrik Lundh 1995-1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#include <math.h>
+
+ImagingPalette
+ImagingPaletteNew(const char *mode) {
+ /* Create a palette object */
+
+ int i;
+ ImagingPalette palette;
+
+ if (strcmp(mode, "RGB") && strcmp(mode, "RGBA")) {
+ return (ImagingPalette)ImagingError_ModeError();
+ }
+
+ palette = calloc(1, sizeof(struct ImagingPaletteInstance));
+ if (!palette) {
+ return (ImagingPalette)ImagingError_MemoryError();
+ }
+
+ strncpy(palette->mode, mode, IMAGING_MODE_LENGTH - 1);
+ palette->mode[IMAGING_MODE_LENGTH - 1] = 0;
+
+ palette->size = 0;
+ for (i = 0; i < 256; i++) {
+ palette->palette[i * 4 + 3] = 255; /* opaque */
+ }
+
+ return palette;
+}
+
+ImagingPalette
+ImagingPaletteNewBrowser(void) {
+ /* Create a standard "browser" palette object */
+
+ int i, r, g, b;
+ ImagingPalette palette;
+
+ palette = ImagingPaletteNew("RGB");
+ if (!palette) {
+ return NULL;
+ }
+
+ /* FIXME: Add 10-level windows palette here? */
+
+ /* Simple 6x6x6 colour cube */
+ i = 10;
+ for (b = 0; b < 256; b += 51) {
+ for (g = 0; g < 256; g += 51) {
+ for (r = 0; r < 256; r += 51) {
+ palette->palette[i * 4 + 0] = r;
+ palette->palette[i * 4 + 1] = g;
+ palette->palette[i * 4 + 2] = b;
+ i++;
+ }
+ }
+ }
+ palette->size = i;
+
+ /* FIXME: add 30-level greyscale wedge here? */
+
+ return palette;
+}
+
+ImagingPalette
+ImagingPaletteDuplicate(ImagingPalette palette) {
+ /* Duplicate palette descriptor */
+
+ ImagingPalette new_palette;
+
+ if (!palette) {
+ return NULL;
+ }
+ /* malloc check ok, small constant allocation */
+ new_palette = malloc(sizeof(struct ImagingPaletteInstance));
+ if (!new_palette) {
+ return (ImagingPalette)ImagingError_MemoryError();
+ }
+
+ memcpy(new_palette, palette, sizeof(struct ImagingPaletteInstance));
+
+ /* Don't share the cache */
+ new_palette->cache = NULL;
+
+ return new_palette;
+}
+
+void
+ImagingPaletteDelete(ImagingPalette palette) {
+ /* Destroy palette object */
+
+ if (palette) {
+ if (palette->cache) {
+ free(palette->cache);
+ }
+ free(palette);
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* Colour mapping */
+/* -------------------------------------------------------------------- */
+
+/* This code is used to map RGB triplets to palette indices, using
+ a palette index cache. */
+
+/*
+ * This implementation is loosely based on the corresponding code in
+ * the IJG JPEG library by Thomas G. Lane. Original algorithms by
+ * Paul Heckbert and Spencer W. Thomas.
+ *
+ * The IJG JPEG library is copyright (C) 1991-1995, Thomas G. Lane. */
+
+#define DIST(a, b, s) (a - b) * (a - b) * s
+
+/* Colour weights (no scaling, for now) */
+#define RSCALE 1
+#define GSCALE 1
+#define BSCALE 1
+
+/* Calculated scaled distances */
+#define RDIST(a, b) DIST(a, b, RSCALE *RSCALE)
+#define GDIST(a, b) DIST(a, b, GSCALE *GSCALE)
+#define BDIST(a, b) DIST(a, b, BSCALE *BSCALE)
+
+/* Incremental steps */
+#define RSTEP (4 * RSCALE)
+#define GSTEP (4 * GSCALE)
+#define BSTEP (4 * BSCALE)
+
+#define BOX 8
+
+#define BOXVOLUME BOX *BOX *BOX
+
+void
+ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b) {
+ int i, j;
+ unsigned int dmin[256], dmax;
+ int r0, g0, b0;
+ int r1, g1, b1;
+ int rc, gc, bc;
+ unsigned int d[BOXVOLUME];
+ UINT8 c[BOXVOLUME];
+
+ /* Get box boundaries for the given (r,g,b)-triplet. Each box
+ covers eight cache slots (32 colour values, that is). */
+
+ r0 = r & 0xe0;
+ r1 = r0 + 0x1f;
+ rc = (r0 + r1) / 2;
+ g0 = g & 0xe0;
+ g1 = g0 + 0x1f;
+ gc = (g0 + g1) / 2;
+ b0 = b & 0xe0;
+ b1 = b0 + 0x1f;
+ bc = (b0 + b1) / 2;
+
+ /* Step 1 -- Select relevant palette entries (after Heckbert) */
+
+ /* For each palette entry, calculate the min and max distances to
+ * any position in the box given by the colour we're looking for. */
+
+ dmax = (unsigned int)~0;
+
+ for (i = 0; i < palette->size; i++) {
+ int r, g, b;
+ unsigned int tmin, tmax;
+
+ /* Find min and max distances to any point in the box */
+ r = palette->palette[i * 4 + 0];
+ tmin = (r < r0) ? RDIST(r, r0) : (r > r1) ? RDIST(r, r1) : 0;
+ tmax = (r <= rc) ? RDIST(r, r1) : RDIST(r, r0);
+
+ g = palette->palette[i * 4 + 1];
+ tmin += (g < g0) ? GDIST(g, g0) : (g > g1) ? GDIST(g, g1) : 0;
+ tmax += (g <= gc) ? GDIST(g, g1) : GDIST(g, g0);
+
+ b = palette->palette[i * 4 + 2];
+ tmin += (b < b0) ? BDIST(b, b0) : (b > b1) ? BDIST(b, b1) : 0;
+ tmax += (b <= bc) ? BDIST(b, b1) : BDIST(b, b0);
+
+ dmin[i] = tmin;
+ if (tmax < dmax) {
+ dmax = tmax; /* keep the smallest max distance only */
+ }
+ }
+
+ /* Step 2 -- Incrementally update cache slot (after Thomas) */
+
+ /* Find the box containing the nearest palette entry, and update
+ * all slots in that box. We only check boxes for which the min
+ * distance is less than or equal the smallest max distance */
+
+ for (i = 0; i < BOXVOLUME; i++) {
+ d[i] = (unsigned int)~0;
+ }
+
+ for (i = 0; i < palette->size; i++) {
+ if (dmin[i] <= dmax) {
+ int rd, gd, bd;
+ int ri, gi, bi;
+ int rx, gx, bx;
+
+ ri = (r0 - palette->palette[i * 4 + 0]) * RSCALE;
+ gi = (g0 - palette->palette[i * 4 + 1]) * GSCALE;
+ bi = (b0 - palette->palette[i * 4 + 2]) * BSCALE;
+
+ rd = ri * ri + gi * gi + bi * bi;
+
+ ri = ri * (2 * RSTEP) + RSTEP * RSTEP;
+ gi = gi * (2 * GSTEP) + GSTEP * GSTEP;
+ bi = bi * (2 * BSTEP) + BSTEP * BSTEP;
+
+ rx = ri;
+ for (r = j = 0; r < BOX; r++) {
+ gd = rd;
+ gx = gi;
+ for (g = 0; g < BOX; g++) {
+ bd = gd;
+ bx = bi;
+ for (b = 0; b < BOX; b++) {
+ if ((unsigned int)bd < d[j]) {
+ d[j] = bd;
+ c[j] = (UINT8)i;
+ }
+ bd += bx;
+ bx += 2 * BSTEP * BSTEP;
+ j++;
+ }
+ gd += gx;
+ gx += 2 * GSTEP * GSTEP;
+ }
+ rd += rx;
+ rx += 2 * RSTEP * RSTEP;
+ }
+ }
+ }
+
+ /* Step 3 -- Update cache */
+
+ /* The c array now contains the closest match for each
+ * cache slot in the box. Update the cache. */
+
+ j = 0;
+ for (r = r0; r < r1; r += 4) {
+ for (g = g0; g < g1; g += 4) {
+ for (b = b0; b < b1; b += 4) {
+ ImagingPaletteCache(palette, r, g, b) = c[j++];
+ }
+ }
+ }
+}
+
+int
+ImagingPaletteCachePrepare(ImagingPalette palette) {
+ /* Add a colour cache to a palette */
+
+ int i;
+ int entries = 64 * 64 * 64;
+
+ if (palette->cache == NULL) {
+ /* The cache is 512k. It might be a good idea to break it
+ up into a pointer array (e.g. an 8-bit image?) */
+
+ /* malloc check ok, small constant allocation */
+ palette->cache = (INT16 *)malloc(entries * sizeof(INT16));
+ if (!palette->cache) {
+ (void)ImagingError_MemoryError();
+ return -1;
+ }
+
+ /* Mark all entries as empty */
+ for (i = 0; i < entries; i++) {
+ palette->cache[i] = 0x100;
+ }
+ }
+
+ return 0;
+}
+
+void
+ImagingPaletteCacheDelete(ImagingPalette palette) {
+ /* Release the colour cache, if any */
+
+ if (palette && palette->cache) {
+ free(palette->cache);
+ palette->cache = NULL;
+ }
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Paste.c b/contrib/python/Pillow/py3/libImaging/Paste.c
new file mode 100644
index 00000000000..6684b11efe3
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Paste.c
@@ -0,0 +1,628 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * paste image on another image
+ *
+ * history:
+ * 96-03-27 fl Created
+ * 96-07-16 fl Support "1", "L" and "RGBA" masks
+ * 96-08-16 fl Merged with opaque paste
+ * 97-01-17 fl Faster blending, added support for RGBa images
+ * 97-08-27 fl Faster masking for 32-bit images
+ * 98-02-02 fl Fixed MULDIV255 macro for gcc
+ * 99-02-02 fl Added "RGBa" mask support
+ * 99-02-06 fl Rewritten. Added support for masked fill operations.
+ * 99-12-08 fl Fixed matte fill.
+ *
+ * Copyright (c) Fredrik Lundh 1996-97.
+ * Copyright (c) Secret Labs AB 1997-99.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+static inline void
+paste(
+ Imaging imOut,
+ Imaging imIn,
+ int dx,
+ int dy,
+ int sx,
+ int sy,
+ int xsize,
+ int ysize,
+ int pixelsize) {
+ /* paste opaque region */
+
+ int y;
+
+ dx *= pixelsize;
+ sx *= pixelsize;
+
+ xsize *= pixelsize;
+
+ for (y = 0; y < ysize; y++) {
+ memcpy(imOut->image[y + dy] + dx, imIn->image[y + sy] + sx, xsize);
+ }
+}
+
+static inline void
+paste_mask_1(
+ Imaging imOut,
+ Imaging imIn,
+ Imaging imMask,
+ int dx,
+ int dy,
+ int sx,
+ int sy,
+ int xsize,
+ int ysize,
+ int pixelsize) {
+ /* paste with mode "1" mask */
+
+ int x, y;
+
+ if (imOut->image8) {
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = imOut->image8[y + dy] + dx;
+ UINT8 *in = imIn->image8[y + sy] + sx;
+ UINT8 *mask = imMask->image8[y + sy] + sx;
+ for (x = 0; x < xsize; x++) {
+ if (*mask++) {
+ *out = *in;
+ }
+ out++, in++;
+ }
+ }
+
+ } else {
+ for (y = 0; y < ysize; y++) {
+ INT32 *out = imOut->image32[y + dy] + dx;
+ INT32 *in = imIn->image32[y + sy] + sx;
+ UINT8 *mask = imMask->image8[y + sy] + sx;
+ for (x = 0; x < xsize; x++) {
+ if (*mask++) {
+ *out = *in;
+ }
+ out++, in++;
+ }
+ }
+ }
+}
+
+static inline void
+paste_mask_L(
+ Imaging imOut,
+ Imaging imIn,
+ Imaging imMask,
+ int dx,
+ int dy,
+ int sx,
+ int sy,
+ int xsize,
+ int ysize,
+ int pixelsize) {
+ /* paste with mode "L" matte */
+
+ int x, y;
+ unsigned int tmp1;
+
+ if (imOut->image8) {
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = imOut->image8[y + dy] + dx;
+ UINT8 *in = imIn->image8[y + sy] + sx;
+ UINT8 *mask = imMask->image8[y + sy] + sx;
+ for (x = 0; x < xsize; x++) {
+ *out = BLEND(*mask, *out, *in, tmp1);
+ out++, in++, mask++;
+ }
+ }
+
+ } else {
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = (UINT8 *)(imOut->image32[y + dy] + dx);
+ UINT8 *in = (UINT8 *)(imIn->image32[y + sy] + sx);
+ UINT8 *mask = (UINT8 *)(imMask->image8[y + sy] + sx);
+ for (x = 0; x < xsize; x++) {
+ UINT8 a = mask[0];
+ out[0] = BLEND(a, out[0], in[0], tmp1);
+ out[1] = BLEND(a, out[1], in[1], tmp1);
+ out[2] = BLEND(a, out[2], in[2], tmp1);
+ out[3] = BLEND(a, out[3], in[3], tmp1);
+ out += 4;
+ in += 4;
+ mask++;
+ }
+ }
+ }
+}
+
+static inline void
+paste_mask_RGBA(
+ Imaging imOut,
+ Imaging imIn,
+ Imaging imMask,
+ int dx,
+ int dy,
+ int sx,
+ int sy,
+ int xsize,
+ int ysize,
+ int pixelsize) {
+ /* paste with mode "RGBA" matte */
+
+ int x, y;
+ unsigned int tmp1;
+
+ if (imOut->image8) {
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = imOut->image8[y + dy] + dx;
+ UINT8 *in = imIn->image8[y + sy] + sx;
+ UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx * 4 + 3;
+ for (x = 0; x < xsize; x++) {
+ *out = BLEND(*mask, *out, *in, tmp1);
+ out++, in++, mask += 4;
+ }
+ }
+
+ } else {
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = (UINT8 *)(imOut->image32[y + dy] + dx);
+ UINT8 *in = (UINT8 *)(imIn->image32[y + sy] + sx);
+ UINT8 *mask = (UINT8 *)(imMask->image32[y + sy] + sx);
+ for (x = 0; x < xsize; x++) {
+ UINT8 a = mask[3];
+ out[0] = BLEND(a, out[0], in[0], tmp1);
+ out[1] = BLEND(a, out[1], in[1], tmp1);
+ out[2] = BLEND(a, out[2], in[2], tmp1);
+ out[3] = BLEND(a, out[3], in[3], tmp1);
+ out += 4;
+ in += 4;
+ mask += 4;
+ }
+ }
+ }
+}
+
+static inline void
+paste_mask_RGBa(
+ Imaging imOut,
+ Imaging imIn,
+ Imaging imMask,
+ int dx,
+ int dy,
+ int sx,
+ int sy,
+ int xsize,
+ int ysize,
+ int pixelsize) {
+ /* paste with mode "RGBa" matte */
+
+ int x, y;
+ unsigned int tmp1;
+
+ if (imOut->image8) {
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = imOut->image8[y + dy] + dx;
+ UINT8 *in = imIn->image8[y + sy] + sx;
+ UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx * 4 + 3;
+ for (x = 0; x < xsize; x++) {
+ *out = PREBLEND(*mask, *out, *in, tmp1);
+ out++, in++, mask += 4;
+ }
+ }
+
+ } else {
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = (UINT8 *)(imOut->image32[y + dy] + dx);
+ UINT8 *in = (UINT8 *)(imIn->image32[y + sy] + sx);
+ UINT8 *mask = (UINT8 *)(imMask->image32[y + sy] + sx);
+ for (x = 0; x < xsize; x++) {
+ UINT8 a = mask[3];
+ out[0] = PREBLEND(a, out[0], in[0], tmp1);
+ out[1] = PREBLEND(a, out[1], in[1], tmp1);
+ out[2] = PREBLEND(a, out[2], in[2], tmp1);
+ out[3] = PREBLEND(a, out[3], in[3], tmp1);
+ out += 4;
+ in += 4;
+ mask += 4;
+ }
+ }
+ }
+}
+
+int
+ImagingPaste(
+ Imaging imOut, Imaging imIn, Imaging imMask, int dx0, int dy0, int dx1, int dy1) {
+ int xsize, ysize;
+ int pixelsize;
+ int sx0, sy0;
+ ImagingSectionCookie cookie;
+
+ if (!imOut || !imIn) {
+ (void)ImagingError_ModeError();
+ return -1;
+ }
+
+ pixelsize = imOut->pixelsize;
+
+ xsize = dx1 - dx0;
+ ysize = dy1 - dy0;
+
+ if (xsize != imIn->xsize || ysize != imIn->ysize || pixelsize != imIn->pixelsize) {
+ (void)ImagingError_Mismatch();
+ return -1;
+ }
+
+ if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) {
+ (void)ImagingError_Mismatch();
+ return -1;
+ }
+
+ /* Determine which region to copy */
+ sx0 = sy0 = 0;
+ if (dx0 < 0) {
+ xsize += dx0, sx0 = -dx0, dx0 = 0;
+ }
+ if (dx0 + xsize > imOut->xsize) {
+ xsize = imOut->xsize - dx0;
+ }
+ if (dy0 < 0) {
+ ysize += dy0, sy0 = -dy0, dy0 = 0;
+ }
+ if (dy0 + ysize > imOut->ysize) {
+ ysize = imOut->ysize - dy0;
+ }
+
+ if (xsize <= 0 || ysize <= 0) {
+ return 0;
+ }
+
+ if (!imMask) {
+ ImagingSectionEnter(&cookie);
+ paste(imOut, imIn, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "1") == 0) {
+ ImagingSectionEnter(&cookie);
+ paste_mask_1(imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "L") == 0) {
+ ImagingSectionEnter(&cookie);
+ paste_mask_L(imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "LA") == 0 || strcmp(imMask->mode, "RGBA") == 0) {
+ ImagingSectionEnter(&cookie);
+ paste_mask_RGBA(
+ imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "RGBa") == 0) {
+ ImagingSectionEnter(&cookie);
+ paste_mask_RGBa(
+ imOut, imIn, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else {
+ (void)ImagingError_ValueError("bad transparency mask");
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline void
+fill(
+ Imaging imOut,
+ const void *ink_,
+ int dx,
+ int dy,
+ int xsize,
+ int ysize,
+ int pixelsize) {
+ /* fill opaque region */
+
+ int x, y;
+ UINT8 ink8 = 0;
+ INT32 ink32 = 0L;
+
+ memcpy(&ink32, ink_, pixelsize);
+ memcpy(&ink8, ink_, sizeof(ink8));
+
+ if (imOut->image8 || ink32 == 0L) {
+ dx *= pixelsize;
+ xsize *= pixelsize;
+ for (y = 0; y < ysize; y++) {
+ memset(imOut->image[y + dy] + dx, ink8, xsize);
+ }
+
+ } else {
+ for (y = 0; y < ysize; y++) {
+ INT32 *out = imOut->image32[y + dy] + dx;
+ for (x = 0; x < xsize; x++) {
+ out[x] = ink32;
+ }
+ }
+ }
+}
+
+static inline void
+fill_mask_1(
+ Imaging imOut,
+ const void *ink_,
+ Imaging imMask,
+ int dx,
+ int dy,
+ int sx,
+ int sy,
+ int xsize,
+ int ysize,
+ int pixelsize) {
+ /* fill with mode "1" mask */
+
+ int x, y;
+ UINT8 ink8 = 0;
+ INT32 ink32 = 0L;
+
+ memcpy(&ink32, ink_, pixelsize);
+ memcpy(&ink8, ink_, sizeof(ink8));
+
+ if (imOut->image8) {
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = imOut->image8[y + dy] + dx;
+ UINT8 *mask = imMask->image8[y + sy] + sx;
+ for (x = 0; x < xsize; x++) {
+ if (*mask++) {
+ *out = ink8;
+ }
+ out++;
+ }
+ }
+
+ } else {
+ for (y = 0; y < ysize; y++) {
+ INT32 *out = imOut->image32[y + dy] + dx;
+ UINT8 *mask = imMask->image8[y + sy] + sx;
+ for (x = 0; x < xsize; x++) {
+ if (*mask++) {
+ *out = ink32;
+ }
+ out++;
+ }
+ }
+ }
+}
+
+static inline void
+fill_mask_L(
+ Imaging imOut,
+ const UINT8 *ink,
+ Imaging imMask,
+ int dx,
+ int dy,
+ int sx,
+ int sy,
+ int xsize,
+ int ysize,
+ int pixelsize) {
+ /* fill with mode "L" matte */
+
+ int x, y, i;
+ unsigned int tmp1;
+
+ if (imOut->image8) {
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = imOut->image8[y + dy] + dx;
+ if (strncmp(imOut->mode, "I;16", 4) == 0) {
+ out += dx;
+ }
+ UINT8 *mask = imMask->image8[y + sy] + sx;
+ for (x = 0; x < xsize; x++) {
+ *out = BLEND(*mask, *out, ink[0], tmp1);
+ if (strncmp(imOut->mode, "I;16", 4) == 0) {
+ out++;
+ *out = BLEND(*mask, *out, ink[1], tmp1);
+ }
+ out++, mask++;
+ }
+ }
+
+ } else {
+ int alpha_channel = strcmp(imOut->mode, "RGBa") == 0 ||
+ strcmp(imOut->mode, "RGBA") == 0 ||
+ strcmp(imOut->mode, "La") == 0 ||
+ strcmp(imOut->mode, "LA") == 0 ||
+ strcmp(imOut->mode, "PA") == 0;
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = (UINT8 *)imOut->image[y + dy] + dx * pixelsize;
+ UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx;
+ for (x = 0; x < xsize; x++) {
+ for (i = 0; i < pixelsize; i++) {
+ UINT8 channel_mask = *mask;
+ if (alpha_channel && i != 3 && channel_mask != 0) {
+ channel_mask =
+ 255 - (255 - channel_mask) * (1 - (255 - out[3]) / 255);
+ }
+ out[i] = BLEND(channel_mask, out[i], ink[i], tmp1);
+ }
+ out += pixelsize;
+ mask++;
+ }
+ }
+ }
+}
+
+static inline void
+fill_mask_RGBA(
+ Imaging imOut,
+ const UINT8 *ink,
+ Imaging imMask,
+ int dx,
+ int dy,
+ int sx,
+ int sy,
+ int xsize,
+ int ysize,
+ int pixelsize) {
+ /* fill with mode "RGBA" matte */
+
+ int x, y, i;
+ unsigned int tmp1;
+
+ if (imOut->image8) {
+ sx = sx * 4 + 3;
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = imOut->image8[y + dy] + dx;
+ UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx;
+ for (x = 0; x < xsize; x++) {
+ *out = BLEND(*mask, *out, ink[0], tmp1);
+ out++, mask += 4;
+ }
+ }
+
+ } else {
+ dx *= pixelsize;
+ sx = sx * 4 + 3;
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = (UINT8 *)imOut->image[y + dy] + dx;
+ UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx;
+ for (x = 0; x < xsize; x++) {
+ for (i = 0; i < pixelsize; i++) {
+ *out = BLEND(*mask, *out, ink[i], tmp1);
+ out++;
+ }
+ mask += 4;
+ }
+ }
+ }
+}
+
+static inline void
+fill_mask_RGBa(
+ Imaging imOut,
+ const UINT8 *ink,
+ Imaging imMask,
+ int dx,
+ int dy,
+ int sx,
+ int sy,
+ int xsize,
+ int ysize,
+ int pixelsize) {
+ /* fill with mode "RGBa" matte */
+
+ int x, y, i;
+ unsigned int tmp1;
+
+ if (imOut->image8) {
+ sx = sx * 4 + 3;
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = imOut->image8[y + dy] + dx;
+ UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx;
+ for (x = 0; x < xsize; x++) {
+ *out = PREBLEND(*mask, *out, ink[0], tmp1);
+ out++, mask += 4;
+ }
+ }
+
+ } else {
+ dx *= pixelsize;
+ sx = sx * 4 + 3;
+ for (y = 0; y < ysize; y++) {
+ UINT8 *out = (UINT8 *)imOut->image[y + dy] + dx;
+ UINT8 *mask = (UINT8 *)imMask->image[y + sy] + sx;
+ for (x = 0; x < xsize; x++) {
+ for (i = 0; i < pixelsize; i++) {
+ *out = PREBLEND(*mask, *out, ink[i], tmp1);
+ out++;
+ }
+ mask += 4;
+ }
+ }
+ }
+}
+
+int
+ImagingFill2(
+ Imaging imOut,
+ const void *ink,
+ Imaging imMask,
+ int dx0,
+ int dy0,
+ int dx1,
+ int dy1) {
+ ImagingSectionCookie cookie;
+ int xsize, ysize;
+ int pixelsize;
+ int sx0, sy0;
+
+ if (!imOut || !ink) {
+ (void)ImagingError_ModeError();
+ return -1;
+ }
+
+ pixelsize = imOut->pixelsize;
+
+ xsize = dx1 - dx0;
+ ysize = dy1 - dy0;
+
+ if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) {
+ (void)ImagingError_Mismatch();
+ return -1;
+ }
+
+ /* Determine which region to fill */
+ sx0 = sy0 = 0;
+ if (dx0 < 0) {
+ xsize += dx0, sx0 = -dx0, dx0 = 0;
+ }
+ if (dx0 + xsize > imOut->xsize) {
+ xsize = imOut->xsize - dx0;
+ }
+ if (dy0 < 0) {
+ ysize += dy0, sy0 = -dy0, dy0 = 0;
+ }
+ if (dy0 + ysize > imOut->ysize) {
+ ysize = imOut->ysize - dy0;
+ }
+
+ if (xsize <= 0 || ysize <= 0) {
+ return 0;
+ }
+
+ if (!imMask) {
+ ImagingSectionEnter(&cookie);
+ fill(imOut, ink, dx0, dy0, xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "1") == 0) {
+ ImagingSectionEnter(&cookie);
+ fill_mask_1(imOut, ink, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "L") == 0) {
+ ImagingSectionEnter(&cookie);
+ fill_mask_L(imOut, ink, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "RGBA") == 0) {
+ ImagingSectionEnter(&cookie);
+ fill_mask_RGBA(imOut, ink, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else if (strcmp(imMask->mode, "RGBa") == 0) {
+ ImagingSectionEnter(&cookie);
+ fill_mask_RGBa(imOut, ink, imMask, dx0, dy0, sx0, sy0, xsize, ysize, pixelsize);
+ ImagingSectionLeave(&cookie);
+
+ } else {
+ (void)ImagingError_ValueError("bad transparency mask");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/PcdDecode.c b/contrib/python/Pillow/py3/libImaging/PcdDecode.c
new file mode 100644
index 00000000000..f13803cb688
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/PcdDecode.c
@@ -0,0 +1,74 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for uncompressed PCD image data.
+ *
+ * history:
+ * 96-05-10 fl Created
+ * 96-05-18 fl New tables
+ * 97-01-25 fl Use PhotoYCC unpacker
+ *
+ * notes:
+ * This driver supports uncompressed PCD modes only
+ * (resolutions up to 768x512).
+ *
+ * Copyright (c) Fredrik Lundh 1996-97.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+int
+ImagingPcdDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ int x;
+ int chunk;
+ UINT8 *out;
+ UINT8 *ptr;
+
+ ptr = buf;
+
+ chunk = 3 * state->xsize;
+
+ for (;;) {
+ /* We need data for two full lines before we can do anything */
+ if (bytes < chunk) {
+ return ptr - buf;
+ }
+
+ /* Unpack first line */
+ out = state->buffer;
+ for (x = 0; x < state->xsize; x++) {
+ out[0] = ptr[x];
+ out[1] = ptr[(x + 4 * state->xsize) / 2];
+ out[2] = ptr[(x + 5 * state->xsize) / 2];
+ out += 3;
+ }
+
+ state->shuffle((UINT8 *)im->image[state->y], state->buffer, state->xsize);
+
+ if (++state->y >= state->ysize) {
+ return -1; /* This can hardly happen */
+ }
+
+ /* Unpack second line */
+ out = state->buffer;
+ for (x = 0; x < state->xsize; x++) {
+ out[0] = ptr[x + state->xsize];
+ out[1] = ptr[(x + 4 * state->xsize) / 2];
+ out[2] = ptr[(x + 5 * state->xsize) / 2];
+ out += 3;
+ }
+
+ state->shuffle((UINT8 *)im->image[state->y], state->buffer, state->xsize);
+
+ if (++state->y >= state->ysize) {
+ return -1;
+ }
+
+ ptr += chunk;
+ bytes -= chunk;
+ }
+}
diff --git a/contrib/python/Pillow/py3/libImaging/PcxDecode.c b/contrib/python/Pillow/py3/libImaging/PcxDecode.c
new file mode 100644
index 00000000000..c95ffc8692c
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/PcxDecode.c
@@ -0,0 +1,89 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for PCX image data.
+ *
+ * history:
+ * 95-09-14 fl Created
+ *
+ * Copyright (c) Fredrik Lundh 1995.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+int
+ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ UINT8 n;
+ UINT8 *ptr;
+
+ if ((state->xsize * state->bits + 7) / 8 > state->bytes) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+
+ ptr = buf;
+
+ for (;;) {
+ if (bytes < 1) {
+ return ptr - buf;
+ }
+
+ if ((*ptr & 0xC0) == 0xC0) {
+ /* Run */
+ if (bytes < 2) {
+ return ptr - buf;
+ }
+
+ n = ptr[0] & 0x3F;
+
+ while (n > 0) {
+ if (state->x >= state->bytes) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ break;
+ }
+ state->buffer[state->x++] = ptr[1];
+ n--;
+ }
+
+ ptr += 2;
+ bytes -= 2;
+
+ } else {
+ /* Literal */
+ state->buffer[state->x++] = ptr[0];
+ ptr++;
+ bytes--;
+ }
+
+ if (state->x >= state->bytes) {
+ if (state->bytes % state->xsize && state->bytes > state->xsize) {
+ int bands = state->bytes / state->xsize;
+ int stride = state->bytes / bands;
+ int i;
+ for (i = 1; i < bands; i++) { // note -- skipping first band
+ memmove(
+ &state->buffer[i * state->xsize],
+ &state->buffer[i * stride],
+ state->xsize);
+ }
+ }
+ /* Got a full line, unpack it */
+ state->shuffle(
+ (UINT8 *)im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->buffer,
+ state->xsize);
+
+ state->x = 0;
+
+ if (++state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+ }
+ }
+}
diff --git a/contrib/python/Pillow/py3/libImaging/PcxEncode.c b/contrib/python/Pillow/py3/libImaging/PcxEncode.c
new file mode 100644
index 00000000000..549614bfd39
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/PcxEncode.c
@@ -0,0 +1,187 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * encoder for PCX data
+ *
+ * history:
+ * 99-02-07 fl created
+ *
+ * Copyright (c) Fredrik Lundh 1999.
+ * Copyright (c) Secret Labs AB 1999.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+enum { INIT, FETCH, ENCODE };
+
+/* we're reusing "ystep" to store the last value */
+#define LAST ystep
+
+int
+ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
+ UINT8 *ptr;
+ int this;
+ int bytes_per_line = 0;
+ int padding = 0;
+ int stride = 0;
+ int bpp = 0;
+ int planes = 1;
+ int i;
+
+ ptr = buf;
+
+ if (!state->state) {
+ /* sanity check */
+ if (state->xsize <= 0 || state->ysize <= 0) {
+ state->errcode = IMAGING_CODEC_END;
+ return 0;
+ }
+ state->state = FETCH;
+ }
+
+ bpp = state->bits;
+ if (state->bits == 24) {
+ planes = 3;
+ bpp = 8;
+ }
+
+ bytes_per_line = (state->xsize * bpp + 7) / 8;
+ /* The stride here needs to be kept in sync with the version in
+ PcxImagePlugin.py. If it's not, the header and the body of the
+ image will be out of sync and bad things will happen on decode.
+ */
+ stride = bytes_per_line + (bytes_per_line % 2);
+
+ padding = stride - bytes_per_line;
+
+ for (;;) {
+ switch (state->state) {
+ case FETCH:
+
+ /* get a line of data */
+ if (state->y >= state->ysize) {
+ state->errcode = IMAGING_CODEC_END;
+ return ptr - buf;
+ }
+
+ state->shuffle(
+ state->buffer,
+ (UINT8 *)im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->xsize);
+
+ state->y += 1;
+
+ state->count = 1;
+ state->LAST = state->buffer[0];
+
+ state->x = 1;
+
+ state->state = ENCODE;
+ /* fall through */
+
+ case ENCODE:
+ /* compress this line */
+
+ /* when we arrive here, "count" contains the number of
+ bytes having the value of "LAST" that we've already
+ seen */
+ do {
+ /* If we're encoding an odd width file, and we've
+ got more than one plane, we need to pad each
+ color row with padding bytes at the end. Since
+ The pixels are stored RRRRRGGGGGBBBBB, so we need
+ to have the padding be RRRRRPGGGGGPBBBBBP. Hence
+ the double loop
+ */
+ while (state->x % bytes_per_line) {
+ if (state->count == 63) {
+ /* this run is full; flush it */
+ if (bytes < 2) {
+ return ptr - buf;
+ }
+ ptr[0] = 0xff;
+ ptr[1] = state->LAST;
+ ptr += 2;
+ bytes -= 2;
+
+ state->count = 0;
+ }
+
+ this = state->buffer[state->x];
+
+ if (this == state->LAST) {
+ /* extend the current run */
+ state->x += 1;
+ state->count += 1;
+
+ } else {
+ /* start a new run */
+ if (state->count == 1 && (state->LAST < 0xc0)) {
+ if (bytes < 1) {
+ return ptr - buf;
+ }
+ ptr[0] = state->LAST;
+ ptr += 1;
+ bytes -= 1;
+ } else {
+ if (state->count > 0) {
+ if (bytes < 2) {
+ return ptr - buf;
+ }
+ ptr[0] = 0xc0 | state->count;
+ ptr[1] = state->LAST;
+ ptr += 2;
+ bytes -= 2;
+ }
+ }
+
+ state->LAST = this;
+ state->count = 1;
+
+ state->x += 1;
+ }
+ }
+
+ /* end of line; flush the current run */
+ if (state->count == 1 && (state->LAST < 0xc0)) {
+ if (bytes < 1 + padding) {
+ return ptr - buf;
+ }
+ ptr[0] = state->LAST;
+ ptr += 1;
+ bytes -= 1;
+ } else {
+ if (state->count > 0) {
+ if (bytes < 2 + padding) {
+ return ptr - buf;
+ }
+ ptr[0] = 0xc0 | state->count;
+ ptr[1] = state->LAST;
+ ptr += 2;
+ bytes -= 2;
+ }
+ }
+ /* add the padding */
+ for (i = 0; i < padding; i++) {
+ ptr[0] = 0;
+ ptr += 1;
+ bytes -= 1;
+ }
+ /* reset for the next color plane. */
+ if (state->x < planes * bytes_per_line) {
+ state->count = 1;
+ state->LAST = state->buffer[state->x];
+ state->x += 1;
+ }
+ } while (state->x < planes * bytes_per_line);
+
+ /* read next line */
+ state->state = FETCH;
+ break;
+ }
+ }
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Point.c b/contrib/python/Pillow/py3/libImaging/Point.c
new file mode 100644
index 00000000000..8883578cbff
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Point.c
@@ -0,0 +1,270 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * point (pixel) translation
+ *
+ * history:
+ * 1995-11-27 fl Created
+ * 1996-03-31 fl Fixed colour support
+ * 1996-08-13 fl Support 8-bit to "1" thresholding
+ * 1997-05-31 fl Added floating point transform
+ * 1998-07-02 fl Added integer point transform
+ * 1998-07-17 fl Support L to anything lookup
+ * 2004-12-18 fl Refactored; added I to L lookup
+ *
+ * Copyright (c) 1997-2004 by Secret Labs AB.
+ * Copyright (c) 1995-2004 by Fredrik Lundh.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+typedef struct {
+ const void *table;
+} im_point_context;
+
+static void
+im_point_8_8(Imaging imOut, Imaging imIn, im_point_context *context) {
+ int x, y;
+ /* 8-bit source, 8-bit destination */
+ UINT8 *table = (UINT8 *)context->table;
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8 *in = imIn->image8[y];
+ UINT8 *out = imOut->image8[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ out[x] = table[in[x]];
+ }
+ }
+}
+
+static void
+im_point_2x8_2x8(Imaging imOut, Imaging imIn, im_point_context *context) {
+ int x, y;
+ /* 2x8-bit source, 2x8-bit destination */
+ UINT8 *table = (UINT8 *)context->table;
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8 *in = (UINT8 *)imIn->image[y];
+ UINT8 *out = (UINT8 *)imOut->image[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ out[0] = table[in[0]];
+ out[3] = table[in[3] + 256];
+ in += 4;
+ out += 4;
+ }
+ }
+}
+
+static void
+im_point_3x8_3x8(Imaging imOut, Imaging imIn, im_point_context *context) {
+ int x, y;
+ /* 3x8-bit source, 3x8-bit destination */
+ UINT8 *table = (UINT8 *)context->table;
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8 *in = (UINT8 *)imIn->image[y];
+ UINT8 *out = (UINT8 *)imOut->image[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ out[0] = table[in[0]];
+ out[1] = table[in[1] + 256];
+ out[2] = table[in[2] + 512];
+ in += 4;
+ out += 4;
+ }
+ }
+}
+
+static void
+im_point_4x8_4x8(Imaging imOut, Imaging imIn, im_point_context *context) {
+ int x, y;
+ /* 4x8-bit source, 4x8-bit destination */
+ UINT8 *table = (UINT8 *)context->table;
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8 *in = (UINT8 *)imIn->image[y];
+ UINT8 *out = (UINT8 *)imOut->image[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ out[0] = table[in[0]];
+ out[1] = table[in[1] + 256];
+ out[2] = table[in[2] + 512];
+ out[3] = table[in[3] + 768];
+ in += 4;
+ out += 4;
+ }
+ }
+}
+
+static void
+im_point_8_32(Imaging imOut, Imaging imIn, im_point_context *context) {
+ int x, y;
+ /* 8-bit source, 32-bit destination */
+ char *table = (char *)context->table;
+ for (y = 0; y < imIn->ysize; y++) {
+ UINT8 *in = imIn->image8[y];
+ INT32 *out = imOut->image32[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ memcpy(out + x, table + in[x] * sizeof(INT32), sizeof(INT32));
+ }
+ }
+}
+
+static void
+im_point_32_8(Imaging imOut, Imaging imIn, im_point_context *context) {
+ int x, y;
+ /* 32-bit source, 8-bit destination */
+ UINT8 *table = (UINT8 *)context->table;
+ for (y = 0; y < imIn->ysize; y++) {
+ INT32 *in = imIn->image32[y];
+ UINT8 *out = imOut->image8[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ int v = in[x];
+ if (v < 0) {
+ v = 0;
+ } else if (v > 65535) {
+ v = 65535;
+ }
+ out[x] = table[v];
+ }
+ }
+}
+
+Imaging
+ImagingPoint(Imaging imIn, const char *mode, const void *table) {
+ /* lookup table transform */
+
+ ImagingSectionCookie cookie;
+ Imaging imOut;
+ im_point_context context;
+ void (*point)(Imaging imIn, Imaging imOut, im_point_context * context);
+
+ if (!imIn) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ if (!mode) {
+ mode = imIn->mode;
+ }
+
+ if (imIn->type != IMAGING_TYPE_UINT8) {
+ if (imIn->type != IMAGING_TYPE_INT32 || strcmp(mode, "L") != 0) {
+ goto mode_mismatch;
+ }
+ } else if (!imIn->image8 && strcmp(imIn->mode, mode) != 0) {
+ goto mode_mismatch;
+ }
+
+ imOut = ImagingNew(mode, imIn->xsize, imIn->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ /* find appropriate handler */
+ if (imIn->type == IMAGING_TYPE_UINT8) {
+ if (imIn->bands == imOut->bands && imIn->type == imOut->type) {
+ switch (imIn->bands) {
+ case 1:
+ point = im_point_8_8;
+ break;
+ case 2:
+ point = im_point_2x8_2x8;
+ break;
+ case 3:
+ point = im_point_3x8_3x8;
+ break;
+ case 4:
+ point = im_point_4x8_4x8;
+ break;
+ default:
+ /* this cannot really happen */
+ point = im_point_8_8;
+ break;
+ }
+ } else {
+ point = im_point_8_32;
+ }
+ } else {
+ point = im_point_32_8;
+ }
+
+ ImagingCopyPalette(imOut, imIn);
+
+ ImagingSectionEnter(&cookie);
+
+ context.table = table;
+ point(imOut, imIn, &context);
+
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+
+mode_mismatch:
+ return (Imaging)ImagingError_ValueError(
+ "point operation not supported for this mode");
+}
+
+Imaging
+ImagingPointTransform(Imaging imIn, double scale, double offset) {
+ /* scale/offset transform */
+
+ ImagingSectionCookie cookie;
+ Imaging imOut;
+ int x, y;
+
+ if (!imIn || (strcmp(imIn->mode, "I") != 0 && strcmp(imIn->mode, "I;16") != 0 &&
+ strcmp(imIn->mode, "F") != 0)) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+
+ switch (imIn->type) {
+ case IMAGING_TYPE_INT32:
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ INT32 *in = imIn->image32[y];
+ INT32 *out = imOut->image32[y];
+ /* FIXME: add clipping? */
+ for (x = 0; x < imIn->xsize; x++) {
+ out[x] = in[x] * scale + offset;
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ break;
+ case IMAGING_TYPE_FLOAT32:
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ FLOAT32 *in = (FLOAT32 *)imIn->image32[y];
+ FLOAT32 *out = (FLOAT32 *)imOut->image32[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ out[x] = in[x] * scale + offset;
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ break;
+ case IMAGING_TYPE_SPECIAL:
+ if (strcmp(imIn->mode, "I;16") == 0) {
+ ImagingSectionEnter(&cookie);
+ for (y = 0; y < imIn->ysize; y++) {
+ char *in = (char *)imIn->image[y];
+ char *out = (char *)imOut->image[y];
+ /* FIXME: add clipping? */
+ for (x = 0; x < imIn->xsize; x++) {
+ UINT16 v;
+ memcpy(&v, in + x * sizeof(v), sizeof(v));
+ v = v * scale + offset;
+ memcpy(out + x * sizeof(UINT16), &v, sizeof(v));
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ break;
+ }
+ /* FALL THROUGH */
+ default:
+ ImagingDelete(imOut);
+ return (Imaging)ImagingError_ValueError("internal error");
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Quant.c b/contrib/python/Pillow/py3/libImaging/Quant.c
new file mode 100644
index 00000000000..c84acb99889
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Quant.c
@@ -0,0 +1,1859 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * image quantizer
+ *
+ * history:
+ * 1998-09-10 tjs Contributed
+ * 1998-12-29 fl Added to PIL 1.0b1
+ * 2004-02-21 fl Fixed bogus free() on quantization error
+ * 2005-02-07 fl Limit number of colors to 256
+ *
+ * Written by Toby J Sargeant <[email protected]>.
+ *
+ * Copyright (c) 1998 by Toby J Sargeant
+ * Copyright (c) 1998-2004 by Secret Labs AB. All rights reserved.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <time.h>
+
+#include "QuantTypes.h"
+#include "QuantOctree.h"
+#include "QuantPngQuant.h"
+#include "QuantHash.h"
+#include "QuantHeap.h"
+
+/* MSVC9.0 */
+#ifndef UINT32_MAX
+#define UINT32_MAX 0xffffffff
+#endif
+
+#define NO_OUTPUT
+
+typedef struct {
+ uint32_t scale;
+} PixelHashData;
+
+typedef struct _PixelList {
+ struct _PixelList *next[3], *prev[3];
+ Pixel p;
+ unsigned int flag : 1;
+ int count;
+} PixelList;
+
+typedef struct _BoxNode {
+ struct _BoxNode *l, *r;
+ PixelList *head[3], *tail[3];
+ int axis;
+ int volume;
+ uint32_t pixelCount;
+} BoxNode;
+
+#define _SQR(x) ((x) * (x))
+#define _DISTSQR(p1, p2) \
+ _SQR((int)((p1)->c.r) - (int)((p2)->c.r)) + \
+ _SQR((int)((p1)->c.g) - (int)((p2)->c.g)) + \
+ _SQR((int)((p1)->c.b) - (int)((p2)->c.b))
+
+#define MAX_HASH_ENTRIES 65536
+
+#define PIXEL_HASH(r, g, b) \
+ (((unsigned int)(r)) * 463 ^ ((unsigned int)(g) << 8) * 10069 ^ \
+ ((unsigned int)(b) << 16) * 64997)
+
+#define PIXEL_UNSCALE(p, q, s) \
+ ((q)->c.r = (p)->c.r << (s)), ((q)->c.g = (p)->c.g << (s)), \
+ ((q)->c.b = (p)->c.b << (s))
+
+#define PIXEL_SCALE(p, q, s) \
+ ((q)->c.r = (p)->c.r >> (s)), ((q)->c.g = (p)->c.g >> (s)), \
+ ((q)->c.b = (p)->c.b >> (s))
+
+static uint32_t
+unshifted_pixel_hash(const HashTable *h, const Pixel pixel) {
+ return PIXEL_HASH(pixel.c.r, pixel.c.g, pixel.c.b);
+}
+
+static int
+unshifted_pixel_cmp(const HashTable *h, const Pixel pixel1, const Pixel pixel2) {
+ if (pixel1.c.r == pixel2.c.r) {
+ if (pixel1.c.g == pixel2.c.g) {
+ if (pixel1.c.b == pixel2.c.b) {
+ return 0;
+ } else {
+ return (int)(pixel1.c.b) - (int)(pixel2.c.b);
+ }
+ } else {
+ return (int)(pixel1.c.g) - (int)(pixel2.c.g);
+ }
+ } else {
+ return (int)(pixel1.c.r) - (int)(pixel2.c.r);
+ }
+}
+
+static uint32_t
+pixel_hash(const HashTable *h, const Pixel pixel) {
+ PixelHashData *d = (PixelHashData *)hashtable_get_user_data(h);
+ return PIXEL_HASH(
+ pixel.c.r >> d->scale, pixel.c.g >> d->scale, pixel.c.b >> d->scale);
+}
+
+static int
+pixel_cmp(const HashTable *h, const Pixel pixel1, const Pixel pixel2) {
+ PixelHashData *d = (PixelHashData *)hashtable_get_user_data(h);
+ uint32_t A, B;
+ A = PIXEL_HASH(
+ pixel1.c.r >> d->scale, pixel1.c.g >> d->scale, pixel1.c.b >> d->scale);
+ B = PIXEL_HASH(
+ pixel2.c.r >> d->scale, pixel2.c.g >> d->scale, pixel2.c.b >> d->scale);
+ return (A == B) ? 0 : ((A < B) ? -1 : 1);
+}
+
+static void
+exists_count_func(const HashTable *h, const Pixel key, uint32_t *val) {
+ *val += 1;
+}
+
+static void
+new_count_func(const HashTable *h, const Pixel key, uint32_t *val) {
+ *val = 1;
+}
+
+static void
+rehash_collide(
+ const HashTable *h, Pixel *keyp, uint32_t *valp, Pixel newkey, uint32_t newval) {
+ *valp += newval;
+}
+
+/* %% */
+
+static HashTable *
+create_pixel_hash(Pixel *pixelData, uint32_t nPixels) {
+ PixelHashData *d;
+ HashTable *hash;
+ uint32_t i;
+#ifndef NO_OUTPUT
+ uint32_t timer, timer2, timer3;
+#endif
+
+ /* malloc check ok, small constant allocation */
+ d = malloc(sizeof(PixelHashData));
+ if (!d) {
+ return NULL;
+ }
+ hash = hashtable_new(pixel_hash, pixel_cmp);
+ hashtable_set_user_data(hash, d);
+ d->scale = 0;
+#ifndef NO_OUTPUT
+ timer = timer3 = clock();
+#endif
+ for (i = 0; i < nPixels; i++) {
+ if (!hashtable_insert_or_update_computed(
+ hash, pixelData[i], new_count_func, exists_count_func)) {
+ ;
+ }
+ while (hashtable_get_count(hash) > MAX_HASH_ENTRIES) {
+ d->scale++;
+#ifndef NO_OUTPUT
+ printf("rehashing - new scale: %d\n", (int)d->scale);
+ timer2 = clock();
+#endif
+ hashtable_rehash_compute(hash, rehash_collide);
+#ifndef NO_OUTPUT
+ timer2 = clock() - timer2;
+ printf("rehash took %f sec\n", timer2 / (double)CLOCKS_PER_SEC);
+ timer += timer2;
+#endif
+ }
+ }
+#ifndef NO_OUTPUT
+ printf("inserts took %f sec\n", (clock() - timer) / (double)CLOCKS_PER_SEC);
+#endif
+#ifndef NO_OUTPUT
+ printf("total %f sec\n", (clock() - timer3) / (double)CLOCKS_PER_SEC);
+#endif
+ return hash;
+}
+
+static void
+destroy_pixel_hash(HashTable *hash) {
+ PixelHashData *d = (PixelHashData *)hashtable_get_user_data(hash);
+ if (d) {
+ free(d);
+ }
+ hashtable_free(hash);
+}
+
+/* 1. hash quantized pixels. */
+/* 2. create R,G,B lists of sorted quantized pixels. */
+/* 3. median cut. */
+/* 4. build hash table from median cut boxes. */
+/* 5. for each pixel, compute entry in hash table, and hence median cut box. */
+/* 6. compute median cut box pixel averages. */
+/* 7. map each pixel to nearest average. */
+
+static int
+compute_box_volume(BoxNode *b) {
+ unsigned char rl, rh, gl, gh, bl, bh;
+ if (b->volume >= 0) {
+ return b->volume;
+ }
+ if (!b->head[0]) {
+ b->volume = 0;
+ } else {
+ rh = b->head[0]->p.c.r;
+ rl = b->tail[0]->p.c.r;
+ gh = b->head[1]->p.c.g;
+ gl = b->tail[1]->p.c.g;
+ bh = b->head[2]->p.c.b;
+ bl = b->tail[2]->p.c.b;
+ b->volume = (rh - rl + 1) * (gh - gl + 1) * (bh - bl + 1);
+ }
+ return b->volume;
+}
+
+static void
+hash_to_list(const HashTable *h, const Pixel pixel, const uint32_t count, void *u) {
+ PixelHashData *d = (PixelHashData *)hashtable_get_user_data(h);
+ PixelList **pl = (PixelList **)u;
+ PixelList *p;
+ int i;
+ Pixel q;
+
+ PIXEL_SCALE(&pixel, &q, d->scale);
+
+ /* malloc check ok, small constant allocation */
+ p = malloc(sizeof(PixelList));
+ if (!p) {
+ return;
+ }
+
+ p->flag = 0;
+ p->p = q;
+ p->count = count;
+ for (i = 0; i < 3; i++) {
+ p->next[i] = pl[i];
+ p->prev[i] = NULL;
+ if (pl[i]) {
+ pl[i]->prev[i] = p;
+ }
+ pl[i] = p;
+ }
+}
+
+static PixelList *
+mergesort_pixels(PixelList *head, int i) {
+ PixelList *c, *t, *a, *b, *p;
+ if (!head || !head->next[i]) {
+ if (head) {
+ head->next[i] = NULL;
+ head->prev[i] = NULL;
+ }
+ return head;
+ }
+ for (c = t = head; c && t;
+ c = c->next[i], t = (t->next[i]) ? t->next[i]->next[i] : NULL)
+ ;
+ if (c) {
+ if (c->prev[i]) {
+ c->prev[i]->next[i] = NULL;
+ }
+ c->prev[i] = NULL;
+ }
+ a = mergesort_pixels(head, i);
+ b = mergesort_pixels(c, i);
+ head = NULL;
+ p = NULL;
+ while (a && b) {
+ if (a->p.a.v[i] > b->p.a.v[i]) {
+ c = a;
+ a = a->next[i];
+ } else {
+ c = b;
+ b = b->next[i];
+ }
+ c->prev[i] = p;
+ c->next[i] = NULL;
+ if (p) {
+ p->next[i] = c;
+ }
+ p = c;
+ if (!head) {
+ head = c;
+ }
+ }
+ if (a) {
+ c->next[i] = a;
+ a->prev[i] = c;
+ } else if (b) {
+ c->next[i] = b;
+ b->prev[i] = c;
+ }
+ return head;
+}
+
+#if defined(TEST_MERGESORT) || defined(TEST_SORTED)
+static int
+test_sorted(PixelList *pl[3]) {
+ int i, n, l;
+ PixelList *t;
+
+ for (i = 0; i < 3; i++) {
+ n = 0;
+ l = 256;
+ for (t = pl[i]; t; t = t->next[i]) {
+ if (l < t->p.a.v[i])
+ return 0;
+ l = t->p.a.v[i];
+ }
+ }
+ return 1;
+}
+#endif
+
+static int
+box_heap_cmp(const Heap *h, const void *A, const void *B) {
+ BoxNode *a = (BoxNode *)A;
+ BoxNode *b = (BoxNode *)B;
+ return (int)a->pixelCount - (int)b->pixelCount;
+}
+
+#define LUMINANCE(p) (77 * (p)->c.r + 150 * (p)->c.g + 29 * (p)->c.b)
+
+static int
+splitlists(
+ PixelList *h[3],
+ PixelList *t[3],
+ PixelList *nh[2][3],
+ PixelList *nt[2][3],
+ uint32_t nCount[2],
+ int axis,
+ uint32_t pixelCount) {
+ uint32_t left;
+
+ PixelList *l, *r, *c, *n;
+ int i;
+ int nRight;
+#ifndef NO_OUTPUT
+ int nLeft;
+#endif
+ int splitColourVal;
+
+#ifdef TEST_SPLIT
+ {
+ PixelList *_prevTest, *_nextTest;
+ int _i, _nextCount[3], _prevCount[3];
+ for (_i = 0; _i < 3; _i++) {
+ for (_nextCount[_i] = 0, _nextTest = h[_i];
+ _nextTest && _nextTest->next[_i];
+ _nextTest = _nextTest->next[_i], _nextCount[_i]++)
+ ;
+ for (_prevCount[_i] = 0, _prevTest = t[_i];
+ _prevTest && _prevTest->prev[_i];
+ _prevTest = _prevTest->prev[_i], _prevCount[_i]++)
+ ;
+ if (_nextTest != t[_i]) {
+ printf("next-list of axis %d does not end at tail\n", _i);
+ exit(1);
+ }
+ if (_prevTest != h[_i]) {
+ printf("prev-list of axis %d does not end at head\n", _i);
+ exit(1);
+ }
+ for (; _nextTest && _nextTest->prev[_i]; _nextTest = _nextTest->prev[_i])
+ ;
+ for (; _prevTest && _prevTest->next[_i]; _prevTest = _prevTest->next[_i])
+ ;
+ if (_nextTest != h[_i]) {
+ printf("next-list of axis %d does not loop back to head\n", _i);
+ exit(1);
+ }
+ if (_prevTest != t[_i]) {
+ printf("prev-list of axis %d does not loop back to tail\n", _i);
+ exit(1);
+ }
+ }
+ for (_i = 1; _i < 3; _i++) {
+ if (_prevCount[_i] != _prevCount[_i - 1] ||
+ _nextCount[_i] != _nextCount[_i - 1] ||
+ _prevCount[_i] != _nextCount[_i]) {
+ printf(
+ "{%d %d %d} {%d %d %d}\n",
+ _prevCount[0],
+ _prevCount[1],
+ _prevCount[2],
+ _nextCount[0],
+ _nextCount[1],
+ _nextCount[2]);
+ exit(1);
+ }
+ }
+ }
+#endif
+ nCount[0] = nCount[1] = 0;
+ nRight = 0;
+#ifndef NO_OUTPUT
+ nLeft = 0;
+#endif
+ for (left = 0, c = h[axis]; c;) {
+ left = left + c->count;
+ nCount[0] += c->count;
+ c->flag = 0;
+#ifndef NO_OUTPUT
+ nLeft++;
+#endif
+ c = c->next[axis];
+ if (left * 2 > pixelCount) {
+ break;
+ }
+ }
+ if (c) {
+ splitColourVal = c->prev[axis]->p.a.v[axis];
+ for (; c; c = c->next[axis]) {
+ if (splitColourVal != c->p.a.v[axis]) {
+ break;
+ }
+ c->flag = 0;
+#ifndef NO_OUTPUT
+ nLeft++;
+#endif
+ nCount[0] += c->count;
+ }
+ }
+ for (; c; c = c->next[axis]) {
+ c->flag = 1;
+ nRight++;
+ nCount[1] += c->count;
+ }
+ if (!nRight) {
+ for (c = t[axis], splitColourVal = t[axis]->p.a.v[axis]; c; c = c->prev[axis]) {
+ if (splitColourVal != c->p.a.v[axis]) {
+ break;
+ }
+ c->flag = 1;
+ nRight++;
+#ifndef NO_OUTPUT
+ nLeft--;
+#endif
+ nCount[0] -= c->count;
+ nCount[1] += c->count;
+ }
+ }
+#ifndef NO_OUTPUT
+ if (!nLeft) {
+ for (c = h[axis]; c; c = c->next[axis]) {
+ printf("[%d %d %d]\n", c->p.c.r, c->p.c.g, c->p.c.b);
+ }
+ printf("warning... trivial split\n");
+ }
+#endif
+
+ for (i = 0; i < 3; i++) {
+ l = r = NULL;
+ nh[0][i] = nt[0][i] = NULL;
+ nh[1][i] = nt[1][i] = NULL;
+ for (c = h[i]; c; c = n) {
+ n = c->next[i];
+ if (c->flag) { /* move pixel to right list*/
+ if (r) {
+ r->next[i] = c;
+ } else {
+ nh[1][i] = c;
+ }
+ c->prev[i] = r;
+ r = c;
+ } else { /* move pixel to left list */
+ if (l) {
+ l->next[i] = c;
+ } else {
+ nh[0][i] = c;
+ }
+ c->prev[i] = l;
+ l = c;
+ }
+ }
+ if (l) {
+ l->next[i] = NULL;
+ }
+ if (r) {
+ r->next[i] = NULL;
+ }
+ nt[0][i] = l;
+ nt[1][i] = r;
+ }
+ return 1;
+}
+
+static int
+split(BoxNode *node) {
+ unsigned char rl, rh, gl, gh, bl, bh;
+ int f[3];
+ int best, axis;
+ int i;
+ PixelList *heads[2][3];
+ PixelList *tails[2][3];
+ uint32_t newCounts[2];
+ BoxNode *left, *right;
+
+ rh = node->head[0]->p.c.r;
+ rl = node->tail[0]->p.c.r;
+ gh = node->head[1]->p.c.g;
+ gl = node->tail[1]->p.c.g;
+ bh = node->head[2]->p.c.b;
+ bl = node->tail[2]->p.c.b;
+#ifdef TEST_SPLIT
+ printf("splitting node [%d %d %d] [%d %d %d] ", rl, gl, bl, rh, gh, bh);
+#endif
+ f[0] = (rh - rl) * 77;
+ f[1] = (gh - gl) * 150;
+ f[2] = (bh - bl) * 29;
+
+ best = f[0];
+ axis = 0;
+ for (i = 1; i < 3; i++) {
+ if (best < f[i]) {
+ best = f[i];
+ axis = i;
+ }
+ }
+#ifdef TEST_SPLIT
+ printf("along axis %d\n", axis + 1);
+#endif
+
+#ifdef TEST_SPLIT
+ {
+ PixelList *_prevTest, *_nextTest;
+ int _i, _nextCount[3], _prevCount[3];
+ for (_i = 0; _i < 3; _i++) {
+ if (node->tail[_i]->next[_i]) {
+ printf("tail is not tail\n");
+ printf(
+ "node->tail[%d]->next[%d]=%p\n", _i, _i, node->tail[_i]->next[_i]);
+ }
+ if (node->head[_i]->prev[_i]) {
+ printf("head is not head\n");
+ printf(
+ "node->head[%d]->prev[%d]=%p\n", _i, _i, node->head[_i]->prev[_i]);
+ }
+ }
+
+ for (_i = 0; _i < 3; _i++) {
+ for (_nextCount[_i] = 0, _nextTest = node->head[_i];
+ _nextTest && _nextTest->next[_i];
+ _nextTest = _nextTest->next[_i], _nextCount[_i]++)
+ ;
+ for (_prevCount[_i] = 0, _prevTest = node->tail[_i];
+ _prevTest && _prevTest->prev[_i];
+ _prevTest = _prevTest->prev[_i], _prevCount[_i]++)
+ ;
+ if (_nextTest != node->tail[_i]) {
+ printf("next-list of axis %d does not end at tail\n", _i);
+ }
+ if (_prevTest != node->head[_i]) {
+ printf("prev-list of axis %d does not end at head\n", _i);
+ }
+ for (; _nextTest && _nextTest->prev[_i]; _nextTest = _nextTest->prev[_i])
+ ;
+ for (; _prevTest && _prevTest->next[_i]; _prevTest = _prevTest->next[_i])
+ ;
+ if (_nextTest != node->head[_i]) {
+ printf("next-list of axis %d does not loop back to head\n", _i);
+ }
+ if (_prevTest != node->tail[_i]) {
+ printf("prev-list of axis %d does not loop back to tail\n", _i);
+ }
+ }
+ for (_i = 1; _i < 3; _i++) {
+ if (_prevCount[_i] != _prevCount[_i - 1] ||
+ _nextCount[_i] != _nextCount[_i - 1] ||
+ _prevCount[_i] != _nextCount[_i]) {
+ printf(
+ "{%d %d %d} {%d %d %d}\n",
+ _prevCount[0],
+ _prevCount[1],
+ _prevCount[2],
+ _nextCount[0],
+ _nextCount[1],
+ _nextCount[2]);
+ }
+ }
+ }
+#endif
+ node->axis = axis;
+ if (!splitlists(
+ node->head, node->tail, heads, tails, newCounts, axis, node->pixelCount)) {
+#ifndef NO_OUTPUT
+ printf("list split failed.\n");
+#endif
+ return 0;
+ }
+#ifdef TEST_SPLIT
+ if (!test_sorted(heads[0])) {
+ printf("bug in split");
+ exit(1);
+ }
+ if (!test_sorted(heads[1])) {
+ printf("bug in split");
+ exit(1);
+ }
+#endif
+ /* malloc check ok, small constant allocation */
+ left = malloc(sizeof(BoxNode));
+ right = malloc(sizeof(BoxNode));
+ if (!left || !right) {
+ free(left);
+ free(right);
+ return 0;
+ }
+ for (i = 0; i < 3; i++) {
+ left->head[i] = heads[0][i];
+ left->tail[i] = tails[0][i];
+ right->head[i] = heads[1][i];
+ right->tail[i] = tails[1][i];
+ node->head[i] = NULL;
+ node->tail[i] = NULL;
+ }
+#ifdef TEST_SPLIT
+ if (left->head[0]) {
+ rh = left->head[0]->p.c.r;
+ rl = left->tail[0]->p.c.r;
+ gh = left->head[1]->p.c.g;
+ gl = left->tail[1]->p.c.g;
+ bh = left->head[2]->p.c.b;
+ bl = left->tail[2]->p.c.b;
+ printf(" left node [%3d %3d %3d] [%3d %3d %3d]\n", rl, gl, bl, rh, gh, bh);
+ }
+ if (right->head[0]) {
+ rh = right->head[0]->p.c.r;
+ rl = right->tail[0]->p.c.r;
+ gh = right->head[1]->p.c.g;
+ gl = right->tail[1]->p.c.g;
+ bh = right->head[2]->p.c.b;
+ bl = right->tail[2]->p.c.b;
+ printf(" right node [%3d %3d %3d] [%3d %3d %3d]\n", rl, gl, bl, rh, gh, bh);
+ }
+#endif
+ left->l = left->r = NULL;
+ right->l = right->r = NULL;
+ left->axis = right->axis = -1;
+ left->volume = right->volume = -1;
+ left->pixelCount = newCounts[0];
+ right->pixelCount = newCounts[1];
+ node->l = left;
+ node->r = right;
+ return 1;
+}
+
+static BoxNode *
+median_cut(PixelList *hl[3], uint32_t imPixelCount, int nPixels) {
+ PixelList *tl[3];
+ int i;
+ BoxNode *root;
+ Heap *h;
+ BoxNode *thisNode;
+
+ h = ImagingQuantHeapNew(box_heap_cmp);
+ /* malloc check ok, small constant allocation */
+ root = malloc(sizeof(BoxNode));
+ if (!root) {
+ ImagingQuantHeapFree(h);
+ return NULL;
+ }
+ for (i = 0; i < 3; i++) {
+ for (tl[i] = hl[i]; tl[i] && tl[i]->next[i]; tl[i] = tl[i]->next[i])
+ ;
+ root->head[i] = hl[i];
+ root->tail[i] = tl[i];
+ }
+ root->l = root->r = NULL;
+ root->axis = -1;
+ root->volume = -1;
+ root->pixelCount = imPixelCount;
+
+ ImagingQuantHeapAdd(h, (void *)root);
+ while (--nPixels) {
+ do {
+ if (!ImagingQuantHeapRemove(h, (void **)&thisNode)) {
+ goto done;
+ }
+ } while (compute_box_volume(thisNode) == 1);
+ if (!split(thisNode)) {
+#ifndef NO_OUTPUT
+ printf("Oops, split failed...\n");
+#endif
+ exit(1);
+ }
+ ImagingQuantHeapAdd(h, (void *)(thisNode->l));
+ ImagingQuantHeapAdd(h, (void *)(thisNode->r));
+ }
+done:
+ ImagingQuantHeapFree(h);
+ return root;
+}
+
+static void
+free_box_tree(BoxNode *n) {
+ PixelList *p, *pp;
+ if (n->l) {
+ free_box_tree(n->l);
+ }
+ if (n->r) {
+ free_box_tree(n->r);
+ }
+ for (p = n->head[0]; p; p = pp) {
+ pp = p->next[0];
+ free(p);
+ }
+ free(n);
+}
+
+#ifdef TEST_SPLIT_INTEGRITY
+static int
+checkContained(BoxNode *n, Pixel *pp) {
+ if (n->l && n->r) {
+ return checkContained(n->l, pp) + checkContained(n->r, pp);
+ }
+ if (n->l || n->r) {
+#ifndef NO_OUTPUT
+ printf("box tree is dead\n");
+#endif
+ return 0;
+ }
+ if (pp->c.r <= n->head[0]->p.c.r && pp->c.r >= n->tail[0]->p.c.r &&
+ pp->c.g <= n->head[1]->p.c.g && pp->c.g >= n->tail[1]->p.c.g &&
+ pp->c.b <= n->head[2]->p.c.b && pp->c.b >= n->tail[2]->p.c.b) {
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+static int
+annotate_hash_table(BoxNode *n, HashTable *h, uint32_t *box) {
+ PixelList *p;
+ PixelHashData *d = (PixelHashData *)hashtable_get_user_data(h);
+ Pixel q;
+ if (n->l && n->r) {
+ return annotate_hash_table(n->l, h, box) && annotate_hash_table(n->r, h, box);
+ }
+ if (n->l || n->r) {
+#ifndef NO_OUTPUT
+ printf("box tree is dead\n");
+#endif
+ return 0;
+ }
+ for (p = n->head[0]; p; p = p->next[0]) {
+ PIXEL_UNSCALE(&(p->p), &q, d->scale);
+ if (!hashtable_insert(h, q, *box)) {
+#ifndef NO_OUTPUT
+ printf("hashtable insert failed\n");
+#endif
+ return 0;
+ }
+ }
+ if (n->head[0]) {
+ (*box)++;
+ }
+ return 1;
+}
+
+typedef struct {
+ uint32_t *distance;
+ uint32_t index;
+} DistanceWithIndex;
+
+static int
+_distance_index_cmp(const void *a, const void *b) {
+ DistanceWithIndex *A = (DistanceWithIndex *)a;
+ DistanceWithIndex *B = (DistanceWithIndex *)b;
+ if (*A->distance == *B->distance) {
+ return A->index < B->index ? -1 : +1;
+ }
+ return *A->distance < *B->distance ? -1 : +1;
+}
+
+static int
+resort_distance_tables(
+ uint32_t *avgDist, uint32_t **avgDistSortKey, Pixel *p, uint32_t nEntries) {
+ uint32_t i, j, k;
+ uint32_t **skRow;
+ uint32_t *skElt;
+
+ for (i = 0; i < nEntries; i++) {
+ avgDist[i * nEntries + i] = 0;
+ for (j = 0; j < i; j++) {
+ avgDist[j * nEntries + i] = avgDist[i * nEntries + j] =
+ _DISTSQR(p + i, p + j);
+ }
+ }
+ for (i = 0; i < nEntries; i++) {
+ skRow = avgDistSortKey + i * nEntries;
+ for (j = 1; j < nEntries; j++) {
+ skElt = skRow[j];
+ for (k = j; k && (*(skRow[k - 1]) > *(skRow[k])); k--) {
+ skRow[k] = skRow[k - 1];
+ }
+ if (k != j) {
+ skRow[k] = skElt;
+ }
+ }
+ }
+ return 1;
+}
+
+static int
+build_distance_tables(
+ uint32_t *avgDist, uint32_t **avgDistSortKey, Pixel *p, uint32_t nEntries) {
+ uint32_t i, j;
+ DistanceWithIndex *dwi;
+
+ for (i = 0; i < nEntries; i++) {
+ avgDist[i * nEntries + i] = 0;
+ avgDistSortKey[i * nEntries + i] = &(avgDist[i * nEntries + i]);
+ for (j = 0; j < i; j++) {
+ avgDist[j * nEntries + i] = avgDist[i * nEntries + j] =
+ _DISTSQR(p + i, p + j);
+ avgDistSortKey[j * nEntries + i] = &(avgDist[j * nEntries + i]);
+ avgDistSortKey[i * nEntries + j] = &(avgDist[i * nEntries + j]);
+ }
+ }
+
+ dwi = calloc(nEntries, sizeof(DistanceWithIndex));
+ if (!dwi) {
+ return 0;
+ }
+ for (i = 0; i < nEntries; i++) {
+ for (j = 0; j < nEntries; j++) {
+ dwi[j] = (DistanceWithIndex){
+ &(avgDist[i * nEntries + j]),
+ j
+ };
+ }
+ qsort(
+ dwi,
+ nEntries,
+ sizeof(DistanceWithIndex),
+ _distance_index_cmp);
+ for (j = 0; j < nEntries; j++) {
+ avgDistSortKey[i * nEntries + j] = dwi[j].distance;
+ }
+ }
+ free(dwi);
+ return 1;
+}
+
+static int
+map_image_pixels(
+ Pixel *pixelData,
+ uint32_t nPixels,
+ Pixel *paletteData,
+ uint32_t nPaletteEntries,
+ uint32_t *avgDist,
+ uint32_t **avgDistSortKey,
+ uint32_t *pixelArray) {
+ uint32_t *aD, **aDSK;
+ uint32_t idx;
+ uint32_t i, j;
+ uint32_t bestdist, bestmatch, dist;
+ uint32_t initialdist;
+ HashTable *h2;
+
+ h2 = hashtable_new(unshifted_pixel_hash, unshifted_pixel_cmp);
+ for (i = 0; i < nPixels; i++) {
+ if (!hashtable_lookup(h2, pixelData[i], &bestmatch)) {
+ bestmatch = 0;
+ initialdist = _DISTSQR(paletteData + bestmatch, pixelData + i);
+ bestdist = initialdist;
+ initialdist <<= 2;
+ aDSK = avgDistSortKey + bestmatch * nPaletteEntries;
+ aD = avgDist + bestmatch * nPaletteEntries;
+ for (j = 0; j < nPaletteEntries; j++) {
+ idx = aDSK[j] - aD;
+ if (*(aDSK[j]) <= initialdist) {
+ dist = _DISTSQR(paletteData + idx, pixelData + i);
+ if (dist < bestdist) {
+ bestdist = dist;
+ bestmatch = idx;
+ }
+ } else {
+ break;
+ }
+ }
+ hashtable_insert(h2, pixelData[i], bestmatch);
+ }
+ pixelArray[i] = bestmatch;
+ }
+ hashtable_free(h2);
+ return 1;
+}
+
+static int
+map_image_pixels_from_quantized_pixels(
+ Pixel *pixelData,
+ uint32_t nPixels,
+ Pixel *paletteData,
+ uint32_t nPaletteEntries,
+ uint32_t *avgDist,
+ uint32_t **avgDistSortKey,
+ uint32_t *pixelArray,
+ uint32_t *avg[3],
+ uint32_t *count) {
+ uint32_t *aD, **aDSK;
+ uint32_t idx;
+ uint32_t i, j;
+ uint32_t bestdist, bestmatch, dist;
+ uint32_t initialdist;
+ HashTable *h2;
+ int changes = 0;
+
+ h2 = hashtable_new(unshifted_pixel_hash, unshifted_pixel_cmp);
+ for (i = 0; i < nPixels; i++) {
+ if (!hashtable_lookup(h2, pixelData[i], &bestmatch)) {
+ bestmatch = pixelArray[i];
+ initialdist = _DISTSQR(paletteData + bestmatch, pixelData + i);
+ bestdist = initialdist;
+ initialdist <<= 2;
+ aDSK = avgDistSortKey + bestmatch * nPaletteEntries;
+ aD = avgDist + bestmatch * nPaletteEntries;
+ for (j = 0; j < nPaletteEntries; j++) {
+ idx = aDSK[j] - aD;
+ if (*(aDSK[j]) <= initialdist) {
+ dist = _DISTSQR(paletteData + idx, pixelData + i);
+ if (dist < bestdist) {
+ bestdist = dist;
+ bestmatch = idx;
+ }
+ } else {
+ break;
+ }
+ }
+ hashtable_insert(h2, pixelData[i], bestmatch);
+ }
+ if (pixelArray[i] != bestmatch) {
+ changes++;
+ avg[0][bestmatch] += pixelData[i].c.r;
+ avg[1][bestmatch] += pixelData[i].c.g;
+ avg[2][bestmatch] += pixelData[i].c.b;
+ avg[0][pixelArray[i]] -= pixelData[i].c.r;
+ avg[1][pixelArray[i]] -= pixelData[i].c.g;
+ avg[2][pixelArray[i]] -= pixelData[i].c.b;
+ count[bestmatch]++;
+ count[pixelArray[i]]--;
+ pixelArray[i] = bestmatch;
+ }
+ }
+ hashtable_free(h2);
+ return changes;
+}
+
+static int
+map_image_pixels_from_median_box(
+ Pixel *pixelData,
+ uint32_t nPixels,
+ Pixel *paletteData,
+ uint32_t nPaletteEntries,
+ HashTable *medianBoxHash,
+ uint32_t *avgDist,
+ uint32_t **avgDistSortKey,
+ uint32_t *pixelArray) {
+ uint32_t *aD, **aDSK;
+ uint32_t idx;
+ uint32_t i, j;
+ uint32_t bestdist, bestmatch, dist;
+ uint32_t initialdist;
+ HashTable *h2;
+ uint32_t pixelVal;
+
+ h2 = hashtable_new(unshifted_pixel_hash, unshifted_pixel_cmp);
+ for (i = 0; i < nPixels; i++) {
+ if (hashtable_lookup(h2, pixelData[i], &pixelVal)) {
+ pixelArray[i] = pixelVal;
+ continue;
+ }
+ if (!hashtable_lookup(medianBoxHash, pixelData[i], &pixelVal)) {
+#ifndef NO_OUTPUT
+ printf("pixel lookup failed\n");
+#endif
+ return 0;
+ }
+ initialdist = _DISTSQR(paletteData + pixelVal, pixelData + i);
+ bestdist = initialdist;
+ bestmatch = pixelVal;
+ initialdist <<= 2;
+ aDSK = avgDistSortKey + pixelVal * nPaletteEntries;
+ aD = avgDist + pixelVal * nPaletteEntries;
+ for (j = 0; j < nPaletteEntries; j++) {
+ idx = aDSK[j] - aD;
+ if (*(aDSK[j]) <= initialdist) {
+ dist = _DISTSQR(paletteData + idx, pixelData + i);
+ if (dist < bestdist) {
+ bestdist = dist;
+ bestmatch = idx;
+ }
+ } else {
+ break;
+ }
+ }
+ pixelArray[i] = bestmatch;
+ hashtable_insert(h2, pixelData[i], bestmatch);
+ }
+ hashtable_free(h2);
+ return 1;
+}
+
+static int
+compute_palette_from_median_cut(
+ Pixel *pixelData,
+ uint32_t nPixels,
+ HashTable *medianBoxHash,
+ Pixel **palette,
+ uint32_t nPaletteEntries) {
+ uint32_t i;
+ uint32_t paletteEntry;
+ Pixel *p;
+ uint32_t *avg[3];
+ uint32_t *count;
+
+ *palette = NULL;
+ /* malloc check ok, using calloc */
+ if (!(count = calloc(nPaletteEntries, sizeof(uint32_t)))) {
+ return 0;
+ }
+ for (i = 0; i < 3; i++) {
+ avg[i] = NULL;
+ }
+ for (i = 0; i < 3; i++) {
+ /* malloc check ok, using calloc */
+ if (!(avg[i] = calloc(nPaletteEntries, sizeof(uint32_t)))) {
+ for (i = 0; i < 3; i++) {
+ if (avg[i]) {
+ free(avg[i]);
+ }
+ }
+ free(count);
+ return 0;
+ }
+ }
+ for (i = 0; i < nPixels; i++) {
+#ifdef TEST_SPLIT_INTEGRITY
+ if (!(i % 100)) {
+ printf("%05d\r", i);
+ fflush(stdout);
+ }
+ if (checkContained(root, pixelData + i) > 1) {
+ printf("pixel in two boxes\n");
+ for (i = 0; i < 3; i++) {
+ free(avg[i]);
+ }
+ free(count);
+ return 0;
+ }
+#endif
+ if (!hashtable_lookup(medianBoxHash, pixelData[i], &paletteEntry)) {
+#ifndef NO_OUTPUT
+ printf("pixel lookup failed\n");
+#endif
+ for (i = 0; i < 3; i++) {
+ free(avg[i]);
+ }
+ free(count);
+ return 0;
+ }
+ if (paletteEntry >= nPaletteEntries) {
+#ifndef NO_OUTPUT
+ printf(
+ "panic - paletteEntry>=nPaletteEntries (%d>=%d)\n",
+ (int)paletteEntry,
+ (int)nPaletteEntries);
+#endif
+ for (i = 0; i < 3; i++) {
+ free(avg[i]);
+ }
+ free(count);
+ return 0;
+ }
+ avg[0][paletteEntry] += pixelData[i].c.r;
+ avg[1][paletteEntry] += pixelData[i].c.g;
+ avg[2][paletteEntry] += pixelData[i].c.b;
+ count[paletteEntry]++;
+ }
+ /* malloc check ok, using calloc */
+ p = calloc(nPaletteEntries, sizeof(Pixel));
+ if (!p) {
+ for (i = 0; i < 3; i++) {
+ free(avg[i]);
+ }
+ free(count);
+ return 0;
+ }
+ for (i = 0; i < nPaletteEntries; i++) {
+ p[i].c.r = (int)(.5 + (double)avg[0][i] / (double)count[i]);
+ p[i].c.g = (int)(.5 + (double)avg[1][i] / (double)count[i]);
+ p[i].c.b = (int)(.5 + (double)avg[2][i] / (double)count[i]);
+ }
+ *palette = p;
+ for (i = 0; i < 3; i++) {
+ free(avg[i]);
+ }
+ free(count);
+ return 1;
+}
+
+static int
+recompute_palette_from_averages(
+ Pixel *palette, uint32_t nPaletteEntries, uint32_t *avg[3], uint32_t *count) {
+ uint32_t i;
+
+ for (i = 0; i < nPaletteEntries; i++) {
+ palette[i].c.r = (int)(.5 + (double)avg[0][i] / (double)count[i]);
+ palette[i].c.g = (int)(.5 + (double)avg[1][i] / (double)count[i]);
+ palette[i].c.b = (int)(.5 + (double)avg[2][i] / (double)count[i]);
+ }
+ return 1;
+}
+
+static int
+compute_palette_from_quantized_pixels(
+ Pixel *pixelData,
+ uint32_t nPixels,
+ Pixel *palette,
+ uint32_t nPaletteEntries,
+ uint32_t *avg[3],
+ uint32_t *count,
+ uint32_t *qp) {
+ uint32_t i;
+
+ memset(count, 0, sizeof(uint32_t) * nPaletteEntries);
+ for (i = 0; i < 3; i++) {
+ memset(avg[i], 0, sizeof(uint32_t) * nPaletteEntries);
+ }
+ for (i = 0; i < nPixels; i++) {
+ if (qp[i] >= nPaletteEntries) {
+#ifndef NO_OUTPUT
+ printf("scream\n");
+#endif
+ return 0;
+ }
+ avg[0][qp[i]] += pixelData[i].c.r;
+ avg[1][qp[i]] += pixelData[i].c.g;
+ avg[2][qp[i]] += pixelData[i].c.b;
+ count[qp[i]]++;
+ }
+ for (i = 0; i < nPaletteEntries; i++) {
+ palette[i].c.r = (int)(.5 + (double)avg[0][i] / (double)count[i]);
+ palette[i].c.g = (int)(.5 + (double)avg[1][i] / (double)count[i]);
+ palette[i].c.b = (int)(.5 + (double)avg[2][i] / (double)count[i]);
+ }
+ return 1;
+}
+
+static int
+k_means(
+ Pixel *pixelData,
+ uint32_t nPixels,
+ Pixel *paletteData,
+ uint32_t nPaletteEntries,
+ uint32_t *qp,
+ int threshold) {
+ uint32_t *avg[3];
+ uint32_t *count;
+ uint32_t i;
+ uint32_t *avgDist;
+ uint32_t **avgDistSortKey;
+ int changes;
+ int built = 0;
+
+ if (nPaletteEntries > UINT32_MAX / (sizeof(uint32_t))) {
+ return 0;
+ }
+ /* malloc check ok, using calloc */
+ if (!(count = calloc(nPaletteEntries, sizeof(uint32_t)))) {
+ return 0;
+ }
+ for (i = 0; i < 3; i++) {
+ avg[i] = NULL;
+ }
+ for (i = 0; i < 3; i++) {
+ /* malloc check ok, using calloc */
+ if (!(avg[i] = calloc(nPaletteEntries, sizeof(uint32_t)))) {
+ goto error_1;
+ }
+ }
+
+ /* this is enough of a check, since the multiplication n*size is done above */
+ if (nPaletteEntries > UINT32_MAX / nPaletteEntries) {
+ goto error_1;
+ }
+ /* malloc check ok, using calloc, checking n*n above */
+ avgDist = calloc(nPaletteEntries * nPaletteEntries, sizeof(uint32_t));
+ if (!avgDist) {
+ goto error_1;
+ }
+
+ /* malloc check ok, using calloc, checking n*n above */
+ avgDistSortKey = calloc(nPaletteEntries * nPaletteEntries, sizeof(uint32_t *));
+ if (!avgDistSortKey) {
+ goto error_2;
+ }
+
+#ifndef NO_OUTPUT
+ printf("[");
+ fflush(stdout);
+#endif
+ while (1) {
+ if (!built) {
+ compute_palette_from_quantized_pixels(
+ pixelData, nPixels, paletteData, nPaletteEntries, avg, count, qp);
+ if (!build_distance_tables(
+ avgDist, avgDistSortKey, paletteData, nPaletteEntries)) {
+ goto error_3;
+ }
+ built = 1;
+ } else {
+ recompute_palette_from_averages(paletteData, nPaletteEntries, avg, count);
+ resort_distance_tables(
+ avgDist, avgDistSortKey, paletteData, nPaletteEntries);
+ }
+ changes = map_image_pixels_from_quantized_pixels(
+ pixelData,
+ nPixels,
+ paletteData,
+ nPaletteEntries,
+ avgDist,
+ avgDistSortKey,
+ qp,
+ avg,
+ count);
+ if (changes < 0) {
+ goto error_3;
+ }
+#ifndef NO_OUTPUT
+ printf(".(%d)", changes);
+ fflush(stdout);
+#endif
+ if (changes <= threshold) {
+ break;
+ }
+ }
+#ifndef NO_OUTPUT
+ printf("]\n");
+#endif
+ if (avgDistSortKey) {
+ free(avgDistSortKey);
+ }
+ if (avgDist) {
+ free(avgDist);
+ }
+ for (i = 0; i < 3; i++) {
+ if (avg[i]) {
+ free(avg[i]);
+ }
+ }
+ if (count) {
+ free(count);
+ }
+ return 1;
+
+error_3:
+ if (avgDistSortKey) {
+ free(avgDistSortKey);
+ }
+error_2:
+ if (avgDist) {
+ free(avgDist);
+ }
+error_1:
+ for (i = 0; i < 3; i++) {
+ if (avg[i]) {
+ free(avg[i]);
+ }
+ }
+ if (count) {
+ free(count);
+ }
+ return 0;
+}
+
+static int
+quantize(
+ Pixel *pixelData,
+ uint32_t nPixels,
+ uint32_t nQuantPixels,
+ Pixel **palette,
+ uint32_t *paletteLength,
+ uint32_t **quantizedPixels,
+ int kmeans) {
+ PixelList *hl[3];
+ HashTable *h;
+ BoxNode *root;
+ uint32_t i;
+ uint32_t *qp;
+ uint32_t nPaletteEntries;
+
+ uint32_t *avgDist;
+ uint32_t **avgDistSortKey;
+ Pixel *p;
+
+#ifndef NO_OUTPUT
+ uint32_t timer, timer2;
+#endif
+
+#ifndef NO_OUTPUT
+ timer2 = clock();
+ printf("create hash table...");
+ fflush(stdout);
+ timer = clock();
+#endif
+ h = create_pixel_hash(pixelData, nPixels);
+#ifndef NO_OUTPUT
+ printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC);
+#endif
+ if (!h) {
+ goto error_0;
+ }
+
+#ifndef NO_OUTPUT
+ printf("create lists from hash table...");
+ fflush(stdout);
+ timer = clock();
+#endif
+ hl[0] = hl[1] = hl[2] = NULL;
+ hashtable_foreach(h, hash_to_list, hl);
+#ifndef NO_OUTPUT
+ printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC);
+#endif
+
+ if (!hl[0]) {
+ goto error_1;
+ }
+
+#ifndef NO_OUTPUT
+ printf("mergesort lists...");
+ fflush(stdout);
+ timer = clock();
+#endif
+ for (i = 0; i < 3; i++) {
+ hl[i] = mergesort_pixels(hl[i], i);
+ }
+#ifdef TEST_MERGESORT
+ if (!test_sorted(hl)) {
+ printf("bug in mergesort\n");
+ goto error_1;
+ }
+#endif
+#ifndef NO_OUTPUT
+ printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC);
+#endif
+
+#ifndef NO_OUTPUT
+ printf("median cut...");
+ fflush(stdout);
+ timer = clock();
+#endif
+ root = median_cut(hl, nPixels, nQuantPixels);
+#ifndef NO_OUTPUT
+ printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC);
+#endif
+ if (!root) {
+ goto error_1;
+ }
+ nPaletteEntries = 0;
+#ifndef NO_OUTPUT
+ printf("median cut tree to hash table...");
+ fflush(stdout);
+ timer = clock();
+#endif
+ annotate_hash_table(root, h, &nPaletteEntries);
+#ifndef NO_OUTPUT
+ printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC);
+#endif
+#ifndef NO_OUTPUT
+ printf("compute palette...\n");
+ fflush(stdout);
+ timer = clock();
+#endif
+ if (!compute_palette_from_median_cut(pixelData, nPixels, h, &p, nPaletteEntries)) {
+ goto error_3;
+ }
+#ifndef NO_OUTPUT
+ printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC);
+#endif
+
+ free_box_tree(root);
+ root = NULL;
+
+ /* malloc check ok, using calloc for overflow */
+ qp = calloc(nPixels, sizeof(uint32_t));
+ if (!qp) {
+ goto error_4;
+ }
+
+ if (nPaletteEntries > UINT32_MAX / nPaletteEntries) {
+ goto error_5;
+ }
+ /* malloc check ok, using calloc for overflow, check of n*n above */
+ avgDist = calloc(nPaletteEntries * nPaletteEntries, sizeof(uint32_t));
+ if (!avgDist) {
+ goto error_5;
+ }
+
+ /* malloc check ok, using calloc for overflow, check of n*n above */
+ avgDistSortKey = calloc(nPaletteEntries * nPaletteEntries, sizeof(uint32_t *));
+ if (!avgDistSortKey) {
+ goto error_6;
+ }
+
+ if (!build_distance_tables(avgDist, avgDistSortKey, p, nPaletteEntries)) {
+ goto error_7;
+ }
+
+ if (!map_image_pixels_from_median_box(
+ pixelData, nPixels, p, nPaletteEntries, h, avgDist, avgDistSortKey, qp)) {
+ goto error_7;
+ }
+
+#ifdef TEST_NEAREST_NEIGHBOUR
+#include <math.h>
+ {
+ uint32_t bestmatch, bestdist, dist;
+ HashTable *h2;
+ printf("nearest neighbour search (full search)...");
+ fflush(stdout);
+ timer = clock();
+ h2 = hashtable_new(unshifted_pixel_hash, unshifted_pixel_cmp);
+ for (i = 0; i < nPixels; i++) {
+ if (hashtable_lookup(h2, pixelData[i], &paletteEntry)) {
+ bestmatch = paletteEntry;
+ } else {
+ bestmatch = 0;
+ bestdist = _SQR(pixelData[i].c.r - p[0].c.r) +
+ _SQR(pixelData[i].c.g - p[0].c.g) +
+ _SQR(pixelData[i].c.b - p[0].c.b);
+ for (j = 1; j < nPaletteEntries; j++) {
+ dist = _SQR(pixelData[i].c.r - p[j].c.r) +
+ _SQR(pixelData[i].c.g - p[j].c.g) +
+ _SQR(pixelData[i].c.b - p[j].c.b);
+ if (dist == bestdist && j == qp[i]) {
+ bestmatch = j;
+ }
+ if (dist < bestdist) {
+ bestdist = dist;
+ bestmatch = j;
+ }
+ }
+ hashtable_insert(h2, pixelData[i], bestmatch);
+ }
+ if (qp[i] != bestmatch) {
+ printf ("discrepancy in matching algorithms pixel %d [%d %d] %f %f\n",
+ i,qp[i],bestmatch,
+ sqrt((double)(_SQR(pixelData[i].c.r-p[qp[i]].c.r)+
+ _SQR(pixelData[i].c.g-p[qp[i]].c.g)+
+ _SQR(pixelData[i].c.b-p[qp[i]].c.b))),
+ sqrt((double)(_SQR(pixelData[i].c.r-p[bestmatch].c.r)+
+ _SQR(pixelData[i].c.g-p[bestmatch].c.g)+
+ _SQR(pixelData[i].c.b-p[bestmatch].c.b)))
+ );
+ }
+ }
+ hashtable_free(h2);
+ }
+#endif
+#ifndef NO_OUTPUT
+ printf("k means...\n");
+ fflush(stdout);
+ timer = clock();
+#endif
+ if (kmeans) {
+ k_means(pixelData, nPixels, p, nPaletteEntries, qp, kmeans - 1);
+ }
+#ifndef NO_OUTPUT
+ printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC);
+#endif
+
+ *quantizedPixels = qp;
+ *palette = p;
+ *paletteLength = nPaletteEntries;
+
+#ifndef NO_OUTPUT
+ printf("cleanup...");
+ fflush(stdout);
+ timer = clock();
+#endif
+ if (avgDist) {
+ free(avgDist);
+ }
+ if (avgDistSortKey) {
+ free(avgDistSortKey);
+ }
+ destroy_pixel_hash(h);
+#ifndef NO_OUTPUT
+ printf("done (%f)\n", (clock() - timer) / (double)CLOCKS_PER_SEC);
+ printf("-----\ntotal time %f\n", (clock() - timer2) / (double)CLOCKS_PER_SEC);
+#endif
+ return 1;
+
+error_7:
+ if (avgDistSortKey) {
+ free(avgDistSortKey);
+ }
+error_6:
+ if (avgDist) {
+ free(avgDist);
+ }
+error_5:
+ if (qp) {
+ free(qp);
+ }
+error_4:
+ if (p) {
+ free(p);
+ }
+error_3:
+ if (root) {
+ free_box_tree(root);
+ }
+error_1:
+ destroy_pixel_hash(h);
+error_0:
+ *quantizedPixels = NULL;
+ *paletteLength = 0;
+ *palette = NULL;
+ return 0;
+}
+
+typedef struct {
+ Pixel new;
+ uint32_t furthestV;
+ uint32_t furthestDistance;
+ int secondPixel;
+} DistanceData;
+
+static void
+compute_distances(const HashTable *h, const Pixel pixel, uint32_t *dist, void *u) {
+ DistanceData *data = (DistanceData *)u;
+ uint32_t oldDist = *dist;
+ uint32_t newDist;
+ newDist = _DISTSQR(&(data->new), &pixel);
+ if (data->secondPixel || newDist < oldDist) {
+ *dist = newDist;
+ oldDist = newDist;
+ }
+ if (oldDist > data->furthestDistance) {
+ data->furthestDistance = oldDist;
+ data->furthestV = pixel.v;
+ }
+}
+
+static int
+quantize2(
+ Pixel *pixelData,
+ uint32_t nPixels,
+ uint32_t nQuantPixels,
+ Pixel **palette,
+ uint32_t *paletteLength,
+ uint32_t **quantizedPixels,
+ int kmeans) {
+ HashTable *h;
+ uint32_t i;
+ uint32_t mean[3];
+ Pixel *p;
+ DistanceData data;
+
+ uint32_t *qp;
+ uint32_t *avgDist;
+ uint32_t **avgDistSortKey;
+
+ /* malloc check ok, using calloc */
+ p = calloc(nQuantPixels, sizeof(Pixel));
+ if (!p) {
+ return 0;
+ }
+ mean[0] = mean[1] = mean[2] = 0;
+ h = hashtable_new(unshifted_pixel_hash, unshifted_pixel_cmp);
+ for (i = 0; i < nPixels; i++) {
+ hashtable_insert(h, pixelData[i], 0xffffffff);
+ mean[0] += pixelData[i].c.r;
+ mean[1] += pixelData[i].c.g;
+ mean[2] += pixelData[i].c.b;
+ }
+ data.new.c.r = (int)(.5 + (double)mean[0] / (double)nPixels);
+ data.new.c.g = (int)(.5 + (double)mean[1] / (double)nPixels);
+ data.new.c.b = (int)(.5 + (double)mean[2] / (double)nPixels);
+ for (i = 0; i < nQuantPixels; i++) {
+ data.furthestDistance = 0;
+ data.furthestV = pixelData[0].v;
+ data.secondPixel = (i == 1) ? 1 : 0;
+ hashtable_foreach_update(h, compute_distances, &data);
+ p[i].v = data.furthestV;
+ data.new.v = data.furthestV;
+ }
+ hashtable_free(h);
+
+ /* malloc check ok, using calloc */
+ qp = calloc(nPixels, sizeof(uint32_t));
+ if (!qp) {
+ goto error_1;
+ }
+
+ if (nQuantPixels > UINT32_MAX / nQuantPixels) {
+ goto error_2;
+ }
+
+ /* malloc check ok, using calloc for overflow, check of n*n above */
+ avgDist = calloc(nQuantPixels * nQuantPixels, sizeof(uint32_t));
+ if (!avgDist) {
+ goto error_2;
+ }
+
+ /* malloc check ok, using calloc for overflow, check of n*n above */
+ avgDistSortKey = calloc(nQuantPixels * nQuantPixels, sizeof(uint32_t *));
+ if (!avgDistSortKey) {
+ goto error_3;
+ }
+
+ if (!build_distance_tables(avgDist, avgDistSortKey, p, nQuantPixels)) {
+ goto error_4;
+ }
+
+ if (!map_image_pixels(
+ pixelData, nPixels, p, nQuantPixels, avgDist, avgDistSortKey, qp)) {
+ goto error_4;
+ }
+ if (kmeans) {
+ k_means(pixelData, nPixels, p, nQuantPixels, qp, kmeans - 1);
+ }
+
+ *paletteLength = nQuantPixels;
+ *palette = p;
+ *quantizedPixels = qp;
+ free(avgDistSortKey);
+ free(avgDist);
+ return 1;
+
+error_4:
+ free(avgDistSortKey);
+error_3:
+ free(avgDist);
+error_2:
+ free(qp);
+error_1:
+ free(p);
+ return 0;
+}
+
+Imaging
+ImagingQuantize(Imaging im, int colors, int mode, int kmeans) {
+ int i, j;
+ int x, y, v;
+ UINT8 *pp;
+ Pixel *p;
+ Pixel *palette;
+ uint32_t paletteLength;
+ int result;
+ uint32_t *newData;
+ Imaging imOut;
+ int withAlpha = 0;
+ ImagingSectionCookie cookie;
+
+ if (!im) {
+ return ImagingError_ModeError();
+ }
+ if (colors < 1 || colors > 256) {
+ /* FIXME: for colors > 256, consider returning an RGB image
+ instead (see @PIL205) */
+ return (Imaging)ImagingError_ValueError("bad number of colors");
+ }
+
+ if (strcmp(im->mode, "L") != 0 && strcmp(im->mode, "P") != 0 &&
+ strcmp(im->mode, "RGB") != 0 && strcmp(im->mode, "RGBA") != 0) {
+ return ImagingError_ModeError();
+ }
+
+ /* only octree and imagequant supports RGBA */
+ if (!strcmp(im->mode, "RGBA") && mode != 2 && mode != 3) {
+ return ImagingError_ModeError();
+ }
+
+ if (im->xsize > INT_MAX / im->ysize) {
+ return ImagingError_MemoryError();
+ }
+ /* malloc check ok, using calloc for final overflow, x*y above */
+ p = calloc(im->xsize * im->ysize, sizeof(Pixel));
+ if (!p) {
+ return ImagingError_MemoryError();
+ }
+
+ /* collect statistics */
+
+ /* FIXME: maybe we could load the hash tables directly from the
+ image data? */
+
+ if (!strcmp(im->mode, "L")) {
+ /* greyscale */
+
+ /* FIXME: converting a "L" image to "P" with 256 colors
+ should be done by a simple copy... */
+
+ for (i = y = 0; y < im->ysize; y++) {
+ for (x = 0; x < im->xsize; x++, i++) {
+ p[i].c.r = p[i].c.g = p[i].c.b = im->image8[y][x];
+ p[i].c.a = 255;
+ }
+ }
+
+ } else if (!strcmp(im->mode, "P")) {
+ /* palette */
+
+ pp = im->palette->palette;
+
+ for (i = y = 0; y < im->ysize; y++) {
+ for (x = 0; x < im->xsize; x++, i++) {
+ v = im->image8[y][x];
+ p[i].c.r = pp[v * 4 + 0];
+ p[i].c.g = pp[v * 4 + 1];
+ p[i].c.b = pp[v * 4 + 2];
+ p[i].c.a = pp[v * 4 + 3];
+ }
+ }
+
+ } else if (!strcmp(im->mode, "RGB") || !strcmp(im->mode, "RGBA")) {
+ /* true colour */
+
+ withAlpha = !strcmp(im->mode, "RGBA");
+ int transparency = 0;
+ unsigned char r = 0, g = 0, b = 0;
+ for (i = y = 0; y < im->ysize; y++) {
+ for (x = 0; x < im->xsize; x++, i++) {
+ p[i].v = im->image32[y][x];
+ if (withAlpha && p[i].c.a == 0) {
+ if (transparency == 0) {
+ transparency = 1;
+ r = p[i].c.r;
+ g = p[i].c.g;
+ b = p[i].c.b;
+ } else {
+ /* Set all subsequent transparent pixels
+ to the same colour as the first */
+ p[i].c.r = r;
+ p[i].c.g = g;
+ p[i].c.b = b;
+ }
+ }
+ }
+ }
+
+ } else {
+ free(p);
+ return (Imaging)ImagingError_ValueError("internal error");
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ switch (mode) {
+ case 0:
+ /* median cut */
+ result = quantize(
+ p,
+ im->xsize * im->ysize,
+ colors,
+ &palette,
+ &paletteLength,
+ &newData,
+ kmeans);
+ break;
+ case 1:
+ /* maximum coverage */
+ result = quantize2(
+ p,
+ im->xsize * im->ysize,
+ colors,
+ &palette,
+ &paletteLength,
+ &newData,
+ kmeans);
+ break;
+ case 2:
+ result = quantize_octree(
+ p,
+ im->xsize * im->ysize,
+ colors,
+ &palette,
+ &paletteLength,
+ &newData,
+ withAlpha);
+ break;
+ case 3:
+#ifdef HAVE_LIBIMAGEQUANT
+ result = quantize_pngquant(
+ p,
+ im->xsize,
+ im->ysize,
+ colors,
+ &palette,
+ &paletteLength,
+ &newData,
+ withAlpha);
+#else
+ result = -1;
+#endif
+ break;
+ default:
+ result = 0;
+ break;
+ }
+
+ free(p);
+ ImagingSectionLeave(&cookie);
+
+ if (result > 0) {
+ imOut = ImagingNewDirty("P", im->xsize, im->ysize);
+ ImagingSectionEnter(&cookie);
+
+ for (i = y = 0; y < im->ysize; y++) {
+ for (x = 0; x < im->xsize; x++) {
+ imOut->image8[y][x] = (unsigned char)newData[i++];
+ }
+ }
+
+ free(newData);
+
+ imOut->palette->size = (int)paletteLength;
+ pp = imOut->palette->palette;
+
+ for (i = j = 0; i < (int)paletteLength; i++) {
+ *pp++ = palette[i].c.r;
+ *pp++ = palette[i].c.g;
+ *pp++ = palette[i].c.b;
+ if (withAlpha) {
+ *pp = palette[i].c.a;
+ }
+ pp++;
+ }
+
+ if (withAlpha) {
+ strcpy(imOut->palette->mode, "RGBA");
+ }
+
+ free(palette);
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+
+ } else {
+ if (result == -1) {
+ return (Imaging)ImagingError_ValueError(
+ "dependency required by this method was not "
+ "enabled at compile time");
+ }
+
+ return (Imaging)ImagingError_ValueError("quantization error");
+ }
+}
diff --git a/contrib/python/Pillow/py3/libImaging/QuantHash.c b/contrib/python/Pillow/py3/libImaging/QuantHash.c
new file mode 100644
index 00000000000..ea75d6037f9
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/QuantHash.c
@@ -0,0 +1,336 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * hash tables used by the image quantizer
+ *
+ * history:
+ * 98-09-10 tjs Contributed
+ * 98-12-29 fl Added to PIL 1.0b1
+ *
+ * Written by Toby J Sargeant <[email protected]>.
+ *
+ * Copyright (c) 1998 by Toby J Sargeant
+ * Copyright (c) 1998 by Secret Labs AB
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "QuantHash.h"
+
+typedef struct _HashNode {
+ struct _HashNode *next;
+ HashKey_t key;
+ HashVal_t value;
+} HashNode;
+
+struct _HashTable {
+ HashNode **table;
+ uint32_t length;
+ uint32_t count;
+ HashFunc hashFunc;
+ HashCmpFunc cmpFunc;
+ void *userData;
+};
+
+#define MIN_LENGTH 11
+#define RESIZE_FACTOR 3
+
+static int
+_hashtable_insert_node(HashTable *, HashNode *, int, int, CollisionFunc);
+
+HashTable *
+hashtable_new(HashFunc hf, HashCmpFunc cf) {
+ HashTable *h;
+ h = malloc(sizeof(HashTable));
+ if (!h) {
+ return NULL;
+ }
+ h->hashFunc = hf;
+ h->cmpFunc = cf;
+ h->length = MIN_LENGTH;
+ h->count = 0;
+ h->userData = NULL;
+ h->table = malloc(sizeof(HashNode *) * h->length);
+ if (!h->table) {
+ free(h);
+ return NULL;
+ }
+ memset(h->table, 0, sizeof(HashNode *) * h->length);
+ return h;
+}
+
+static uint32_t
+_findPrime(uint32_t start, int dir) {
+ static int unit[] = {0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0};
+ uint32_t t;
+ while (start > 1) {
+ if (!unit[start & 0x0f]) {
+ start += dir;
+ continue;
+ }
+ for (t = 2; t < sqrt((double)start); t++) {
+ if (!start % t) {
+ break;
+ }
+ }
+ if (t >= sqrt((double)start)) {
+ break;
+ }
+ start += dir;
+ }
+ return start;
+}
+
+static void
+_hashtable_rehash(HashTable *h, CollisionFunc cf, uint32_t newSize) {
+ HashNode **oldTable = h->table;
+ uint32_t i;
+ HashNode *n, *nn;
+ uint32_t oldSize;
+ oldSize = h->length;
+ h->table = malloc(sizeof(HashNode *) * newSize);
+ if (!h->table) {
+ h->table = oldTable;
+ return;
+ }
+ h->length = newSize;
+ h->count = 0;
+ memset(h->table, 0, sizeof(HashNode *) * h->length);
+ for (i = 0; i < oldSize; i++) {
+ for (n = oldTable[i]; n; n = nn) {
+ nn = n->next;
+ _hashtable_insert_node(h, n, 0, 0, cf);
+ }
+ }
+ free(oldTable);
+}
+
+static void
+_hashtable_resize(HashTable *h) {
+ uint32_t newSize;
+ uint32_t oldSize;
+ oldSize = h->length;
+ newSize = oldSize;
+ if (h->count * RESIZE_FACTOR < h->length) {
+ newSize = _findPrime(h->length / 2 - 1, -1);
+ } else if (h->length * RESIZE_FACTOR < h->count) {
+ newSize = _findPrime(h->length * 2 + 1, +1);
+ }
+ if (newSize < MIN_LENGTH) {
+ newSize = oldSize;
+ }
+ if (newSize != oldSize) {
+ _hashtable_rehash(h, NULL, newSize);
+ }
+}
+
+static int
+_hashtable_insert_node(
+ HashTable *h, HashNode *node, int resize, int update, CollisionFunc cf) {
+ uint32_t hash = h->hashFunc(h, node->key) % h->length;
+ HashNode **n, *nv;
+ int i;
+
+ for (n = &(h->table[hash]); *n; n = &((*n)->next)) {
+ nv = *n;
+ i = h->cmpFunc(h, nv->key, node->key);
+ if (!i) {
+ if (cf) {
+ nv->key = node->key;
+ cf(h, &(nv->key), &(nv->value), node->key, node->value);
+ free(node);
+ return 1;
+ } else {
+ nv->key = node->key;
+ nv->value = node->value;
+ free(node);
+ return 1;
+ }
+ } else if (i > 0) {
+ break;
+ }
+ }
+ if (!update) {
+ node->next = *n;
+ *n = node;
+ h->count++;
+ if (resize) {
+ _hashtable_resize(h);
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int
+_hashtable_insert(HashTable *h, HashKey_t key, HashVal_t val, int resize, int update) {
+ HashNode **n, *nv;
+ HashNode *t;
+ int i;
+ uint32_t hash = h->hashFunc(h, key) % h->length;
+
+ for (n = &(h->table[hash]); *n; n = &((*n)->next)) {
+ nv = *n;
+ i = h->cmpFunc(h, nv->key, key);
+ if (!i) {
+ nv->value = val;
+ return 1;
+ } else if (i > 0) {
+ break;
+ }
+ }
+ if (!update) {
+ t = malloc(sizeof(HashNode));
+ if (!t) {
+ return 0;
+ }
+ t->next = *n;
+ *n = t;
+ t->key = key;
+ t->value = val;
+ h->count++;
+ if (resize) {
+ _hashtable_resize(h);
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int
+hashtable_insert_or_update_computed(
+ HashTable *h, HashKey_t key, ComputeFunc newFunc, ComputeFunc existsFunc) {
+ HashNode **n, *nv;
+ HashNode *t;
+ int i;
+ uint32_t hash = h->hashFunc(h, key) % h->length;
+
+ for (n = &(h->table[hash]); *n; n = &((*n)->next)) {
+ nv = *n;
+ i = h->cmpFunc(h, nv->key, key);
+ if (!i) {
+ if (existsFunc) {
+ existsFunc(h, nv->key, &(nv->value));
+ } else {
+ return 0;
+ }
+ return 1;
+ } else if (i > 0) {
+ break;
+ }
+ }
+ t = malloc(sizeof(HashNode));
+ if (!t) {
+ return 0;
+ }
+ t->key = key;
+ t->next = *n;
+ *n = t;
+ if (newFunc) {
+ newFunc(h, t->key, &(t->value));
+ } else {
+ free(t);
+ return 0;
+ }
+ h->count++;
+ _hashtable_resize(h);
+ return 1;
+}
+
+int
+hashtable_insert(HashTable *h, HashKey_t key, HashVal_t val) {
+ return _hashtable_insert(h, key, val, 1, 0);
+}
+
+void
+hashtable_foreach_update(HashTable *h, IteratorUpdateFunc i, void *u) {
+ HashNode *n;
+ uint32_t x;
+
+ if (h->table) {
+ for (x = 0; x < h->length; x++) {
+ for (n = h->table[x]; n; n = n->next) {
+ i(h, n->key, &(n->value), u);
+ }
+ }
+ }
+}
+
+void
+hashtable_foreach(HashTable *h, IteratorFunc i, void *u) {
+ HashNode *n;
+ uint32_t x;
+
+ if (h->table) {
+ for (x = 0; x < h->length; x++) {
+ for (n = h->table[x]; n; n = n->next) {
+ i(h, n->key, n->value, u);
+ }
+ }
+ }
+}
+
+void
+hashtable_free(HashTable *h) {
+ HashNode *n, *nn;
+ uint32_t i;
+
+ if (h->table) {
+ for (i = 0; i < h->length; i++) {
+ for (n = h->table[i]; n; n = nn) {
+ nn = n->next;
+ free(n);
+ }
+ }
+ free(h->table);
+ }
+ free(h);
+}
+
+void
+hashtable_rehash_compute(HashTable *h, CollisionFunc cf) {
+ _hashtable_rehash(h, cf, h->length);
+}
+
+int
+hashtable_lookup(const HashTable *h, const HashKey_t key, HashVal_t *valp) {
+ uint32_t hash = h->hashFunc(h, key) % h->length;
+ HashNode *n;
+ int i;
+
+ for (n = h->table[hash]; n; n = n->next) {
+ i = h->cmpFunc(h, n->key, key);
+ if (!i) {
+ *valp = n->value;
+ return 1;
+ } else if (i > 0) {
+ break;
+ }
+ }
+ return 0;
+}
+
+uint32_t
+hashtable_get_count(const HashTable *h) {
+ return h->count;
+}
+
+void *
+hashtable_get_user_data(const HashTable *h) {
+ return h->userData;
+}
+
+void *
+hashtable_set_user_data(HashTable *h, void *data) {
+ void *r = h->userData;
+ h->userData = data;
+ return r;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/QuantHash.h b/contrib/python/Pillow/py3/libImaging/QuantHash.h
new file mode 100644
index 00000000000..fc1a9900376
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/QuantHash.h
@@ -0,0 +1,55 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * image quantizer
+ *
+ * Written by Toby J Sargeant <[email protected]>.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#ifndef __QUANTHASH_H__
+#define __QUANTHASH_H__
+
+#include "QuantTypes.h"
+
+typedef struct _HashTable HashTable;
+typedef Pixel HashKey_t;
+typedef uint32_t HashVal_t;
+
+typedef uint32_t (*HashFunc)(const HashTable *, const HashKey_t);
+typedef int (*HashCmpFunc)(const HashTable *, const HashKey_t, const HashKey_t);
+typedef void (*IteratorFunc)(
+ const HashTable *, const HashKey_t, const HashVal_t, void *);
+typedef void (*IteratorUpdateFunc)(
+ const HashTable *, const HashKey_t, HashVal_t *, void *);
+typedef void (*ComputeFunc)(const HashTable *, const HashKey_t, HashVal_t *);
+typedef void (*CollisionFunc)(
+ const HashTable *, HashKey_t *, HashVal_t *, HashKey_t, HashVal_t);
+
+HashTable *
+hashtable_new(HashFunc hf, HashCmpFunc cf);
+void
+hashtable_free(HashTable *h);
+void
+hashtable_foreach(HashTable *h, IteratorFunc i, void *u);
+void
+hashtable_foreach_update(HashTable *h, IteratorUpdateFunc i, void *u);
+int
+hashtable_insert(HashTable *h, HashKey_t key, HashVal_t val);
+int
+hashtable_lookup(const HashTable *h, const HashKey_t key, HashVal_t *valp);
+int
+hashtable_insert_or_update_computed(
+ HashTable *h, HashKey_t key, ComputeFunc newFunc, ComputeFunc existsFunc);
+void *
+hashtable_set_user_data(HashTable *h, void *data);
+void *
+hashtable_get_user_data(const HashTable *h);
+uint32_t
+hashtable_get_count(const HashTable *h);
+void
+hashtable_rehash_compute(HashTable *h, CollisionFunc cf);
+
+#endif // __QUANTHASH_H__
diff --git a/contrib/python/Pillow/py3/libImaging/QuantHeap.c b/contrib/python/Pillow/py3/libImaging/QuantHeap.c
new file mode 100644
index 00000000000..6fb52d8902e
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/QuantHeap.c
@@ -0,0 +1,176 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * heap data type used by the image quantizer
+ *
+ * history:
+ * 98-09-10 tjs Contributed
+ * 98-12-29 fl Added to PIL 1.0b1
+ *
+ * Written by Toby J Sargeant <[email protected]>.
+ *
+ * Copyright (c) 1998 by Toby J Sargeant
+ * Copyright (c) 1998 by Secret Labs AB
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <limits.h>
+
+#include "QuantHeap.h"
+
+struct _Heap {
+ void **heap;
+ unsigned int heapsize;
+ unsigned int heapcount;
+ HeapCmpFunc cf;
+};
+
+#define INITIAL_SIZE 256
+
+// #define DEBUG
+
+#ifdef DEBUG
+static int
+_heap_test(Heap *);
+#endif
+
+void
+ImagingQuantHeapFree(Heap *h) {
+ free(h->heap);
+ free(h);
+}
+
+static int
+_heap_grow(Heap *h, unsigned int newsize) {
+ void *newheap;
+ if (!newsize) {
+ newsize = h->heapsize << 1;
+ }
+ if (newsize < h->heapsize) {
+ return 0;
+ }
+ if (newsize > INT_MAX / sizeof(void *)) {
+ return 0;
+ }
+ /* malloc check ok, using calloc for overflow, also checking
+ above due to memcpy below*/
+ newheap = calloc(newsize, sizeof(void *));
+ if (!newheap) {
+ return 0;
+ }
+ memcpy(newheap, h->heap, sizeof(void *) * h->heapsize);
+ free(h->heap);
+ h->heap = newheap;
+ h->heapsize = newsize;
+ return 1;
+}
+
+#ifdef DEBUG
+static int
+_heap_test(Heap *h) {
+ unsigned int k;
+ for (k = 1; k * 2 <= h->heapcount; k++) {
+ if (h->cf(h, h->heap[k], h->heap[k * 2]) < 0) {
+ printf("heap is bad\n");
+ return 0;
+ }
+ if (k * 2 + 1 <= h->heapcount && h->cf(h, h->heap[k], h->heap[k * 2 + 1]) < 0) {
+ printf("heap is bad\n");
+ return 0;
+ }
+ }
+ return 1;
+}
+#endif
+
+int
+ImagingQuantHeapRemove(Heap *h, void **r) {
+ unsigned int k, l;
+ void *v;
+
+ if (!h->heapcount) {
+ return 0;
+ }
+ *r = h->heap[1];
+ v = h->heap[h->heapcount--];
+ for (k = 1; k * 2 <= h->heapcount; k = l) {
+ l = k * 2;
+ if (l < h->heapcount) {
+ if (h->cf(h, h->heap[l], h->heap[l + 1]) < 0) {
+ l++;
+ }
+ }
+ if (h->cf(h, v, h->heap[l]) > 0) {
+ break;
+ }
+ h->heap[k] = h->heap[l];
+ }
+ h->heap[k] = v;
+#ifdef DEBUG
+ if (!_heap_test(h)) {
+ printf("oops - heap_remove messed up the heap\n");
+ exit(1);
+ }
+#endif
+ return 1;
+}
+
+int
+ImagingQuantHeapAdd(Heap *h, void *val) {
+ int k;
+ if (h->heapcount == h->heapsize - 1) {
+ _heap_grow(h, 0);
+ }
+ k = ++h->heapcount;
+ while (k != 1) {
+ if (h->cf(h, val, h->heap[k / 2]) <= 0) {
+ break;
+ }
+ h->heap[k] = h->heap[k / 2];
+ k >>= 1;
+ }
+ h->heap[k] = val;
+#ifdef DEBUG
+ if (!_heap_test(h)) {
+ printf("oops - heap_add messed up the heap\n");
+ exit(1);
+ }
+#endif
+ return 1;
+}
+
+int
+ImagingQuantHeapTop(Heap *h, void **r) {
+ if (!h->heapcount) {
+ return 0;
+ }
+ *r = h->heap[1];
+ return 1;
+}
+
+Heap *
+ImagingQuantHeapNew(HeapCmpFunc cf) {
+ Heap *h;
+
+ /* malloc check ok, small constant allocation */
+ h = malloc(sizeof(Heap));
+ if (!h) {
+ return NULL;
+ }
+ h->heapsize = INITIAL_SIZE;
+ /* malloc check ok, using calloc for overflow */
+ h->heap = calloc(h->heapsize, sizeof(void *));
+ if (!h->heap) {
+ free(h);
+ return NULL;
+ }
+ h->heapcount = 0;
+ h->cf = cf;
+ return h;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/QuantHeap.h b/contrib/python/Pillow/py3/libImaging/QuantHeap.h
new file mode 100644
index 00000000000..c5286dff2ba
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/QuantHeap.h
@@ -0,0 +1,31 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * image quantizer
+ *
+ * Written by Toby J Sargeant <[email protected]>.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#ifndef __QUANTHEAP_H__
+#define __QUANTHEAP_H__
+
+#include "QuantTypes.h"
+
+typedef struct _Heap Heap;
+
+typedef int (*HeapCmpFunc)(const Heap *, const void *, const void *);
+
+void
+ImagingQuantHeapFree(Heap *);
+int
+ImagingQuantHeapRemove(Heap *, void **);
+int
+ImagingQuantHeapAdd(Heap *, void *);
+int
+ImagingQuantHeapTop(Heap *, void **);
+Heap *ImagingQuantHeapNew(HeapCmpFunc);
+
+#endif // __QUANTHEAP_H__
diff --git a/contrib/python/Pillow/py3/libImaging/QuantOctree.c b/contrib/python/Pillow/py3/libImaging/QuantOctree.c
new file mode 100644
index 00000000000..5e79bce358a
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/QuantOctree.c
@@ -0,0 +1,538 @@
+/* Copyright (c) 2010 Oliver Tonnhofer <[email protected]>, Omniscale
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+*/
+
+/*
+// This file implements a variation of the octree color quantization algorithm.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "ImagingUtils.h"
+#include "QuantOctree.h"
+
+typedef struct _ColorBucket {
+ /* contains palette index when used for look up cube */
+ uint32_t count;
+ uint64_t r;
+ uint64_t g;
+ uint64_t b;
+ uint64_t a;
+} * ColorBucket;
+
+typedef struct _ColorCube {
+ unsigned int rBits, gBits, bBits, aBits;
+ unsigned int rWidth, gWidth, bWidth, aWidth;
+ unsigned int rOffset, gOffset, bOffset, aOffset;
+
+ unsigned long size;
+ ColorBucket buckets;
+} * ColorCube;
+
+#define MAX(a, b) (a) > (b) ? (a) : (b)
+
+static ColorCube
+new_color_cube(int r, int g, int b, int a) {
+ ColorCube cube;
+
+ /* malloc check ok, small constant allocation */
+ cube = malloc(sizeof(struct _ColorCube));
+ if (!cube) {
+ return NULL;
+ }
+
+ cube->rBits = MAX(r, 0);
+ cube->gBits = MAX(g, 0);
+ cube->bBits = MAX(b, 0);
+ cube->aBits = MAX(a, 0);
+
+ /* overflow check for size multiplication below */
+ if (cube->rBits + cube->gBits + cube->bBits + cube->aBits > 31) {
+ free(cube);
+ return NULL;
+ }
+
+ /* the width of the cube for each dimension */
+ cube->rWidth = 1 << cube->rBits;
+ cube->gWidth = 1 << cube->gBits;
+ cube->bWidth = 1 << cube->bBits;
+ cube->aWidth = 1 << cube->aBits;
+
+ /* the offsets of each color */
+
+ cube->rOffset = cube->gBits + cube->bBits + cube->aBits;
+ cube->gOffset = cube->bBits + cube->aBits;
+ cube->bOffset = cube->aBits;
+ cube->aOffset = 0;
+
+ /* the number of color buckets */
+ cube->size = cube->rWidth * cube->gWidth * cube->bWidth * cube->aWidth;
+ /* malloc check ok, overflow checked above */
+ cube->buckets = calloc(cube->size, sizeof(struct _ColorBucket));
+
+ if (!cube->buckets) {
+ free(cube);
+ return NULL;
+ }
+ return cube;
+}
+
+static void
+free_color_cube(ColorCube cube) {
+ if (cube != NULL) {
+ free(cube->buckets);
+ free(cube);
+ }
+}
+
+static long
+color_bucket_offset_pos(
+ const ColorCube cube,
+ unsigned int r,
+ unsigned int g,
+ unsigned int b,
+ unsigned int a) {
+ return r << cube->rOffset | g << cube->gOffset | b << cube->bOffset |
+ a << cube->aOffset;
+}
+
+static long
+color_bucket_offset(const ColorCube cube, const Pixel *p) {
+ unsigned int r = p->c.r >> (8 - cube->rBits);
+ unsigned int g = p->c.g >> (8 - cube->gBits);
+ unsigned int b = p->c.b >> (8 - cube->bBits);
+ unsigned int a = p->c.a >> (8 - cube->aBits);
+ return color_bucket_offset_pos(cube, r, g, b, a);
+}
+
+static ColorBucket
+color_bucket_from_cube(const ColorCube cube, const Pixel *p) {
+ unsigned int offset = color_bucket_offset(cube, p);
+ return &cube->buckets[offset];
+}
+
+static void
+add_color_to_color_cube(const ColorCube cube, const Pixel *p) {
+ ColorBucket bucket = color_bucket_from_cube(cube, p);
+ bucket->count += 1;
+ bucket->r += p->c.r;
+ bucket->g += p->c.g;
+ bucket->b += p->c.b;
+ bucket->a += p->c.a;
+}
+
+static unsigned long
+count_used_color_buckets(const ColorCube cube) {
+ unsigned long usedBuckets = 0;
+ unsigned long i;
+ for (i = 0; i < cube->size; i++) {
+ if (cube->buckets[i].count > 0) {
+ usedBuckets += 1;
+ }
+ }
+ return usedBuckets;
+}
+
+static void
+avg_color_from_color_bucket(const ColorBucket bucket, Pixel *dst) {
+ float count = bucket->count;
+ if (count != 0) {
+ dst->c.r = CLIP8((int)(bucket->r / count));
+ dst->c.g = CLIP8((int)(bucket->g / count));
+ dst->c.b = CLIP8((int)(bucket->b / count));
+ dst->c.a = CLIP8((int)(bucket->a / count));
+ } else {
+ dst->c.r = 0;
+ dst->c.g = 0;
+ dst->c.b = 0;
+ dst->c.a = 0;
+ }
+}
+
+static int
+compare_bucket_count(const ColorBucket a, const ColorBucket b) {
+ return b->count - a->count;
+}
+
+static ColorBucket
+create_sorted_color_palette(const ColorCube cube) {
+ ColorBucket buckets;
+ if (cube->size > LONG_MAX / sizeof(struct _ColorBucket)) {
+ return NULL;
+ }
+ /* malloc check ok, calloc + overflow check above for memcpy */
+ buckets = calloc(cube->size, sizeof(struct _ColorBucket));
+ if (!buckets) {
+ return NULL;
+ }
+ memcpy(buckets, cube->buckets, sizeof(struct _ColorBucket) * cube->size);
+
+ qsort(
+ buckets,
+ cube->size,
+ sizeof(struct _ColorBucket),
+ (int (*)(void const *, void const *)) & compare_bucket_count);
+
+ return buckets;
+}
+
+void
+add_bucket_values(ColorBucket src, ColorBucket dst) {
+ dst->count += src->count;
+ dst->r += src->r;
+ dst->g += src->g;
+ dst->b += src->b;
+ dst->a += src->a;
+}
+
+/* expand or shrink a given cube to level */
+static ColorCube
+copy_color_cube(
+ const ColorCube cube,
+ unsigned int rBits,
+ unsigned int gBits,
+ unsigned int bBits,
+ unsigned int aBits) {
+ unsigned int r, g, b, a;
+ long src_pos, dst_pos;
+ unsigned int src_reduce[4] = {0}, dst_reduce[4] = {0};
+ unsigned int width[4];
+ ColorCube result;
+
+ result = new_color_cube(rBits, gBits, bBits, aBits);
+ if (!result) {
+ return NULL;
+ }
+
+ if (cube->rBits > rBits) {
+ dst_reduce[0] = cube->rBits - result->rBits;
+ width[0] = cube->rWidth;
+ } else {
+ src_reduce[0] = result->rBits - cube->rBits;
+ width[0] = result->rWidth;
+ }
+ if (cube->gBits > gBits) {
+ dst_reduce[1] = cube->gBits - result->gBits;
+ width[1] = cube->gWidth;
+ } else {
+ src_reduce[1] = result->gBits - cube->gBits;
+ width[1] = result->gWidth;
+ }
+ if (cube->bBits > bBits) {
+ dst_reduce[2] = cube->bBits - result->bBits;
+ width[2] = cube->bWidth;
+ } else {
+ src_reduce[2] = result->bBits - cube->bBits;
+ width[2] = result->bWidth;
+ }
+ if (cube->aBits > aBits) {
+ dst_reduce[3] = cube->aBits - result->aBits;
+ width[3] = cube->aWidth;
+ } else {
+ src_reduce[3] = result->aBits - cube->aBits;
+ width[3] = result->aWidth;
+ }
+
+ for (r = 0; r < width[0]; r++) {
+ for (g = 0; g < width[1]; g++) {
+ for (b = 0; b < width[2]; b++) {
+ for (a = 0; a < width[3]; a++) {
+ src_pos = color_bucket_offset_pos(
+ cube,
+ r >> src_reduce[0],
+ g >> src_reduce[1],
+ b >> src_reduce[2],
+ a >> src_reduce[3]);
+ dst_pos = color_bucket_offset_pos(
+ result,
+ r >> dst_reduce[0],
+ g >> dst_reduce[1],
+ b >> dst_reduce[2],
+ a >> dst_reduce[3]);
+ add_bucket_values(
+ &cube->buckets[src_pos], &result->buckets[dst_pos]);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+void
+subtract_color_buckets(ColorCube cube, ColorBucket buckets, long nBuckets) {
+ ColorBucket minuend, subtrahend;
+ long i;
+ Pixel p;
+ for (i = 0; i < nBuckets; i++) {
+ subtrahend = &buckets[i];
+
+ // If the subtrahend contains no buckets, there is nothing to subtract.
+ if (subtrahend->count == 0) {
+ continue;
+ }
+
+ avg_color_from_color_bucket(subtrahend, &p);
+ minuend = color_bucket_from_cube(cube, &p);
+ minuend->count -= subtrahend->count;
+ minuend->r -= subtrahend->r;
+ minuend->g -= subtrahend->g;
+ minuend->b -= subtrahend->b;
+ minuend->a -= subtrahend->a;
+ }
+}
+
+static void
+set_lookup_value(const ColorCube cube, const Pixel *p, long value) {
+ ColorBucket bucket = color_bucket_from_cube(cube, p);
+ bucket->count = value;
+}
+
+uint64_t
+lookup_color(const ColorCube cube, const Pixel *p) {
+ ColorBucket bucket = color_bucket_from_cube(cube, p);
+ return bucket->count;
+}
+
+void
+add_lookup_buckets(ColorCube cube, ColorBucket palette, long nColors, long offset) {
+ long i;
+ Pixel p;
+ for (i = offset + nColors - 1; i >= offset; i--) {
+ avg_color_from_color_bucket(&palette[i], &p);
+ set_lookup_value(cube, &p, i);
+ }
+}
+
+ColorBucket
+combined_palette(
+ ColorBucket bucketsA,
+ unsigned long nBucketsA,
+ ColorBucket bucketsB,
+ unsigned long nBucketsB) {
+ ColorBucket result;
+ if (nBucketsA > LONG_MAX - nBucketsB ||
+ (nBucketsA + nBucketsB) > LONG_MAX / sizeof(struct _ColorBucket)) {
+ return NULL;
+ }
+ /* malloc check ok, overflow check above */
+ result = calloc(nBucketsA + nBucketsB, sizeof(struct _ColorBucket));
+ if (!result) {
+ return NULL;
+ }
+ memcpy(result, bucketsA, sizeof(struct _ColorBucket) * nBucketsA);
+ memcpy(&result[nBucketsA], bucketsB, sizeof(struct _ColorBucket) * nBucketsB);
+ return result;
+}
+
+static Pixel *
+create_palette_array(const ColorBucket palette, unsigned int paletteLength) {
+ Pixel *paletteArray;
+ unsigned int i;
+
+ /* malloc check ok, calloc for overflow */
+ paletteArray = calloc(paletteLength, sizeof(Pixel));
+ if (!paletteArray) {
+ return NULL;
+ }
+
+ for (i = 0; i < paletteLength; i++) {
+ avg_color_from_color_bucket(&palette[i], &paletteArray[i]);
+ }
+ return paletteArray;
+}
+
+static void
+map_image_pixels(
+ const Pixel *pixelData,
+ uint32_t nPixels,
+ const ColorCube lookupCube,
+ uint32_t *pixelArray) {
+ long i;
+ for (i = 0; i < nPixels; i++) {
+ pixelArray[i] = lookup_color(lookupCube, &pixelData[i]);
+ }
+}
+
+const unsigned int CUBE_LEVELS[8] = {4, 4, 4, 0, 2, 2, 2, 0};
+const unsigned int CUBE_LEVELS_ALPHA[8] = {3, 4, 3, 3, 2, 2, 2, 2};
+
+int
+quantize_octree(
+ Pixel *pixelData,
+ uint32_t nPixels,
+ uint32_t nQuantPixels,
+ Pixel **palette,
+ uint32_t *paletteLength,
+ uint32_t **quantizedPixels,
+ int withAlpha) {
+ ColorCube fineCube = NULL;
+ ColorCube coarseCube = NULL;
+ ColorCube lookupCube = NULL;
+ ColorCube coarseLookupCube = NULL;
+ ColorBucket paletteBucketsCoarse = NULL;
+ ColorBucket paletteBucketsFine = NULL;
+ ColorBucket paletteBuckets = NULL;
+ uint32_t *qp = NULL;
+ long i;
+ unsigned long nCoarseColors, nFineColors, nAlreadySubtracted;
+ const unsigned int *cubeBits;
+
+ if (withAlpha) {
+ cubeBits = CUBE_LEVELS_ALPHA;
+ } else {
+ cubeBits = CUBE_LEVELS;
+ }
+
+ /*
+ Create two color cubes, one fine grained with 8x16x8=1024
+ colors buckets and a coarse with 4x4x4=64 color buckets.
+ The coarse one guarantees that there are color buckets available for
+ the whole color range (assuming nQuantPixels > 64).
+
+ For a quantization to 256 colors all 64 coarse colors will be used
+ plus the 192 most used color buckets from the fine color cube.
+ The average of all colors within one bucket is used as the actual
+ color for that bucket.
+
+ For images with alpha the cubes gets a forth dimension,
+ 8x16x8x8 and 4x4x4x4.
+ */
+
+ /* create fine cube */
+ fineCube = new_color_cube(cubeBits[0], cubeBits[1], cubeBits[2], cubeBits[3]);
+ if (!fineCube) {
+ goto error;
+ }
+ for (i = 0; i < nPixels; i++) {
+ add_color_to_color_cube(fineCube, &pixelData[i]);
+ }
+
+ /* create coarse cube */
+ coarseCube =
+ copy_color_cube(fineCube, cubeBits[4], cubeBits[5], cubeBits[6], cubeBits[7]);
+ if (!coarseCube) {
+ goto error;
+ }
+ nCoarseColors = count_used_color_buckets(coarseCube);
+
+ /* limit to nQuantPixels */
+ if (nCoarseColors > nQuantPixels) {
+ nCoarseColors = nQuantPixels;
+ }
+
+ /* how many space do we have in our palette for fine colors? */
+ nFineColors = nQuantPixels - nCoarseColors;
+
+ /* create fine color palette */
+ paletteBucketsFine = create_sorted_color_palette(fineCube);
+ if (!paletteBucketsFine) {
+ goto error;
+ }
+
+ /* remove the used fine colors from the coarse cube */
+ subtract_color_buckets(coarseCube, paletteBucketsFine, nFineColors);
+
+ /* did the subtraction cleared one or more coarse bucket? */
+ while (nCoarseColors > count_used_color_buckets(coarseCube)) {
+ /* then we can use the free buckets for fine colors */
+ nAlreadySubtracted = nFineColors;
+ nCoarseColors = count_used_color_buckets(coarseCube);
+ nFineColors = nQuantPixels - nCoarseColors;
+ subtract_color_buckets(
+ coarseCube,
+ &paletteBucketsFine[nAlreadySubtracted],
+ nFineColors - nAlreadySubtracted);
+ }
+
+ /* create our palette buckets with fine and coarse combined */
+ paletteBucketsCoarse = create_sorted_color_palette(coarseCube);
+ if (!paletteBucketsCoarse) {
+ goto error;
+ }
+ paletteBuckets = combined_palette(
+ paletteBucketsCoarse, nCoarseColors, paletteBucketsFine, nFineColors);
+
+ free(paletteBucketsFine);
+ paletteBucketsFine = NULL;
+ free(paletteBucketsCoarse);
+ paletteBucketsCoarse = NULL;
+ if (!paletteBuckets) {
+ goto error;
+ }
+
+ /* add all coarse colors to our coarse lookup cube. */
+ coarseLookupCube =
+ new_color_cube(cubeBits[4], cubeBits[5], cubeBits[6], cubeBits[7]);
+ if (!coarseLookupCube) {
+ goto error;
+ }
+ add_lookup_buckets(coarseLookupCube, paletteBuckets, nCoarseColors, 0);
+
+ /* expand coarse cube (64) to larger fine cube (4k). the value of each
+ coarse bucket is then present in the according 64 fine buckets. */
+ lookupCube = copy_color_cube(
+ coarseLookupCube, cubeBits[0], cubeBits[1], cubeBits[2], cubeBits[3]);
+ if (!lookupCube) {
+ goto error;
+ }
+
+ /* add fine colors to the lookup cube */
+ add_lookup_buckets(lookupCube, paletteBuckets, nFineColors, nCoarseColors);
+
+ /* create result pixels and map palette indices */
+ /* malloc check ok, calloc for overflow */
+ qp = calloc(nPixels, sizeof(Pixel));
+ if (!qp) {
+ goto error;
+ }
+ map_image_pixels(pixelData, nPixels, lookupCube, qp);
+
+ /* convert palette buckets to RGB pixel palette */
+ *palette = create_palette_array(paletteBuckets, nQuantPixels);
+ if (!(*palette)) {
+ goto error;
+ }
+
+ *quantizedPixels = qp;
+ *paletteLength = nQuantPixels;
+
+ free_color_cube(coarseCube);
+ free_color_cube(fineCube);
+ free_color_cube(lookupCube);
+ free_color_cube(coarseLookupCube);
+ free(paletteBuckets);
+ return 1;
+
+error:
+ /* everything is initialized to NULL
+ so we are safe to call free */
+ free(qp);
+ free_color_cube(lookupCube);
+ free_color_cube(coarseLookupCube);
+ free(paletteBuckets);
+ free(paletteBucketsCoarse);
+ free(paletteBucketsFine);
+ free_color_cube(coarseCube);
+ free_color_cube(fineCube);
+ return 0;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/QuantOctree.h b/contrib/python/Pillow/py3/libImaging/QuantOctree.h
new file mode 100644
index 00000000000..e1c50407402
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/QuantOctree.h
@@ -0,0 +1,9 @@
+#ifndef __QUANT_OCTREE_H__
+#define __QUANT_OCTREE_H__
+
+#include "QuantTypes.h"
+
+int
+quantize_octree(Pixel *, uint32_t, uint32_t, Pixel **, uint32_t *, uint32_t **, int);
+
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/QuantPngQuant.c b/contrib/python/Pillow/py3/libImaging/QuantPngQuant.c
new file mode 100644
index 00000000000..7a36300e408
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/QuantPngQuant.c
@@ -0,0 +1,132 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * quantization using libimagequant, a part of pngquant.
+ *
+ * Copyright (c) 2016 Marcin Kurczewski <[email protected]>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "QuantPngQuant.h"
+
+#ifdef HAVE_LIBIMAGEQUANT
+#include "libimagequant.h"
+
+int
+quantize_pngquant(
+ Pixel *pixelData,
+ unsigned int width,
+ unsigned int height,
+ uint32_t quantPixels,
+ Pixel **palette,
+ uint32_t *paletteLength,
+ uint32_t **quantizedPixels,
+ int withAlpha) {
+ int result = 0;
+ liq_image *image = NULL;
+ liq_attr *attr = NULL;
+ liq_result *remap = NULL;
+ unsigned char *charMatrix = NULL;
+ unsigned char **charMatrixRows = NULL;
+ unsigned int i, y;
+ *palette = NULL;
+ *paletteLength = 0;
+ *quantizedPixels = NULL;
+
+ /* configure pngquant */
+ attr = liq_attr_create();
+ if (!attr) {
+ goto err;
+ }
+ if (quantPixels) {
+ liq_set_max_colors(attr, quantPixels);
+ }
+
+ /* prepare input image */
+ image = liq_image_create_rgba(attr, pixelData, width, height, 0.45455 /* gamma */);
+ if (!image) {
+ goto err;
+ }
+
+ /* quantize the image */
+ remap = liq_quantize_image(attr, image);
+ if (!remap) {
+ goto err;
+ }
+ liq_set_output_gamma(remap, 0.45455);
+ liq_set_dithering_level(remap, 1);
+
+ /* write output palette */
+ const liq_palette *l_palette = liq_get_palette(remap);
+ *paletteLength = l_palette->count;
+ *palette = malloc(sizeof(Pixel) * l_palette->count);
+ if (!*palette) {
+ goto err;
+ }
+ for (i = 0; i < l_palette->count; i++) {
+ (*palette)[i].c.b = l_palette->entries[i].b;
+ (*palette)[i].c.g = l_palette->entries[i].g;
+ (*palette)[i].c.r = l_palette->entries[i].r;
+ (*palette)[i].c.a = l_palette->entries[i].a;
+ }
+
+ /* write output pixels (pngquant uses char array) */
+ charMatrix = malloc(width * height);
+ if (!charMatrix) {
+ goto err;
+ }
+ charMatrixRows = malloc(height * sizeof(unsigned char *));
+ if (!charMatrixRows) {
+ goto err;
+ }
+ for (y = 0; y < height; y++) {
+ charMatrixRows[y] = &charMatrix[y * width];
+ }
+ if (LIQ_OK != liq_write_remapped_image_rows(remap, image, charMatrixRows)) {
+ goto err;
+ }
+
+ /* transcribe output pixels (pillow uses uint32_t array) */
+ *quantizedPixels = malloc(sizeof(uint32_t) * width * height);
+ if (!*quantizedPixels) {
+ goto err;
+ }
+ for (i = 0; i < width * height; i++) {
+ (*quantizedPixels)[i] = charMatrix[i];
+ }
+
+ result = 1;
+
+err:
+ if (attr) {
+ liq_attr_destroy(attr);
+ }
+ if (image) {
+ liq_image_destroy(image);
+ }
+ if (remap) {
+ liq_result_destroy(remap);
+ }
+ free(charMatrix);
+ free(charMatrixRows);
+ if (!result) {
+ free(*quantizedPixels);
+ free(*palette);
+ }
+ return result;
+}
+
+const char *
+ImagingImageQuantVersion(void) {
+ static char version[20];
+ int number = liq_version();
+ sprintf(version, "%d.%d.%d", number / 10000, (number / 100) % 100, number % 100);
+ return version;
+}
+
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/QuantPngQuant.h b/contrib/python/Pillow/py3/libImaging/QuantPngQuant.h
new file mode 100644
index 00000000000..d65e42590ca
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/QuantPngQuant.h
@@ -0,0 +1,17 @@
+#ifndef __QUANT_PNGQUANT_H__
+#define __QUANT_PNGQUANT_H__
+
+#include "QuantTypes.h"
+
+int
+quantize_pngquant(
+ Pixel *,
+ unsigned int,
+ unsigned int,
+ uint32_t,
+ Pixel **,
+ uint32_t *,
+ uint32_t **,
+ int);
+
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/QuantTypes.h b/contrib/python/Pillow/py3/libImaging/QuantTypes.h
new file mode 100644
index 00000000000..986b70806dc
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/QuantTypes.h
@@ -0,0 +1,32 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * image quantizer
+ *
+ * Written by Toby J Sargeant <[email protected]>.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#ifndef __TYPES_H__
+#define __TYPES_H__
+
+#ifdef _MSC_VER
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#else
+#include <stdint.h>
+#endif
+
+typedef union {
+ struct {
+ unsigned char r, g, b, a;
+ } c;
+ struct {
+ unsigned char v[4];
+ } a;
+ uint32_t v;
+} Pixel;
+
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/RankFilter.c b/contrib/python/Pillow/py3/libImaging/RankFilter.c
new file mode 100644
index 00000000000..73a6baecbb2
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/RankFilter.c
@@ -0,0 +1,132 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * min, max, median filters
+ *
+ * history:
+ * 2002-06-08 fl Created
+ *
+ * Copyright (c) Secret Labs AB 2002. All rights reserved.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+/* Fast rank algorithm (due to Wirth), based on public domain code
+ by Nicolas Devillard, available at http://ndevilla.free.fr */
+
+#define SWAP(type, a, b) \
+ { \
+ register type t = (a); \
+ (a) = (b); \
+ (b) = t; \
+ }
+
+#define MakeRankFunction(type) \
+ static type Rank##type(type a[], int n, int k) { \
+ register int i, j, l, m; \
+ register type x; \
+ l = 0; \
+ m = n - 1; \
+ while (l < m) { \
+ x = a[k]; \
+ i = l; \
+ j = m; \
+ do { \
+ while (a[i] < x) { \
+ i++; \
+ } \
+ while (x < a[j]) { \
+ j--; \
+ } \
+ if (i <= j) { \
+ SWAP(type, a[i], a[j]); \
+ i++; \
+ j--; \
+ } \
+ } while (i <= j); \
+ if (j < k) { \
+ l = i; \
+ } \
+ if (k < i) { \
+ m = j; \
+ } \
+ } \
+ return a[k]; \
+ }
+
+MakeRankFunction(UINT8) MakeRankFunction(INT32) MakeRankFunction(FLOAT32)
+
+ Imaging ImagingRankFilter(Imaging im, int size, int rank) {
+ Imaging imOut = NULL;
+ int x, y;
+ int i, margin, size2;
+
+ if (!im || im->bands != 1 || im->type == IMAGING_TYPE_SPECIAL) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ if (!(size & 1)) {
+ return (Imaging)ImagingError_ValueError("bad filter size");
+ }
+
+ /* malloc check ok, for overflow in the define below */
+ if (size > INT_MAX / size || size > INT_MAX / (size * (int)sizeof(FLOAT32))) {
+ return (Imaging)ImagingError_ValueError("filter size too large");
+ }
+
+ size2 = size * size;
+ margin = (size - 1) / 2;
+
+ if (rank < 0 || rank >= size2) {
+ return (Imaging)ImagingError_ValueError("bad rank value");
+ }
+
+ imOut = ImagingNew(im->mode, im->xsize - 2 * margin, im->ysize - 2 * margin);
+ if (!imOut) {
+ return NULL;
+ }
+
+ /* malloc check ok, checked above */
+#define RANK_BODY(type) \
+ do { \
+ type *buf = malloc(size2 * sizeof(type)); \
+ if (!buf) { \
+ goto nomemory; \
+ } \
+ for (y = 0; y < imOut->ysize; y++) { \
+ for (x = 0; x < imOut->xsize; x++) { \
+ for (i = 0; i < size; i++) { \
+ memcpy( \
+ buf + i * size, \
+ &IMAGING_PIXEL_##type(im, x, y + i), \
+ size * sizeof(type)); \
+ } \
+ IMAGING_PIXEL_##type(imOut, x, y) = Rank##type(buf, size2, rank); \
+ } \
+ } \
+ free(buf); \
+ } while (0)
+
+ if (im->image8) {
+ RANK_BODY(UINT8);
+ } else if (im->type == IMAGING_TYPE_INT32) {
+ RANK_BODY(INT32);
+ } else if (im->type == IMAGING_TYPE_FLOAT32) {
+ RANK_BODY(FLOAT32);
+ } else {
+ /* safety net (we shouldn't end up here) */
+ ImagingDelete(imOut);
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ ImagingCopyPalette(imOut, im);
+
+ return imOut;
+
+nomemory:
+ ImagingDelete(imOut);
+ return (Imaging)ImagingError_MemoryError();
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Raw.h b/contrib/python/Pillow/py3/libImaging/Raw.h
new file mode 100644
index 00000000000..ab718837f4a
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Raw.h
@@ -0,0 +1,14 @@
+/* Raw.h */
+
+typedef struct {
+ /* CONFIGURATION */
+
+ /* Distance between lines (0=no padding) */
+ int stride;
+
+ /* PRIVATE (initialized by decoder) */
+
+ /* Padding between lines */
+ int skip;
+
+} RAWSTATE;
diff --git a/contrib/python/Pillow/py3/libImaging/RawDecode.c b/contrib/python/Pillow/py3/libImaging/RawDecode.c
new file mode 100644
index 00000000000..24abe48041f
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/RawDecode.c
@@ -0,0 +1,91 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for raw (uncompressed) image data
+ *
+ * history:
+ * 96-03-07 fl rewritten
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#include "Raw.h"
+
+int
+ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ enum { LINE = 1, SKIP };
+ RAWSTATE *rawstate = state->context;
+
+ UINT8 *ptr;
+
+ if (state->state == 0) {
+ /* Initialize context variables */
+
+ /* get size of image data and padding */
+ state->bytes = (state->xsize * state->bits + 7) / 8;
+ if (rawstate->stride) {
+ rawstate->skip = rawstate->stride - state->bytes;
+ if (rawstate->skip < 0) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+ } else {
+ rawstate->skip = 0;
+ }
+
+ /* check image orientation */
+ if (state->ystep < 0) {
+ state->y = state->ysize - 1;
+ state->ystep = -1;
+ } else {
+ state->ystep = 1;
+ }
+
+ state->state = LINE;
+ }
+
+ ptr = buf;
+
+ for (;;) {
+ if (state->state == SKIP) {
+ /* Skip padding between lines */
+
+ if (bytes < rawstate->skip) {
+ return ptr - buf;
+ }
+
+ ptr += rawstate->skip;
+ bytes -= rawstate->skip;
+
+ state->state = LINE;
+ }
+
+ if (bytes < state->bytes) {
+ return ptr - buf;
+ }
+
+ /* Unpack data */
+ state->shuffle(
+ (UINT8 *)im->image[state->y + state->yoff] + state->xoff * im->pixelsize,
+ ptr,
+ state->xsize);
+
+ ptr += state->bytes;
+ bytes -= state->bytes;
+
+ state->y += state->ystep;
+
+ if (state->y < 0 || state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+
+ state->state = SKIP;
+ }
+}
diff --git a/contrib/python/Pillow/py3/libImaging/RawEncode.c b/contrib/python/Pillow/py3/libImaging/RawEncode.c
new file mode 100644
index 00000000000..50de8d98275
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/RawEncode.c
@@ -0,0 +1,87 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * coder for raw data
+ *
+ * FIXME: This encoder will fail if the buffer is not large enough to
+ * hold one full line of data. There's a workaround for this problem
+ * in ImageFile.py, but it should be solved here instead.
+ *
+ * history:
+ * 96-04-30 fl created
+ * 97-01-03 fl fixed padding
+ *
+ * Copyright (c) Fredrik Lundh 1996-97.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution. */
+
+#include "Imaging.h"
+
+int
+ImagingRawEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
+ UINT8 *ptr;
+
+ if (!state->state) {
+ /* The "count" field holds the stride, if specified. Fix
+ things up so "bytes" is the full size, and "count" the
+ packed size */
+
+ if (state->count > 0) {
+ int bytes = state->count;
+
+ /* stride must not be less than real size */
+ if (state->count < state->bytes) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+ state->count = state->bytes;
+ state->bytes = bytes;
+ } else {
+ state->count = state->bytes;
+ }
+
+ /* The "ystep" field specifies the orientation */
+
+ if (state->ystep < 0) {
+ state->y = state->ysize - 1;
+ state->ystep = -1;
+ } else {
+ state->ystep = 1;
+ }
+
+ state->state = 1;
+ }
+
+ if (bytes < state->bytes) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return 0;
+ }
+
+ ptr = buf;
+
+ while (bytes >= state->bytes) {
+ state->shuffle(
+ ptr,
+ (UINT8 *)im->image[state->y + state->yoff] + state->xoff * im->pixelsize,
+ state->xsize);
+
+ if (state->bytes > state->count) {
+ /* zero-pad the buffer, if necessary */
+ memset(ptr + state->count, 0, state->bytes - state->count);
+ }
+
+ ptr += state->bytes;
+ bytes -= state->bytes;
+
+ state->y += state->ystep;
+
+ if (state->y < 0 || state->y >= state->ysize) {
+ state->errcode = IMAGING_CODEC_END;
+ break;
+ }
+ }
+
+ return ptr - buf;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Reduce.c b/contrib/python/Pillow/py3/libImaging/Reduce.c
new file mode 100644
index 00000000000..60928d2bc36
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Reduce.c
@@ -0,0 +1,1483 @@
+#include "Imaging.h"
+
+#include <math.h>
+
+#define ROUND_UP(f) ((int)((f) >= 0.0 ? (f) + 0.5F : (f)-0.5F))
+
+UINT32
+division_UINT32(int divider, int result_bits) {
+ UINT32 max_dividend = (1 << result_bits) * divider;
+ float max_int = (1 << 30) * 4.0;
+ return (UINT32)(max_int / max_dividend);
+}
+
+void
+ImagingReduceNxN(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) {
+ /* The most general implementation for any xscale and yscale
+ */
+ int x, y, xx, yy;
+ UINT32 multiplier = division_UINT32(yscale * xscale, 8);
+ UINT32 amend = yscale * xscale / 2;
+
+ if (imIn->image8) {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy_from = box[1] + y * yscale;
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ UINT32 ss = amend;
+ for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) {
+ UINT8 *line0 = (UINT8 *)imIn->image8[yy];
+ UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1];
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss += line0[xx + 0] + line0[xx + 1] + line1[xx + 0] +
+ line1[xx + 1];
+ }
+ if (xscale & 0x01) {
+ ss += line0[xx + 0] + line1[xx + 0];
+ }
+ }
+ if (yscale & 0x01) {
+ UINT8 *line = (UINT8 *)imIn->image8[yy];
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss += line[xx + 0] + line[xx + 1];
+ }
+ if (xscale & 0x01) {
+ ss += line[xx + 0];
+ }
+ }
+ imOut->image8[y][x] = (ss * multiplier) >> 24;
+ }
+ }
+ } else {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy_from = box[1] + y * yscale;
+ if (imIn->bands == 2) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ UINT32 v;
+ UINT32 ss0 = amend, ss3 = amend;
+ for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) {
+ UINT8 *line0 = (UINT8 *)imIn->image[yy];
+ UINT8 *line1 = (UINT8 *)imIn->image[yy + 1];
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss0 += line0[xx * 4 + 0] + line0[xx * 4 + 4] +
+ line1[xx * 4 + 0] + line1[xx * 4 + 4];
+ ss3 += line0[xx * 4 + 3] + line0[xx * 4 + 7] +
+ line1[xx * 4 + 3] + line1[xx * 4 + 7];
+ }
+ if (xscale & 0x01) {
+ ss0 += line0[xx * 4 + 0] + line1[xx * 4 + 0];
+ ss3 += line0[xx * 4 + 3] + line1[xx * 4 + 3];
+ }
+ }
+ if (yscale & 0x01) {
+ UINT8 *line = (UINT8 *)imIn->image[yy];
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss0 += line[xx * 4 + 0] + line[xx * 4 + 4];
+ ss3 += line[xx * 4 + 3] + line[xx * 4 + 7];
+ }
+ if (xscale & 0x01) {
+ ss0 += line[xx * 4 + 0];
+ ss3 += line[xx * 4 + 3];
+ }
+ }
+ v = MAKE_UINT32(
+ (ss0 * multiplier) >> 24, 0, 0, (ss3 * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (imIn->bands == 3) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ UINT32 v;
+ UINT32 ss0 = amend, ss1 = amend, ss2 = amend;
+ for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) {
+ UINT8 *line0 = (UINT8 *)imIn->image[yy];
+ UINT8 *line1 = (UINT8 *)imIn->image[yy + 1];
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss0 += line0[xx * 4 + 0] + line0[xx * 4 + 4] +
+ line1[xx * 4 + 0] + line1[xx * 4 + 4];
+ ss1 += line0[xx * 4 + 1] + line0[xx * 4 + 5] +
+ line1[xx * 4 + 1] + line1[xx * 4 + 5];
+ ss2 += line0[xx * 4 + 2] + line0[xx * 4 + 6] +
+ line1[xx * 4 + 2] + line1[xx * 4 + 6];
+ }
+ if (xscale & 0x01) {
+ ss0 += line0[xx * 4 + 0] + line1[xx * 4 + 0];
+ ss1 += line0[xx * 4 + 1] + line1[xx * 4 + 1];
+ ss2 += line0[xx * 4 + 2] + line1[xx * 4 + 2];
+ }
+ }
+ if (yscale & 0x01) {
+ UINT8 *line = (UINT8 *)imIn->image[yy];
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss0 += line[xx * 4 + 0] + line[xx * 4 + 4];
+ ss1 += line[xx * 4 + 1] + line[xx * 4 + 5];
+ ss2 += line[xx * 4 + 2] + line[xx * 4 + 6];
+ }
+ if (xscale & 0x01) {
+ ss0 += line[xx * 4 + 0];
+ ss1 += line[xx * 4 + 1];
+ ss2 += line[xx * 4 + 2];
+ }
+ }
+ v = MAKE_UINT32(
+ (ss0 * multiplier) >> 24,
+ (ss1 * multiplier) >> 24,
+ (ss2 * multiplier) >> 24,
+ 0);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else { // bands == 4
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ UINT32 v;
+ UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend;
+ for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) {
+ UINT8 *line0 = (UINT8 *)imIn->image[yy];
+ UINT8 *line1 = (UINT8 *)imIn->image[yy + 1];
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss0 += line0[xx * 4 + 0] + line0[xx * 4 + 4] +
+ line1[xx * 4 + 0] + line1[xx * 4 + 4];
+ ss1 += line0[xx * 4 + 1] + line0[xx * 4 + 5] +
+ line1[xx * 4 + 1] + line1[xx * 4 + 5];
+ ss2 += line0[xx * 4 + 2] + line0[xx * 4 + 6] +
+ line1[xx * 4 + 2] + line1[xx * 4 + 6];
+ ss3 += line0[xx * 4 + 3] + line0[xx * 4 + 7] +
+ line1[xx * 4 + 3] + line1[xx * 4 + 7];
+ }
+ if (xscale & 0x01) {
+ ss0 += line0[xx * 4 + 0] + line1[xx * 4 + 0];
+ ss1 += line0[xx * 4 + 1] + line1[xx * 4 + 1];
+ ss2 += line0[xx * 4 + 2] + line1[xx * 4 + 2];
+ ss3 += line0[xx * 4 + 3] + line1[xx * 4 + 3];
+ }
+ }
+ if (yscale & 0x01) {
+ UINT8 *line = (UINT8 *)imIn->image[yy];
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss0 += line[xx * 4 + 0] + line[xx * 4 + 4];
+ ss1 += line[xx * 4 + 1] + line[xx * 4 + 5];
+ ss2 += line[xx * 4 + 2] + line[xx * 4 + 6];
+ ss3 += line[xx * 4 + 3] + line[xx * 4 + 7];
+ }
+ if (xscale & 0x01) {
+ ss0 += line[xx * 4 + 0];
+ ss1 += line[xx * 4 + 1];
+ ss2 += line[xx * 4 + 2];
+ ss3 += line[xx * 4 + 3];
+ }
+ }
+ v = MAKE_UINT32(
+ (ss0 * multiplier) >> 24,
+ (ss1 * multiplier) >> 24,
+ (ss2 * multiplier) >> 24,
+ (ss3 * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+}
+
+void
+ImagingReduce1xN(Imaging imOut, Imaging imIn, int box[4], int yscale) {
+ /* Optimized implementation for xscale = 1.
+ */
+ int x, y, yy;
+ int xscale = 1;
+ UINT32 multiplier = division_UINT32(yscale * xscale, 8);
+ UINT32 amend = yscale * xscale / 2;
+
+ if (imIn->image8) {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy_from = box[1] + y * yscale;
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 ss = amend;
+ for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) {
+ UINT8 *line0 = (UINT8 *)imIn->image8[yy];
+ UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1];
+ ss += line0[xx + 0] + line1[xx + 0];
+ }
+ if (yscale & 0x01) {
+ UINT8 *line = (UINT8 *)imIn->image8[yy];
+ ss += line[xx + 0];
+ }
+ imOut->image8[y][x] = (ss * multiplier) >> 24;
+ }
+ }
+ } else {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy_from = box[1] + y * yscale;
+ if (imIn->bands == 2) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ UINT32 ss0 = amend, ss3 = amend;
+ for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) {
+ UINT8 *line0 = (UINT8 *)imIn->image[yy];
+ UINT8 *line1 = (UINT8 *)imIn->image[yy + 1];
+ ss0 += line0[xx * 4 + 0] + line1[xx * 4 + 0];
+ ss3 += line0[xx * 4 + 3] + line1[xx * 4 + 3];
+ }
+ if (yscale & 0x01) {
+ UINT8 *line = (UINT8 *)imIn->image[yy];
+ ss0 += line[xx * 4 + 0];
+ ss3 += line[xx * 4 + 3];
+ }
+ v = MAKE_UINT32(
+ (ss0 * multiplier) >> 24, 0, 0, (ss3 * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (imIn->bands == 3) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ UINT32 ss0 = amend, ss1 = amend, ss2 = amend;
+ for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) {
+ UINT8 *line0 = (UINT8 *)imIn->image[yy];
+ UINT8 *line1 = (UINT8 *)imIn->image[yy + 1];
+ ss0 += line0[xx * 4 + 0] + line1[xx * 4 + 0];
+ ss1 += line0[xx * 4 + 1] + line1[xx * 4 + 1];
+ ss2 += line0[xx * 4 + 2] + line1[xx * 4 + 2];
+ }
+ if (yscale & 0x01) {
+ UINT8 *line = (UINT8 *)imIn->image[yy];
+ ss0 += line[xx * 4 + 0];
+ ss1 += line[xx * 4 + 1];
+ ss2 += line[xx * 4 + 2];
+ }
+ v = MAKE_UINT32(
+ (ss0 * multiplier) >> 24,
+ (ss1 * multiplier) >> 24,
+ (ss2 * multiplier) >> 24,
+ 0);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else { // bands == 4
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend;
+ for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) {
+ UINT8 *line0 = (UINT8 *)imIn->image[yy];
+ UINT8 *line1 = (UINT8 *)imIn->image[yy + 1];
+ ss0 += line0[xx * 4 + 0] + line1[xx * 4 + 0];
+ ss1 += line0[xx * 4 + 1] + line1[xx * 4 + 1];
+ ss2 += line0[xx * 4 + 2] + line1[xx * 4 + 2];
+ ss3 += line0[xx * 4 + 3] + line1[xx * 4 + 3];
+ }
+ if (yscale & 0x01) {
+ UINT8 *line = (UINT8 *)imIn->image[yy];
+ ss0 += line[xx * 4 + 0];
+ ss1 += line[xx * 4 + 1];
+ ss2 += line[xx * 4 + 2];
+ ss3 += line[xx * 4 + 3];
+ }
+ v = MAKE_UINT32(
+ (ss0 * multiplier) >> 24,
+ (ss1 * multiplier) >> 24,
+ (ss2 * multiplier) >> 24,
+ (ss3 * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+}
+
+void
+ImagingReduceNx1(Imaging imOut, Imaging imIn, int box[4], int xscale) {
+ /* Optimized implementation for yscale = 1.
+ */
+ int x, y, xx;
+ int yscale = 1;
+ UINT32 multiplier = division_UINT32(yscale * xscale, 8);
+ UINT32 amend = yscale * xscale / 2;
+
+ if (imIn->image8) {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line = (UINT8 *)imIn->image8[yy];
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ UINT32 ss = amend;
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss += line[xx + 0] + line[xx + 1];
+ }
+ if (xscale & 0x01) {
+ ss += line[xx + 0];
+ }
+ imOut->image8[y][x] = (ss * multiplier) >> 24;
+ }
+ }
+ } else {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line = (UINT8 *)imIn->image[yy];
+ if (imIn->bands == 2) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ UINT32 v;
+ UINT32 ss0 = amend, ss3 = amend;
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss0 += line[xx * 4 + 0] + line[xx * 4 + 4];
+ ss3 += line[xx * 4 + 3] + line[xx * 4 + 7];
+ }
+ if (xscale & 0x01) {
+ ss0 += line[xx * 4 + 0];
+ ss3 += line[xx * 4 + 3];
+ }
+ v = MAKE_UINT32(
+ (ss0 * multiplier) >> 24, 0, 0, (ss3 * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (imIn->bands == 3) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ UINT32 v;
+ UINT32 ss0 = amend, ss1 = amend, ss2 = amend;
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss0 += line[xx * 4 + 0] + line[xx * 4 + 4];
+ ss1 += line[xx * 4 + 1] + line[xx * 4 + 5];
+ ss2 += line[xx * 4 + 2] + line[xx * 4 + 6];
+ }
+ if (xscale & 0x01) {
+ ss0 += line[xx * 4 + 0];
+ ss1 += line[xx * 4 + 1];
+ ss2 += line[xx * 4 + 2];
+ }
+ v = MAKE_UINT32(
+ (ss0 * multiplier) >> 24,
+ (ss1 * multiplier) >> 24,
+ (ss2 * multiplier) >> 24,
+ 0);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else { // bands == 4
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ UINT32 v;
+ UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend;
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss0 += line[xx * 4 + 0] + line[xx * 4 + 4];
+ ss1 += line[xx * 4 + 1] + line[xx * 4 + 5];
+ ss2 += line[xx * 4 + 2] + line[xx * 4 + 6];
+ ss3 += line[xx * 4 + 3] + line[xx * 4 + 7];
+ }
+ if (xscale & 0x01) {
+ ss0 += line[xx * 4 + 0];
+ ss1 += line[xx * 4 + 1];
+ ss2 += line[xx * 4 + 2];
+ ss3 += line[xx * 4 + 3];
+ }
+ v = MAKE_UINT32(
+ (ss0 * multiplier) >> 24,
+ (ss1 * multiplier) >> 24,
+ (ss2 * multiplier) >> 24,
+ (ss3 * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+}
+
+void
+ImagingReduce1x2(Imaging imOut, Imaging imIn, int box[4]) {
+ /* Optimized implementation for xscale = 1 and yscale = 2.
+ */
+ int xscale = 1, yscale = 2;
+ int x, y;
+ UINT32 ss0, ss1, ss2, ss3;
+ UINT32 amend = yscale * xscale / 2;
+
+ if (imIn->image8) {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0];
+ UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1];
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ ss0 = line0[xx + 0] + line1[xx + 0];
+ imOut->image8[y][x] = (ss0 + amend) >> 1;
+ }
+ }
+ } else {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image[yy + 0];
+ UINT8 *line1 = (UINT8 *)imIn->image[yy + 1];
+ if (imIn->bands == 2) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line1[xx * 4 + 0];
+ ss3 = line0[xx * 4 + 3] + line1[xx * 4 + 3];
+ v = MAKE_UINT32((ss0 + amend) >> 1, 0, 0, (ss3 + amend) >> 1);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (imIn->bands == 3) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line1[xx * 4 + 0];
+ ss1 = line0[xx * 4 + 1] + line1[xx * 4 + 1];
+ ss2 = line0[xx * 4 + 2] + line1[xx * 4 + 2];
+ v = MAKE_UINT32(
+ (ss0 + amend) >> 1, (ss1 + amend) >> 1, (ss2 + amend) >> 1, 0);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else { // bands == 4
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line1[xx * 4 + 0];
+ ss1 = line0[xx * 4 + 1] + line1[xx * 4 + 1];
+ ss2 = line0[xx * 4 + 2] + line1[xx * 4 + 2];
+ ss3 = line0[xx * 4 + 3] + line1[xx * 4 + 3];
+ v = MAKE_UINT32(
+ (ss0 + amend) >> 1,
+ (ss1 + amend) >> 1,
+ (ss2 + amend) >> 1,
+ (ss3 + amend) >> 1);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+}
+
+void
+ImagingReduce2x1(Imaging imOut, Imaging imIn, int box[4]) {
+ /* Optimized implementation for xscale = 2 and yscale = 1.
+ */
+ int xscale = 2, yscale = 1;
+ int x, y;
+ UINT32 ss0, ss1, ss2, ss3;
+ UINT32 amend = yscale * xscale / 2;
+
+ if (imIn->image8) {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0];
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ ss0 = line0[xx + 0] + line0[xx + 1];
+ imOut->image8[y][x] = (ss0 + amend) >> 1;
+ }
+ }
+ } else {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image[yy + 0];
+ if (imIn->bands == 2) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4];
+ ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7];
+ v = MAKE_UINT32((ss0 + amend) >> 1, 0, 0, (ss3 + amend) >> 1);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (imIn->bands == 3) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4];
+ ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5];
+ ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6];
+ v = MAKE_UINT32(
+ (ss0 + amend) >> 1, (ss1 + amend) >> 1, (ss2 + amend) >> 1, 0);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else { // bands == 4
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4];
+ ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5];
+ ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6];
+ ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7];
+ v = MAKE_UINT32(
+ (ss0 + amend) >> 1,
+ (ss1 + amend) >> 1,
+ (ss2 + amend) >> 1,
+ (ss3 + amend) >> 1);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+}
+
+void
+ImagingReduce2x2(Imaging imOut, Imaging imIn, int box[4]) {
+ /* Optimized implementation for xscale = 2 and yscale = 2.
+ */
+ int xscale = 2, yscale = 2;
+ int x, y;
+ UINT32 ss0, ss1, ss2, ss3;
+ UINT32 amend = yscale * xscale / 2;
+
+ if (imIn->image8) {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0];
+ UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1];
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ ss0 = line0[xx + 0] + line0[xx + 1] + line1[xx + 0] + line1[xx + 1];
+ imOut->image8[y][x] = (ss0 + amend) >> 2;
+ }
+ }
+ } else {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image[yy + 0];
+ UINT8 *line1 = (UINT8 *)imIn->image[yy + 1];
+ if (imIn->bands == 2) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line1[xx * 4 + 0] +
+ line1[xx * 4 + 4];
+ ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line1[xx * 4 + 3] +
+ line1[xx * 4 + 7];
+ v = MAKE_UINT32((ss0 + amend) >> 2, 0, 0, (ss3 + amend) >> 2);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (imIn->bands == 3) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line1[xx * 4 + 0] +
+ line1[xx * 4 + 4];
+ ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line1[xx * 4 + 1] +
+ line1[xx * 4 + 5];
+ ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line1[xx * 4 + 2] +
+ line1[xx * 4 + 6];
+ v = MAKE_UINT32(
+ (ss0 + amend) >> 2, (ss1 + amend) >> 2, (ss2 + amend) >> 2, 0);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else { // bands == 4
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line1[xx * 4 + 0] +
+ line1[xx * 4 + 4];
+ ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line1[xx * 4 + 1] +
+ line1[xx * 4 + 5];
+ ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line1[xx * 4 + 2] +
+ line1[xx * 4 + 6];
+ ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line1[xx * 4 + 3] +
+ line1[xx * 4 + 7];
+ v = MAKE_UINT32(
+ (ss0 + amend) >> 2,
+ (ss1 + amend) >> 2,
+ (ss2 + amend) >> 2,
+ (ss3 + amend) >> 2);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+}
+
+void
+ImagingReduce1x3(Imaging imOut, Imaging imIn, int box[4]) {
+ /* Optimized implementation for xscale = 1 and yscale = 3.
+ */
+ int xscale = 1, yscale = 3;
+ int x, y;
+ UINT32 ss0, ss1, ss2, ss3;
+ UINT32 multiplier = division_UINT32(yscale * xscale, 8);
+ UINT32 amend = yscale * xscale / 2;
+
+ if (imIn->image8) {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0];
+ UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1];
+ UINT8 *line2 = (UINT8 *)imIn->image8[yy + 2];
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ ss0 = line0[xx + 0] + line1[xx + 0] + line2[xx + 0];
+ imOut->image8[y][x] = ((ss0 + amend) * multiplier) >> 24;
+ }
+ }
+ } else {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image[yy + 0];
+ UINT8 *line1 = (UINT8 *)imIn->image[yy + 1];
+ UINT8 *line2 = (UINT8 *)imIn->image[yy + 2];
+ if (imIn->bands == 2) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line1[xx * 4 + 0] + line2[xx * 4 + 0];
+ ss3 = line0[xx * 4 + 3] + line1[xx * 4 + 3] + line2[xx * 4 + 3];
+ v = MAKE_UINT32(
+ ((ss0 + amend) * multiplier) >> 24,
+ 0,
+ 0,
+ ((ss3 + amend) * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (imIn->bands == 3) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line1[xx * 4 + 0] + line2[xx * 4 + 0];
+ ss1 = line0[xx * 4 + 1] + line1[xx * 4 + 1] + line2[xx * 4 + 1];
+ ss2 = line0[xx * 4 + 2] + line1[xx * 4 + 2] + line2[xx * 4 + 2];
+ v = MAKE_UINT32(
+ ((ss0 + amend) * multiplier) >> 24,
+ ((ss1 + amend) * multiplier) >> 24,
+ ((ss2 + amend) * multiplier) >> 24,
+ 0);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else { // bands == 4
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line1[xx * 4 + 0] + line2[xx * 4 + 0];
+ ss1 = line0[xx * 4 + 1] + line1[xx * 4 + 1] + line2[xx * 4 + 1];
+ ss2 = line0[xx * 4 + 2] + line1[xx * 4 + 2] + line2[xx * 4 + 2];
+ ss3 = line0[xx * 4 + 3] + line1[xx * 4 + 3] + line2[xx * 4 + 3];
+ v = MAKE_UINT32(
+ ((ss0 + amend) * multiplier) >> 24,
+ ((ss1 + amend) * multiplier) >> 24,
+ ((ss2 + amend) * multiplier) >> 24,
+ ((ss3 + amend) * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+}
+
+void
+ImagingReduce3x1(Imaging imOut, Imaging imIn, int box[4]) {
+ /* Optimized implementation for xscale = 3 and yscale = 1.
+ */
+ int xscale = 3, yscale = 1;
+ int x, y;
+ UINT32 ss0, ss1, ss2, ss3;
+ UINT32 multiplier = division_UINT32(yscale * xscale, 8);
+ UINT32 amend = yscale * xscale / 2;
+
+ if (imIn->image8) {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0];
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ ss0 = line0[xx + 0] + line0[xx + 1] + line0[xx + 2];
+ imOut->image8[y][x] = ((ss0 + amend) * multiplier) >> 24;
+ }
+ }
+ } else {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image[yy + 0];
+ if (imIn->bands == 2) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8];
+ ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11];
+ v = MAKE_UINT32(
+ ((ss0 + amend) * multiplier) >> 24,
+ 0,
+ 0,
+ ((ss3 + amend) * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (imIn->bands == 3) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8];
+ ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9];
+ ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10];
+ v = MAKE_UINT32(
+ ((ss0 + amend) * multiplier) >> 24,
+ ((ss1 + amend) * multiplier) >> 24,
+ ((ss2 + amend) * multiplier) >> 24,
+ 0);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else { // bands == 4
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8];
+ ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9];
+ ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10];
+ ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11];
+ v = MAKE_UINT32(
+ ((ss0 + amend) * multiplier) >> 24,
+ ((ss1 + amend) * multiplier) >> 24,
+ ((ss2 + amend) * multiplier) >> 24,
+ ((ss3 + amend) * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+}
+
+void
+ImagingReduce3x3(Imaging imOut, Imaging imIn, int box[4]) {
+ /* Optimized implementation for xscale = 3 and yscale = 3.
+ */
+ int xscale = 3, yscale = 3;
+ int x, y;
+ UINT32 ss0, ss1, ss2, ss3;
+ UINT32 multiplier = division_UINT32(yscale * xscale, 8);
+ UINT32 amend = yscale * xscale / 2;
+
+ if (imIn->image8) {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0];
+ UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1];
+ UINT8 *line2 = (UINT8 *)imIn->image8[yy + 2];
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ ss0 = line0[xx + 0] + line0[xx + 1] + line0[xx + 2] + line1[xx + 0] +
+ line1[xx + 1] + line1[xx + 2] + line2[xx + 0] + line2[xx + 1] +
+ line2[xx + 2];
+ imOut->image8[y][x] = ((ss0 + amend) * multiplier) >> 24;
+ }
+ }
+ } else {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image[yy + 0];
+ UINT8 *line1 = (UINT8 *)imIn->image[yy + 1];
+ UINT8 *line2 = (UINT8 *)imIn->image[yy + 2];
+ if (imIn->bands == 2) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] +
+ line1[xx * 4 + 0] + line1[xx * 4 + 4] + line1[xx * 4 + 8] +
+ line2[xx * 4 + 0] + line2[xx * 4 + 4] + line2[xx * 4 + 8];
+ ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11] +
+ line1[xx * 4 + 3] + line1[xx * 4 + 7] + line1[xx * 4 + 11] +
+ line2[xx * 4 + 3] + line2[xx * 4 + 7] + line2[xx * 4 + 11];
+ v = MAKE_UINT32(
+ ((ss0 + amend) * multiplier) >> 24,
+ 0,
+ 0,
+ ((ss3 + amend) * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (imIn->bands == 3) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] +
+ line1[xx * 4 + 0] + line1[xx * 4 + 4] + line1[xx * 4 + 8] +
+ line2[xx * 4 + 0] + line2[xx * 4 + 4] + line2[xx * 4 + 8];
+ ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9] +
+ line1[xx * 4 + 1] + line1[xx * 4 + 5] + line1[xx * 4 + 9] +
+ line2[xx * 4 + 1] + line2[xx * 4 + 5] + line2[xx * 4 + 9];
+ ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10] +
+ line1[xx * 4 + 2] + line1[xx * 4 + 6] + line1[xx * 4 + 10] +
+ line2[xx * 4 + 2] + line2[xx * 4 + 6] + line2[xx * 4 + 10];
+ v = MAKE_UINT32(
+ ((ss0 + amend) * multiplier) >> 24,
+ ((ss1 + amend) * multiplier) >> 24,
+ ((ss2 + amend) * multiplier) >> 24,
+ 0);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else { // bands == 4
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] +
+ line1[xx * 4 + 0] + line1[xx * 4 + 4] + line1[xx * 4 + 8] +
+ line2[xx * 4 + 0] + line2[xx * 4 + 4] + line2[xx * 4 + 8];
+ ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9] +
+ line1[xx * 4 + 1] + line1[xx * 4 + 5] + line1[xx * 4 + 9] +
+ line2[xx * 4 + 1] + line2[xx * 4 + 5] + line2[xx * 4 + 9];
+ ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10] +
+ line1[xx * 4 + 2] + line1[xx * 4 + 6] + line1[xx * 4 + 10] +
+ line2[xx * 4 + 2] + line2[xx * 4 + 6] + line2[xx * 4 + 10];
+ ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11] +
+ line1[xx * 4 + 3] + line1[xx * 4 + 7] + line1[xx * 4 + 11] +
+ line2[xx * 4 + 3] + line2[xx * 4 + 7] + line2[xx * 4 + 11];
+ v = MAKE_UINT32(
+ ((ss0 + amend) * multiplier) >> 24,
+ ((ss1 + amend) * multiplier) >> 24,
+ ((ss2 + amend) * multiplier) >> 24,
+ ((ss3 + amend) * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+}
+
+void
+ImagingReduce4x4(Imaging imOut, Imaging imIn, int box[4]) {
+ /* Optimized implementation for xscale = 4 and yscale = 4.
+ */
+ int xscale = 4, yscale = 4;
+ int x, y;
+ UINT32 ss0, ss1, ss2, ss3;
+ UINT32 amend = yscale * xscale / 2;
+
+ if (imIn->image8) {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0];
+ UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1];
+ UINT8 *line2 = (UINT8 *)imIn->image8[yy + 2];
+ UINT8 *line3 = (UINT8 *)imIn->image8[yy + 3];
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ ss0 = line0[xx + 0] + line0[xx + 1] + line0[xx + 2] + line0[xx + 3] +
+ line1[xx + 0] + line1[xx + 1] + line1[xx + 2] + line1[xx + 3] +
+ line2[xx + 0] + line2[xx + 1] + line2[xx + 2] + line2[xx + 3] +
+ line3[xx + 0] + line3[xx + 1] + line3[xx + 2] + line3[xx + 3];
+ imOut->image8[y][x] = (ss0 + amend) >> 4;
+ }
+ }
+ } else {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image[yy + 0];
+ UINT8 *line1 = (UINT8 *)imIn->image[yy + 1];
+ UINT8 *line2 = (UINT8 *)imIn->image[yy + 2];
+ UINT8 *line3 = (UINT8 *)imIn->image[yy + 3];
+ if (imIn->bands == 2) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] +
+ line0[xx * 4 + 12] + line1[xx * 4 + 0] + line1[xx * 4 + 4] +
+ line1[xx * 4 + 8] + line1[xx * 4 + 12] + line2[xx * 4 + 0] +
+ line2[xx * 4 + 4] + line2[xx * 4 + 8] + line2[xx * 4 + 12] +
+ line3[xx * 4 + 0] + line3[xx * 4 + 4] + line3[xx * 4 + 8] +
+ line3[xx * 4 + 12];
+ ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11] +
+ line0[xx * 4 + 15] + line1[xx * 4 + 3] + line1[xx * 4 + 7] +
+ line1[xx * 4 + 11] + line1[xx * 4 + 15] + line2[xx * 4 + 3] +
+ line2[xx * 4 + 7] + line2[xx * 4 + 11] + line2[xx * 4 + 15] +
+ line3[xx * 4 + 3] + line3[xx * 4 + 7] + line3[xx * 4 + 11] +
+ line3[xx * 4 + 15];
+ v = MAKE_UINT32((ss0 + amend) >> 4, 0, 0, (ss3 + amend) >> 4);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (imIn->bands == 3) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] +
+ line0[xx * 4 + 12] + line1[xx * 4 + 0] + line1[xx * 4 + 4] +
+ line1[xx * 4 + 8] + line1[xx * 4 + 12] + line2[xx * 4 + 0] +
+ line2[xx * 4 + 4] + line2[xx * 4 + 8] + line2[xx * 4 + 12] +
+ line3[xx * 4 + 0] + line3[xx * 4 + 4] + line3[xx * 4 + 8] +
+ line3[xx * 4 + 12];
+ ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9] +
+ line0[xx * 4 + 13] + line1[xx * 4 + 1] + line1[xx * 4 + 5] +
+ line1[xx * 4 + 9] + line1[xx * 4 + 13] + line2[xx * 4 + 1] +
+ line2[xx * 4 + 5] + line2[xx * 4 + 9] + line2[xx * 4 + 13] +
+ line3[xx * 4 + 1] + line3[xx * 4 + 5] + line3[xx * 4 + 9] +
+ line3[xx * 4 + 13];
+ ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10] +
+ line0[xx * 4 + 14] + line1[xx * 4 + 2] + line1[xx * 4 + 6] +
+ line1[xx * 4 + 10] + line1[xx * 4 + 14] + line2[xx * 4 + 2] +
+ line2[xx * 4 + 6] + line2[xx * 4 + 10] + line2[xx * 4 + 14] +
+ line3[xx * 4 + 2] + line3[xx * 4 + 6] + line3[xx * 4 + 10] +
+ line3[xx * 4 + 14];
+ v = MAKE_UINT32(
+ (ss0 + amend) >> 4, (ss1 + amend) >> 4, (ss2 + amend) >> 4, 0);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else { // bands == 4
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] +
+ line0[xx * 4 + 12] + line1[xx * 4 + 0] + line1[xx * 4 + 4] +
+ line1[xx * 4 + 8] + line1[xx * 4 + 12] + line2[xx * 4 + 0] +
+ line2[xx * 4 + 4] + line2[xx * 4 + 8] + line2[xx * 4 + 12] +
+ line3[xx * 4 + 0] + line3[xx * 4 + 4] + line3[xx * 4 + 8] +
+ line3[xx * 4 + 12];
+ ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9] +
+ line0[xx * 4 + 13] + line1[xx * 4 + 1] + line1[xx * 4 + 5] +
+ line1[xx * 4 + 9] + line1[xx * 4 + 13] + line2[xx * 4 + 1] +
+ line2[xx * 4 + 5] + line2[xx * 4 + 9] + line2[xx * 4 + 13] +
+ line3[xx * 4 + 1] + line3[xx * 4 + 5] + line3[xx * 4 + 9] +
+ line3[xx * 4 + 13];
+ ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10] +
+ line0[xx * 4 + 14] + line1[xx * 4 + 2] + line1[xx * 4 + 6] +
+ line1[xx * 4 + 10] + line1[xx * 4 + 14] + line2[xx * 4 + 2] +
+ line2[xx * 4 + 6] + line2[xx * 4 + 10] + line2[xx * 4 + 14] +
+ line3[xx * 4 + 2] + line3[xx * 4 + 6] + line3[xx * 4 + 10] +
+ line3[xx * 4 + 14];
+ ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11] +
+ line0[xx * 4 + 15] + line1[xx * 4 + 3] + line1[xx * 4 + 7] +
+ line1[xx * 4 + 11] + line1[xx * 4 + 15] + line2[xx * 4 + 3] +
+ line2[xx * 4 + 7] + line2[xx * 4 + 11] + line2[xx * 4 + 15] +
+ line3[xx * 4 + 3] + line3[xx * 4 + 7] + line3[xx * 4 + 11] +
+ line3[xx * 4 + 15];
+ v = MAKE_UINT32(
+ (ss0 + amend) >> 4,
+ (ss1 + amend) >> 4,
+ (ss2 + amend) >> 4,
+ (ss3 + amend) >> 4);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+}
+
+void
+ImagingReduce5x5(Imaging imOut, Imaging imIn, int box[4]) {
+ /* Fast special case for xscale = 5 and yscale = 5.
+ */
+ int xscale = 5, yscale = 5;
+ int x, y;
+ UINT32 ss0, ss1, ss2, ss3;
+ UINT32 multiplier = division_UINT32(yscale * xscale, 8);
+ UINT32 amend = yscale * xscale / 2;
+
+ if (imIn->image8) {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image8[yy + 0];
+ UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1];
+ UINT8 *line2 = (UINT8 *)imIn->image8[yy + 2];
+ UINT8 *line3 = (UINT8 *)imIn->image8[yy + 3];
+ UINT8 *line4 = (UINT8 *)imIn->image8[yy + 4];
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ ss0 = line0[xx + 0] + line0[xx + 1] + line0[xx + 2] + line0[xx + 3] +
+ line0[xx + 4] + line1[xx + 0] + line1[xx + 1] + line1[xx + 2] +
+ line1[xx + 3] + line1[xx + 4] + line2[xx + 0] + line2[xx + 1] +
+ line2[xx + 2] + line2[xx + 3] + line2[xx + 4] + line3[xx + 0] +
+ line3[xx + 1] + line3[xx + 2] + line3[xx + 3] + line3[xx + 4] +
+ line4[xx + 0] + line4[xx + 1] + line4[xx + 2] + line4[xx + 3] +
+ line4[xx + 4];
+ imOut->image8[y][x] = ((ss0 + amend) * multiplier) >> 24;
+ }
+ }
+ } else {
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy = box[1] + y * yscale;
+ UINT8 *line0 = (UINT8 *)imIn->image[yy + 0];
+ UINT8 *line1 = (UINT8 *)imIn->image[yy + 1];
+ UINT8 *line2 = (UINT8 *)imIn->image[yy + 2];
+ UINT8 *line3 = (UINT8 *)imIn->image[yy + 3];
+ UINT8 *line4 = (UINT8 *)imIn->image[yy + 4];
+ if (imIn->bands == 2) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] +
+ line0[xx * 4 + 12] + line0[xx * 4 + 16] + line1[xx * 4 + 0] +
+ line1[xx * 4 + 4] + line1[xx * 4 + 8] + line1[xx * 4 + 12] +
+ line1[xx * 4 + 16] + line2[xx * 4 + 0] + line2[xx * 4 + 4] +
+ line2[xx * 4 + 8] + line2[xx * 4 + 12] + line2[xx * 4 + 16] +
+ line3[xx * 4 + 0] + line3[xx * 4 + 4] + line3[xx * 4 + 8] +
+ line3[xx * 4 + 12] + line3[xx * 4 + 16] + line4[xx * 4 + 0] +
+ line4[xx * 4 + 4] + line4[xx * 4 + 8] + line4[xx * 4 + 12] +
+ line4[xx * 4 + 16];
+ ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11] +
+ line0[xx * 4 + 15] + line0[xx * 4 + 19] + line1[xx * 4 + 3] +
+ line1[xx * 4 + 7] + line1[xx * 4 + 11] + line1[xx * 4 + 15] +
+ line1[xx * 4 + 19] + line2[xx * 4 + 3] + line2[xx * 4 + 7] +
+ line2[xx * 4 + 11] + line2[xx * 4 + 15] + line2[xx * 4 + 19] +
+ line3[xx * 4 + 3] + line3[xx * 4 + 7] + line3[xx * 4 + 11] +
+ line3[xx * 4 + 15] + line3[xx * 4 + 19] + line4[xx * 4 + 3] +
+ line4[xx * 4 + 7] + line4[xx * 4 + 11] + line4[xx * 4 + 15] +
+ line4[xx * 4 + 19];
+ v = MAKE_UINT32(
+ ((ss0 + amend) * multiplier) >> 24,
+ 0,
+ 0,
+ ((ss3 + amend) * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else if (imIn->bands == 3) {
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] +
+ line0[xx * 4 + 12] + line0[xx * 4 + 16] + line1[xx * 4 + 0] +
+ line1[xx * 4 + 4] + line1[xx * 4 + 8] + line1[xx * 4 + 12] +
+ line1[xx * 4 + 16] + line2[xx * 4 + 0] + line2[xx * 4 + 4] +
+ line2[xx * 4 + 8] + line2[xx * 4 + 12] + line2[xx * 4 + 16] +
+ line3[xx * 4 + 0] + line3[xx * 4 + 4] + line3[xx * 4 + 8] +
+ line3[xx * 4 + 12] + line3[xx * 4 + 16] + line4[xx * 4 + 0] +
+ line4[xx * 4 + 4] + line4[xx * 4 + 8] + line4[xx * 4 + 12] +
+ line4[xx * 4 + 16];
+ ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9] +
+ line0[xx * 4 + 13] + line0[xx * 4 + 17] + line1[xx * 4 + 1] +
+ line1[xx * 4 + 5] + line1[xx * 4 + 9] + line1[xx * 4 + 13] +
+ line1[xx * 4 + 17] + line2[xx * 4 + 1] + line2[xx * 4 + 5] +
+ line2[xx * 4 + 9] + line2[xx * 4 + 13] + line2[xx * 4 + 17] +
+ line3[xx * 4 + 1] + line3[xx * 4 + 5] + line3[xx * 4 + 9] +
+ line3[xx * 4 + 13] + line3[xx * 4 + 17] + line4[xx * 4 + 1] +
+ line4[xx * 4 + 5] + line4[xx * 4 + 9] + line4[xx * 4 + 13] +
+ line4[xx * 4 + 17];
+ ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10] +
+ line0[xx * 4 + 14] + line0[xx * 4 + 18] + line1[xx * 4 + 2] +
+ line1[xx * 4 + 6] + line1[xx * 4 + 10] + line1[xx * 4 + 14] +
+ line1[xx * 4 + 18] + line2[xx * 4 + 2] + line2[xx * 4 + 6] +
+ line2[xx * 4 + 10] + line2[xx * 4 + 14] + line2[xx * 4 + 18] +
+ line3[xx * 4 + 2] + line3[xx * 4 + 6] + line3[xx * 4 + 10] +
+ line3[xx * 4 + 14] + line3[xx * 4 + 18] + line4[xx * 4 + 2] +
+ line4[xx * 4 + 6] + line4[xx * 4 + 10] + line4[xx * 4 + 14] +
+ line4[xx * 4 + 18];
+ v = MAKE_UINT32(
+ ((ss0 + amend) * multiplier) >> 24,
+ ((ss1 + amend) * multiplier) >> 24,
+ ((ss2 + amend) * multiplier) >> 24,
+ 0);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ } else { // bands == 4
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx = box[0] + x * xscale;
+ UINT32 v;
+ ss0 = line0[xx * 4 + 0] + line0[xx * 4 + 4] + line0[xx * 4 + 8] +
+ line0[xx * 4 + 12] + line0[xx * 4 + 16] + line1[xx * 4 + 0] +
+ line1[xx * 4 + 4] + line1[xx * 4 + 8] + line1[xx * 4 + 12] +
+ line1[xx * 4 + 16] + line2[xx * 4 + 0] + line2[xx * 4 + 4] +
+ line2[xx * 4 + 8] + line2[xx * 4 + 12] + line2[xx * 4 + 16] +
+ line3[xx * 4 + 0] + line3[xx * 4 + 4] + line3[xx * 4 + 8] +
+ line3[xx * 4 + 12] + line3[xx * 4 + 16] + line4[xx * 4 + 0] +
+ line4[xx * 4 + 4] + line4[xx * 4 + 8] + line4[xx * 4 + 12] +
+ line4[xx * 4 + 16];
+ ss1 = line0[xx * 4 + 1] + line0[xx * 4 + 5] + line0[xx * 4 + 9] +
+ line0[xx * 4 + 13] + line0[xx * 4 + 17] + line1[xx * 4 + 1] +
+ line1[xx * 4 + 5] + line1[xx * 4 + 9] + line1[xx * 4 + 13] +
+ line1[xx * 4 + 17] + line2[xx * 4 + 1] + line2[xx * 4 + 5] +
+ line2[xx * 4 + 9] + line2[xx * 4 + 13] + line2[xx * 4 + 17] +
+ line3[xx * 4 + 1] + line3[xx * 4 + 5] + line3[xx * 4 + 9] +
+ line3[xx * 4 + 13] + line3[xx * 4 + 17] + line4[xx * 4 + 1] +
+ line4[xx * 4 + 5] + line4[xx * 4 + 9] + line4[xx * 4 + 13] +
+ line4[xx * 4 + 17];
+ ss2 = line0[xx * 4 + 2] + line0[xx * 4 + 6] + line0[xx * 4 + 10] +
+ line0[xx * 4 + 14] + line0[xx * 4 + 18] + line1[xx * 4 + 2] +
+ line1[xx * 4 + 6] + line1[xx * 4 + 10] + line1[xx * 4 + 14] +
+ line1[xx * 4 + 18] + line2[xx * 4 + 2] + line2[xx * 4 + 6] +
+ line2[xx * 4 + 10] + line2[xx * 4 + 14] + line2[xx * 4 + 18] +
+ line3[xx * 4 + 2] + line3[xx * 4 + 6] + line3[xx * 4 + 10] +
+ line3[xx * 4 + 14] + line3[xx * 4 + 18] + line4[xx * 4 + 2] +
+ line4[xx * 4 + 6] + line4[xx * 4 + 10] + line4[xx * 4 + 14] +
+ line4[xx * 4 + 18];
+ ss3 = line0[xx * 4 + 3] + line0[xx * 4 + 7] + line0[xx * 4 + 11] +
+ line0[xx * 4 + 15] + line0[xx * 4 + 19] + line1[xx * 4 + 3] +
+ line1[xx * 4 + 7] + line1[xx * 4 + 11] + line1[xx * 4 + 15] +
+ line1[xx * 4 + 19] + line2[xx * 4 + 3] + line2[xx * 4 + 7] +
+ line2[xx * 4 + 11] + line2[xx * 4 + 15] + line2[xx * 4 + 19] +
+ line3[xx * 4 + 3] + line3[xx * 4 + 7] + line3[xx * 4 + 11] +
+ line3[xx * 4 + 15] + line3[xx * 4 + 19] + line4[xx * 4 + 3] +
+ line4[xx * 4 + 7] + line4[xx * 4 + 11] + line4[xx * 4 + 15] +
+ line4[xx * 4 + 19];
+ v = MAKE_UINT32(
+ ((ss0 + amend) * multiplier) >> 24,
+ ((ss1 + amend) * multiplier) >> 24,
+ ((ss2 + amend) * multiplier) >> 24,
+ ((ss3 + amend) * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+}
+
+void
+ImagingReduceCorners(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) {
+ /* Fill the last row and the last column for any xscale and yscale.
+ */
+ int x, y, xx, yy;
+
+ if (imIn->image8) {
+ if (box[2] % xscale) {
+ int scale = (box[2] % xscale) * yscale;
+ UINT32 multiplier = division_UINT32(scale, 8);
+ UINT32 amend = scale / 2;
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy_from = box[1] + y * yscale;
+ UINT32 ss = amend;
+ x = box[2] / xscale;
+
+ for (yy = yy_from; yy < yy_from + yscale; yy++) {
+ UINT8 *line = (UINT8 *)imIn->image8[yy];
+ for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) {
+ ss += line[xx + 0];
+ }
+ }
+ imOut->image8[y][x] = (ss * multiplier) >> 24;
+ }
+ }
+ if (box[3] % yscale) {
+ int scale = xscale * (box[3] % yscale);
+ UINT32 multiplier = division_UINT32(scale, 8);
+ UINT32 amend = scale / 2;
+ y = box[3] / yscale;
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ UINT32 ss = amend;
+ for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) {
+ UINT8 *line = (UINT8 *)imIn->image8[yy];
+ for (xx = xx_from; xx < xx_from + xscale; xx++) {
+ ss += line[xx + 0];
+ }
+ }
+ imOut->image8[y][x] = (ss * multiplier) >> 24;
+ }
+ }
+ if (box[2] % xscale && box[3] % yscale) {
+ int scale = (box[2] % xscale) * (box[3] % yscale);
+ UINT32 multiplier = division_UINT32(scale, 8);
+ UINT32 amend = scale / 2;
+ UINT32 ss = amend;
+ x = box[2] / xscale;
+ y = box[3] / yscale;
+ for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) {
+ UINT8 *line = (UINT8 *)imIn->image8[yy];
+ for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) {
+ ss += line[xx + 0];
+ }
+ }
+ imOut->image8[y][x] = (ss * multiplier) >> 24;
+ }
+ } else {
+ if (box[2] % xscale) {
+ int scale = (box[2] % xscale) * yscale;
+ UINT32 multiplier = division_UINT32(scale, 8);
+ UINT32 amend = scale / 2;
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy_from = box[1] + y * yscale;
+ UINT32 v;
+ UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend;
+ x = box[2] / xscale;
+
+ for (yy = yy_from; yy < yy_from + yscale; yy++) {
+ UINT8 *line = (UINT8 *)imIn->image[yy];
+ for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) {
+ ss0 += line[xx * 4 + 0];
+ ss1 += line[xx * 4 + 1];
+ ss2 += line[xx * 4 + 2];
+ ss3 += line[xx * 4 + 3];
+ }
+ }
+ v = MAKE_UINT32(
+ (ss0 * multiplier) >> 24,
+ (ss1 * multiplier) >> 24,
+ (ss2 * multiplier) >> 24,
+ (ss3 * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ if (box[3] % yscale) {
+ int scale = xscale * (box[3] % yscale);
+ UINT32 multiplier = division_UINT32(scale, 8);
+ UINT32 amend = scale / 2;
+ y = box[3] / yscale;
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ UINT32 v;
+ UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend;
+ for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) {
+ UINT8 *line = (UINT8 *)imIn->image[yy];
+ for (xx = xx_from; xx < xx_from + xscale; xx++) {
+ ss0 += line[xx * 4 + 0];
+ ss1 += line[xx * 4 + 1];
+ ss2 += line[xx * 4 + 2];
+ ss3 += line[xx * 4 + 3];
+ }
+ }
+ v = MAKE_UINT32(
+ (ss0 * multiplier) >> 24,
+ (ss1 * multiplier) >> 24,
+ (ss2 * multiplier) >> 24,
+ (ss3 * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+ if (box[2] % xscale && box[3] % yscale) {
+ int scale = (box[2] % xscale) * (box[3] % yscale);
+ UINT32 multiplier = division_UINT32(scale, 8);
+ UINT32 amend = scale / 2;
+ UINT32 v;
+ UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend;
+ x = box[2] / xscale;
+ y = box[3] / yscale;
+ for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) {
+ UINT8 *line = (UINT8 *)imIn->image[yy];
+ for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) {
+ ss0 += line[xx * 4 + 0];
+ ss1 += line[xx * 4 + 1];
+ ss2 += line[xx * 4 + 2];
+ ss3 += line[xx * 4 + 3];
+ }
+ }
+ v = MAKE_UINT32(
+ (ss0 * multiplier) >> 24,
+ (ss1 * multiplier) >> 24,
+ (ss2 * multiplier) >> 24,
+ (ss3 * multiplier) >> 24);
+ memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v));
+ }
+ }
+}
+
+void
+ImagingReduceNxN_32bpc(
+ Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) {
+ /* The most general implementation for any xscale and yscale
+ */
+ int x, y, xx, yy;
+ double multiplier = 1.0 / (yscale * xscale);
+
+ switch (imIn->type) {
+ case IMAGING_TYPE_INT32:
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy_from = box[1] + y * yscale;
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ double ss = 0;
+ for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) {
+ INT32 *line0 = (INT32 *)imIn->image32[yy];
+ INT32 *line1 = (INT32 *)imIn->image32[yy + 1];
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss += line0[xx + 0] + line0[xx + 1] + line1[xx + 0] +
+ line1[xx + 1];
+ }
+ if (xscale & 0x01) {
+ ss += line0[xx + 0] + line1[xx + 0];
+ }
+ }
+ if (yscale & 0x01) {
+ INT32 *line = (INT32 *)imIn->image32[yy];
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss += line[xx + 0] + line[xx + 1];
+ }
+ if (xscale & 0x01) {
+ ss += line[xx + 0];
+ }
+ }
+ IMAGING_PIXEL_I(imOut, x, y) = ROUND_UP(ss * multiplier);
+ }
+ }
+ break;
+
+ case IMAGING_TYPE_FLOAT32:
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy_from = box[1] + y * yscale;
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ double ss = 0;
+ for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) {
+ FLOAT32 *line0 = (FLOAT32 *)imIn->image32[yy];
+ FLOAT32 *line1 = (FLOAT32 *)imIn->image32[yy + 1];
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss += line0[xx + 0] + line0[xx + 1] + line1[xx + 0] +
+ line1[xx + 1];
+ }
+ if (xscale & 0x01) {
+ ss += line0[xx + 0] + line1[xx + 0];
+ }
+ }
+ if (yscale & 0x01) {
+ FLOAT32 *line = (FLOAT32 *)imIn->image32[yy];
+ for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) {
+ ss += line[xx + 0] + line[xx + 1];
+ }
+ if (xscale & 0x01) {
+ ss += line[xx + 0];
+ }
+ }
+ IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier;
+ }
+ }
+ break;
+ }
+}
+
+void
+ImagingReduceCorners_32bpc(
+ Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) {
+ /* Fill the last row and the last column for any xscale and yscale.
+ */
+ int x, y, xx, yy;
+
+ switch (imIn->type) {
+ case IMAGING_TYPE_INT32:
+ if (box[2] % xscale) {
+ double multiplier = 1.0 / ((box[2] % xscale) * yscale);
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy_from = box[1] + y * yscale;
+ double ss = 0;
+ x = box[2] / xscale;
+ for (yy = yy_from; yy < yy_from + yscale; yy++) {
+ INT32 *line = (INT32 *)imIn->image32[yy];
+ for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) {
+ ss += line[xx + 0];
+ }
+ }
+ IMAGING_PIXEL_I(imOut, x, y) = ROUND_UP(ss * multiplier);
+ }
+ }
+ if (box[3] % yscale) {
+ double multiplier = 1.0 / (xscale * (box[3] % yscale));
+ y = box[3] / yscale;
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ double ss = 0;
+ for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) {
+ INT32 *line = (INT32 *)imIn->image32[yy];
+ for (xx = xx_from; xx < xx_from + xscale; xx++) {
+ ss += line[xx + 0];
+ }
+ }
+ IMAGING_PIXEL_I(imOut, x, y) = ROUND_UP(ss * multiplier);
+ }
+ }
+ if (box[2] % xscale && box[3] % yscale) {
+ double multiplier = 1.0 / ((box[2] % xscale) * (box[3] % yscale));
+ double ss = 0;
+ x = box[2] / xscale;
+ y = box[3] / yscale;
+ for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) {
+ INT32 *line = (INT32 *)imIn->image32[yy];
+ for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) {
+ ss += line[xx + 0];
+ }
+ }
+ IMAGING_PIXEL_I(imOut, x, y) = ROUND_UP(ss * multiplier);
+ }
+ break;
+
+ case IMAGING_TYPE_FLOAT32:
+ if (box[2] % xscale) {
+ double multiplier = 1.0 / ((box[2] % xscale) * yscale);
+ for (y = 0; y < box[3] / yscale; y++) {
+ int yy_from = box[1] + y * yscale;
+ double ss = 0;
+ x = box[2] / xscale;
+ for (yy = yy_from; yy < yy_from + yscale; yy++) {
+ FLOAT32 *line = (FLOAT32 *)imIn->image32[yy];
+ for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) {
+ ss += line[xx + 0];
+ }
+ }
+ IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier;
+ }
+ }
+ if (box[3] % yscale) {
+ double multiplier = 1.0 / (xscale * (box[3] % yscale));
+ y = box[3] / yscale;
+ for (x = 0; x < box[2] / xscale; x++) {
+ int xx_from = box[0] + x * xscale;
+ double ss = 0;
+ for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) {
+ FLOAT32 *line = (FLOAT32 *)imIn->image32[yy];
+ for (xx = xx_from; xx < xx_from + xscale; xx++) {
+ ss += line[xx + 0];
+ }
+ }
+ IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier;
+ }
+ }
+ if (box[2] % xscale && box[3] % yscale) {
+ double multiplier = 1.0 / ((box[2] % xscale) * (box[3] % yscale));
+ double ss = 0;
+ x = box[2] / xscale;
+ y = box[3] / yscale;
+ for (yy = box[1] + y * yscale; yy < box[1] + box[3]; yy++) {
+ FLOAT32 *line = (FLOAT32 *)imIn->image32[yy];
+ for (xx = box[0] + x * xscale; xx < box[0] + box[2]; xx++) {
+ ss += line[xx + 0];
+ }
+ }
+ IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier;
+ }
+ break;
+ }
+}
+
+Imaging
+ImagingReduce(Imaging imIn, int xscale, int yscale, int box[4]) {
+ ImagingSectionCookie cookie;
+ Imaging imOut = NULL;
+
+ if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ if (imIn->type == IMAGING_TYPE_SPECIAL) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ imOut = ImagingNewDirty(
+ imIn->mode, (box[2] + xscale - 1) / xscale, (box[3] + yscale - 1) / yscale);
+ if (!imOut) {
+ return NULL;
+ }
+
+ ImagingSectionEnter(&cookie);
+
+ switch (imIn->type) {
+ case IMAGING_TYPE_UINT8:
+ if (xscale == 1) {
+ if (yscale == 2) {
+ ImagingReduce1x2(imOut, imIn, box);
+ } else if (yscale == 3) {
+ ImagingReduce1x3(imOut, imIn, box);
+ } else {
+ ImagingReduce1xN(imOut, imIn, box, yscale);
+ }
+ } else if (yscale == 1) {
+ if (xscale == 2) {
+ ImagingReduce2x1(imOut, imIn, box);
+ } else if (xscale == 3) {
+ ImagingReduce3x1(imOut, imIn, box);
+ } else {
+ ImagingReduceNx1(imOut, imIn, box, xscale);
+ }
+ } else if (xscale == yscale && xscale <= 5) {
+ if (xscale == 2) {
+ ImagingReduce2x2(imOut, imIn, box);
+ } else if (xscale == 3) {
+ ImagingReduce3x3(imOut, imIn, box);
+ } else if (xscale == 4) {
+ ImagingReduce4x4(imOut, imIn, box);
+ } else {
+ ImagingReduce5x5(imOut, imIn, box);
+ }
+ } else {
+ ImagingReduceNxN(imOut, imIn, box, xscale, yscale);
+ }
+
+ ImagingReduceCorners(imOut, imIn, box, xscale, yscale);
+ break;
+
+ case IMAGING_TYPE_INT32:
+ case IMAGING_TYPE_FLOAT32:
+ ImagingReduceNxN_32bpc(imOut, imIn, box, xscale, yscale);
+
+ ImagingReduceCorners_32bpc(imOut, imIn, box, xscale, yscale);
+ break;
+ }
+
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Resample.c b/contrib/python/Pillow/py3/libImaging/Resample.c
new file mode 100644
index 00000000000..cf79d8a4e4d
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Resample.c
@@ -0,0 +1,708 @@
+#include "Imaging.h"
+
+#include <math.h>
+
+#define ROUND_UP(f) ((int)((f) >= 0.0 ? (f) + 0.5F : (f)-0.5F))
+
+struct filter {
+ double (*filter)(double x);
+ double support;
+};
+
+static inline double
+box_filter(double x) {
+ if (x > -0.5 && x <= 0.5) {
+ return 1.0;
+ }
+ return 0.0;
+}
+
+static inline double
+bilinear_filter(double x) {
+ if (x < 0.0) {
+ x = -x;
+ }
+ if (x < 1.0) {
+ return 1.0 - x;
+ }
+ return 0.0;
+}
+
+static inline double
+hamming_filter(double x) {
+ if (x < 0.0) {
+ x = -x;
+ }
+ if (x == 0.0) {
+ return 1.0;
+ }
+ if (x >= 1.0) {
+ return 0.0;
+ }
+ x = x * M_PI;
+ return sin(x) / x * (0.54f + 0.46f * cos(x));
+}
+
+static inline double
+bicubic_filter(double x) {
+ /* https://en.wikipedia.org/wiki/Bicubic_interpolation#Bicubic_convolution_algorithm
+ */
+#define a -0.5
+ 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 (((x - 5) * x + 8) * x - 4) * a;
+ }
+ return 0.0;
+#undef a
+}
+
+static inline double
+sinc_filter(double x) {
+ if (x == 0.0) {
+ return 1.0;
+ }
+ x = x * M_PI;
+ return sin(x) / x;
+}
+
+static inline double
+lanczos_filter(double x) {
+ /* truncated sinc */
+ if (-3.0 <= x && x < 3.0) {
+ return sinc_filter(x) * sinc_filter(x / 3);
+ }
+ return 0.0;
+}
+
+static struct filter BOX = {box_filter, 0.5};
+static struct filter BILINEAR = {bilinear_filter, 1.0};
+static struct filter HAMMING = {hamming_filter, 1.0};
+static struct filter BICUBIC = {bicubic_filter, 2.0};
+static struct filter LANCZOS = {lanczos_filter, 3.0};
+
+/* 8 bits for result. Filter can have negative areas.
+ In one cases the sum of the coefficients will be negative,
+ in the other it will be more than 1.0. That is why we need
+ two extra bits for overflow and int type. */
+#define PRECISION_BITS (32 - 8 - 2)
+
+/* Handles values form -640 to 639. */
+UINT8 _clip8_lookups[1280] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+ 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
+ 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158,
+ 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192,
+ 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226,
+ 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243,
+ 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255,
+};
+
+UINT8 *clip8_lookups = &_clip8_lookups[640];
+
+static inline UINT8
+clip8(int in) {
+ return clip8_lookups[in >> PRECISION_BITS];
+}
+
+int
+precompute_coeffs(
+ int inSize,
+ float in0,
+ float in1,
+ int outSize,
+ struct filter *filterp,
+ int **boundsp,
+ double **kkp) {
+ double support, scale, filterscale;
+ double center, ww, ss;
+ int xx, x, ksize, xmin, xmax;
+ int *bounds;
+ double *kk, *k;
+
+ /* prepare for horizontal stretch */
+ filterscale = scale = (double)(in1 - in0) / outSize;
+ if (filterscale < 1.0) {
+ filterscale = 1.0;
+ }
+
+ /* determine support size (length of resampling filter) */
+ support = filterp->support * filterscale;
+
+ /* maximum number of coeffs */
+ ksize = (int)ceil(support) * 2 + 1;
+
+ // check for overflow
+ if (outSize > INT_MAX / (ksize * (int)sizeof(double))) {
+ ImagingError_MemoryError();
+ return 0;
+ }
+
+ /* coefficient buffer */
+ /* malloc check ok, overflow checked above */
+ kk = malloc(outSize * ksize * sizeof(double));
+ if (!kk) {
+ ImagingError_MemoryError();
+ return 0;
+ }
+
+ /* malloc check ok, ksize*sizeof(double) > 2*sizeof(int) */
+ bounds = malloc(outSize * 2 * sizeof(int));
+ if (!bounds) {
+ free(kk);
+ ImagingError_MemoryError();
+ return 0;
+ }
+
+ for (xx = 0; xx < outSize; xx++) {
+ center = in0 + (xx + 0.5) * scale;
+ ww = 0.0;
+ ss = 1.0 / filterscale;
+ // Round the value
+ xmin = (int)(center - support + 0.5);
+ if (xmin < 0) {
+ xmin = 0;
+ }
+ // Round the value
+ xmax = (int)(center + support + 0.5);
+ if (xmax > inSize) {
+ xmax = inSize;
+ }
+ xmax -= xmin;
+ k = &kk[xx * ksize];
+ for (x = 0; x < xmax; x++) {
+ double w = filterp->filter((x + xmin - center + 0.5) * ss);
+ k[x] = w;
+ ww += w;
+ }
+ for (x = 0; x < xmax; x++) {
+ if (ww != 0.0) {
+ k[x] /= ww;
+ }
+ }
+ // Remaining values should stay empty if they are used despite of xmax.
+ for (; x < ksize; x++) {
+ k[x] = 0;
+ }
+ bounds[xx * 2 + 0] = xmin;
+ bounds[xx * 2 + 1] = xmax;
+ }
+ *boundsp = bounds;
+ *kkp = kk;
+ return ksize;
+}
+
+void
+normalize_coeffs_8bpc(int outSize, int ksize, double *prekk) {
+ int x;
+ INT32 *kk;
+
+ // use the same buffer for normalized coefficients
+ kk = (INT32 *)prekk;
+
+ for (x = 0; x < outSize * ksize; x++) {
+ if (prekk[x] < 0) {
+ kk[x] = (int)(-0.5 + prekk[x] * (1 << PRECISION_BITS));
+ } else {
+ kk[x] = (int)(0.5 + prekk[x] * (1 << PRECISION_BITS));
+ }
+ }
+}
+
+void
+ImagingResampleHorizontal_8bpc(
+ Imaging imOut, Imaging imIn, int offset, int ksize, int *bounds, double *prekk) {
+ ImagingSectionCookie cookie;
+ int ss0, ss1, ss2, ss3;
+ int xx, yy, x, xmin, xmax;
+ INT32 *k, *kk;
+
+ // use the same buffer for normalized coefficients
+ kk = (INT32 *)prekk;
+ normalize_coeffs_8bpc(imOut->xsize, ksize, prekk);
+
+ ImagingSectionEnter(&cookie);
+ if (imIn->image8) {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ xmin = bounds[xx * 2 + 0];
+ xmax = bounds[xx * 2 + 1];
+ k = &kk[xx * ksize];
+ ss0 = 1 << (PRECISION_BITS - 1);
+ for (x = 0; x < xmax; x++) {
+ ss0 += ((UINT8)imIn->image8[yy + offset][x + xmin]) * k[x];
+ }
+ imOut->image8[yy][xx] = clip8(ss0);
+ }
+ }
+ } else if (imIn->type == IMAGING_TYPE_UINT8) {
+ if (imIn->bands == 2) {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ UINT32 v;
+ xmin = bounds[xx * 2 + 0];
+ xmax = bounds[xx * 2 + 1];
+ k = &kk[xx * ksize];
+ ss0 = ss3 = 1 << (PRECISION_BITS - 1);
+ for (x = 0; x < xmax; x++) {
+ ss0 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 0]) *
+ k[x];
+ ss3 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 3]) *
+ k[x];
+ }
+ v = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3));
+ memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v));
+ }
+ }
+ } else if (imIn->bands == 3) {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ UINT32 v;
+ xmin = bounds[xx * 2 + 0];
+ xmax = bounds[xx * 2 + 1];
+ k = &kk[xx * ksize];
+ ss0 = ss1 = ss2 = 1 << (PRECISION_BITS - 1);
+ for (x = 0; x < xmax; x++) {
+ ss0 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 0]) *
+ k[x];
+ ss1 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 1]) *
+ k[x];
+ ss2 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 2]) *
+ k[x];
+ }
+ v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), 0);
+ memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v));
+ }
+ }
+ } else {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ UINT32 v;
+ xmin = bounds[xx * 2 + 0];
+ xmax = bounds[xx * 2 + 1];
+ k = &kk[xx * ksize];
+ ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS - 1);
+ for (x = 0; x < xmax; x++) {
+ ss0 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 0]) *
+ k[x];
+ ss1 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 1]) *
+ k[x];
+ ss2 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 2]) *
+ k[x];
+ ss3 += ((UINT8)imIn->image[yy + offset][(x + xmin) * 4 + 3]) *
+ k[x];
+ }
+ v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
+ memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+}
+
+void
+ImagingResampleVertical_8bpc(
+ Imaging imOut, Imaging imIn, int offset, int ksize, int *bounds, double *prekk) {
+ ImagingSectionCookie cookie;
+ int ss0, ss1, ss2, ss3;
+ int xx, yy, y, ymin, ymax;
+ INT32 *k, *kk;
+
+ // use the same buffer for normalized coefficients
+ kk = (INT32 *)prekk;
+ normalize_coeffs_8bpc(imOut->ysize, ksize, prekk);
+
+ ImagingSectionEnter(&cookie);
+ if (imIn->image8) {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ k = &kk[yy * ksize];
+ ymin = bounds[yy * 2 + 0];
+ ymax = bounds[yy * 2 + 1];
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ ss0 = 1 << (PRECISION_BITS - 1);
+ for (y = 0; y < ymax; y++) {
+ ss0 += ((UINT8)imIn->image8[y + ymin][xx]) * k[y];
+ }
+ imOut->image8[yy][xx] = clip8(ss0);
+ }
+ }
+ } else if (imIn->type == IMAGING_TYPE_UINT8) {
+ if (imIn->bands == 2) {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ k = &kk[yy * ksize];
+ ymin = bounds[yy * 2 + 0];
+ ymax = bounds[yy * 2 + 1];
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ UINT32 v;
+ ss0 = ss3 = 1 << (PRECISION_BITS - 1);
+ for (y = 0; y < ymax; y++) {
+ ss0 += ((UINT8)imIn->image[y + ymin][xx * 4 + 0]) * k[y];
+ ss3 += ((UINT8)imIn->image[y + ymin][xx * 4 + 3]) * k[y];
+ }
+ v = MAKE_UINT32(clip8(ss0), 0, 0, clip8(ss3));
+ memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v));
+ }
+ }
+ } else if (imIn->bands == 3) {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ k = &kk[yy * ksize];
+ ymin = bounds[yy * 2 + 0];
+ ymax = bounds[yy * 2 + 1];
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ UINT32 v;
+ ss0 = ss1 = ss2 = 1 << (PRECISION_BITS - 1);
+ for (y = 0; y < ymax; y++) {
+ ss0 += ((UINT8)imIn->image[y + ymin][xx * 4 + 0]) * k[y];
+ ss1 += ((UINT8)imIn->image[y + ymin][xx * 4 + 1]) * k[y];
+ ss2 += ((UINT8)imIn->image[y + ymin][xx * 4 + 2]) * k[y];
+ }
+ v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), 0);
+ memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v));
+ }
+ }
+ } else {
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ k = &kk[yy * ksize];
+ ymin = bounds[yy * 2 + 0];
+ ymax = bounds[yy * 2 + 1];
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ UINT32 v;
+ ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS - 1);
+ for (y = 0; y < ymax; y++) {
+ ss0 += ((UINT8)imIn->image[y + ymin][xx * 4 + 0]) * k[y];
+ ss1 += ((UINT8)imIn->image[y + ymin][xx * 4 + 1]) * k[y];
+ ss2 += ((UINT8)imIn->image[y + ymin][xx * 4 + 2]) * k[y];
+ ss3 += ((UINT8)imIn->image[y + ymin][xx * 4 + 3]) * k[y];
+ }
+ v = MAKE_UINT32(clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
+ memcpy(imOut->image[yy] + xx * sizeof(v), &v, sizeof(v));
+ }
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+}
+
+void
+ImagingResampleHorizontal_32bpc(
+ Imaging imOut, Imaging imIn, int offset, int ksize, int *bounds, double *kk) {
+ ImagingSectionCookie cookie;
+ double ss;
+ int xx, yy, x, xmin, xmax;
+ double *k;
+
+ ImagingSectionEnter(&cookie);
+ switch (imIn->type) {
+ case IMAGING_TYPE_INT32:
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ xmin = bounds[xx * 2 + 0];
+ xmax = bounds[xx * 2 + 1];
+ k = &kk[xx * ksize];
+ ss = 0.0;
+ for (x = 0; x < xmax; x++) {
+ ss += IMAGING_PIXEL_I(imIn, x + xmin, yy + offset) * k[x];
+ }
+ IMAGING_PIXEL_I(imOut, xx, yy) = ROUND_UP(ss);
+ }
+ }
+ break;
+
+ case IMAGING_TYPE_FLOAT32:
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ xmin = bounds[xx * 2 + 0];
+ xmax = bounds[xx * 2 + 1];
+ k = &kk[xx * ksize];
+ ss = 0.0;
+ for (x = 0; x < xmax; x++) {
+ ss += IMAGING_PIXEL_F(imIn, x + xmin, yy + offset) * k[x];
+ }
+ IMAGING_PIXEL_F(imOut, xx, yy) = ss;
+ }
+ }
+ break;
+ }
+ ImagingSectionLeave(&cookie);
+}
+
+void
+ImagingResampleVertical_32bpc(
+ Imaging imOut, Imaging imIn, int offset, int ksize, int *bounds, double *kk) {
+ ImagingSectionCookie cookie;
+ double ss;
+ int xx, yy, y, ymin, ymax;
+ double *k;
+
+ ImagingSectionEnter(&cookie);
+ switch (imIn->type) {
+ case IMAGING_TYPE_INT32:
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ ymin = bounds[yy * 2 + 0];
+ ymax = bounds[yy * 2 + 1];
+ k = &kk[yy * ksize];
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ ss = 0.0;
+ for (y = 0; y < ymax; y++) {
+ ss += IMAGING_PIXEL_I(imIn, xx, y + ymin) * k[y];
+ }
+ IMAGING_PIXEL_I(imOut, xx, yy) = ROUND_UP(ss);
+ }
+ }
+ break;
+
+ case IMAGING_TYPE_FLOAT32:
+ for (yy = 0; yy < imOut->ysize; yy++) {
+ ymin = bounds[yy * 2 + 0];
+ ymax = bounds[yy * 2 + 1];
+ k = &kk[yy * ksize];
+ for (xx = 0; xx < imOut->xsize; xx++) {
+ ss = 0.0;
+ for (y = 0; y < ymax; y++) {
+ ss += IMAGING_PIXEL_F(imIn, xx, y + ymin) * k[y];
+ }
+ IMAGING_PIXEL_F(imOut, xx, yy) = ss;
+ }
+ }
+ break;
+ }
+ ImagingSectionLeave(&cookie);
+}
+
+typedef void (*ResampleFunction)(
+ Imaging imOut, Imaging imIn, int offset, int ksize, int *bounds, double *kk);
+
+Imaging
+ImagingResampleInner(
+ Imaging imIn,
+ int xsize,
+ int ysize,
+ struct filter *filterp,
+ float box[4],
+ ResampleFunction ResampleHorizontal,
+ ResampleFunction ResampleVertical);
+
+Imaging
+ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]) {
+ struct filter *filterp;
+ ResampleFunction ResampleHorizontal;
+ ResampleFunction ResampleVertical;
+
+ if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0) {
+ return (Imaging)ImagingError_ModeError();
+ }
+
+ if (imIn->type == IMAGING_TYPE_SPECIAL) {
+ return (Imaging)ImagingError_ModeError();
+ } else if (imIn->image8) {
+ ResampleHorizontal = ImagingResampleHorizontal_8bpc;
+ ResampleVertical = ImagingResampleVertical_8bpc;
+ } else {
+ switch (imIn->type) {
+ case IMAGING_TYPE_UINT8:
+ ResampleHorizontal = ImagingResampleHorizontal_8bpc;
+ ResampleVertical = ImagingResampleVertical_8bpc;
+ break;
+ case IMAGING_TYPE_INT32:
+ case IMAGING_TYPE_FLOAT32:
+ ResampleHorizontal = ImagingResampleHorizontal_32bpc;
+ ResampleVertical = ImagingResampleVertical_32bpc;
+ break;
+ default:
+ return (Imaging)ImagingError_ModeError();
+ }
+ }
+
+ /* check filter */
+ switch (filter) {
+ case IMAGING_TRANSFORM_BOX:
+ filterp = &BOX;
+ break;
+ case IMAGING_TRANSFORM_BILINEAR:
+ filterp = &BILINEAR;
+ break;
+ case IMAGING_TRANSFORM_HAMMING:
+ filterp = &HAMMING;
+ break;
+ case IMAGING_TRANSFORM_BICUBIC:
+ filterp = &BICUBIC;
+ break;
+ case IMAGING_TRANSFORM_LANCZOS:
+ filterp = &LANCZOS;
+ break;
+ default:
+ return (Imaging)ImagingError_ValueError("unsupported resampling filter");
+ }
+
+ return ImagingResampleInner(
+ imIn, xsize, ysize, filterp, box, ResampleHorizontal, ResampleVertical);
+}
+
+Imaging
+ImagingResampleInner(
+ Imaging imIn,
+ int xsize,
+ int ysize,
+ struct filter *filterp,
+ float box[4],
+ ResampleFunction ResampleHorizontal,
+ ResampleFunction ResampleVertical) {
+ Imaging imTemp = NULL;
+ Imaging imOut = NULL;
+
+ int i, need_horizontal, need_vertical;
+ int ybox_first, ybox_last;
+ int ksize_horiz, ksize_vert;
+ int *bounds_horiz, *bounds_vert;
+ double *kk_horiz, *kk_vert;
+
+ need_horizontal = xsize != imIn->xsize || box[0] || box[2] != xsize;
+ need_vertical = ysize != imIn->ysize || box[1] || box[3] != ysize;
+
+ ksize_horiz = precompute_coeffs(
+ imIn->xsize, box[0], box[2], xsize, filterp, &bounds_horiz, &kk_horiz);
+ if (!ksize_horiz) {
+ return NULL;
+ }
+
+ ksize_vert = precompute_coeffs(
+ imIn->ysize, box[1], box[3], ysize, filterp, &bounds_vert, &kk_vert);
+ if (!ksize_vert) {
+ free(bounds_horiz);
+ free(kk_horiz);
+ return NULL;
+ }
+
+ // First used row in the source image
+ ybox_first = bounds_vert[0];
+ // Last used row in the source image
+ ybox_last = bounds_vert[ysize * 2 - 2] + bounds_vert[ysize * 2 - 1];
+
+ /* two-pass resize, horizontal pass */
+ if (need_horizontal) {
+ // Shift bounds for vertical pass
+ for (i = 0; i < ysize; i++) {
+ bounds_vert[i * 2] -= ybox_first;
+ }
+
+ imTemp = ImagingNewDirty(imIn->mode, xsize, ybox_last - ybox_first);
+ if (imTemp) {
+ ResampleHorizontal(
+ imTemp, imIn, ybox_first, ksize_horiz, bounds_horiz, kk_horiz);
+ }
+ free(bounds_horiz);
+ free(kk_horiz);
+ if (!imTemp) {
+ free(bounds_vert);
+ free(kk_vert);
+ return NULL;
+ }
+ imOut = imIn = imTemp;
+ } else {
+ // Free in any case
+ free(bounds_horiz);
+ free(kk_horiz);
+ }
+
+ /* vertical pass */
+ if (need_vertical) {
+ imOut = ImagingNewDirty(imIn->mode, imIn->xsize, ysize);
+ if (imOut) {
+ /* imIn can be the original image or horizontally resampled one */
+ ResampleVertical(imOut, imIn, 0, ksize_vert, bounds_vert, kk_vert);
+ }
+ /* it's safe to call ImagingDelete with empty value
+ if previous step was not performed. */
+ ImagingDelete(imTemp);
+ free(bounds_vert);
+ free(kk_vert);
+ if (!imOut) {
+ return NULL;
+ }
+ } else {
+ // Free in any case
+ free(bounds_vert);
+ free(kk_vert);
+ }
+
+ /* none of the previous steps are performed, copying */
+ if (!imOut) {
+ imOut = ImagingCopy(imIn);
+ }
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Sgi.h b/contrib/python/Pillow/py3/libImaging/Sgi.h
new file mode 100644
index 00000000000..797e5cbf9e1
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Sgi.h
@@ -0,0 +1,39 @@
+/* Sgi.h */
+
+typedef struct {
+ /* CONFIGURATION */
+
+ /* Number of bytes per channel per pixel */
+ int bpc;
+
+ /* RLE offsets table */
+ UINT32 *starttab;
+
+ /* RLE lengths table */
+ UINT32 *lengthtab;
+
+ /* current row offset */
+ UINT32 rleoffset;
+
+ /* current row length */
+ UINT32 rlelength;
+
+ /* RLE table size */
+ int tablen;
+
+ /* RLE table index */
+ int tabindex;
+
+ /* buffer index */
+ int bufindex;
+
+ /* current row index */
+ int rowno;
+
+ /* current channel index */
+ int channo;
+
+ /* image data size from file descriptor */
+ long bufsize;
+
+} SGISTATE;
diff --git a/contrib/python/Pillow/py3/libImaging/SgiRleDecode.c b/contrib/python/Pillow/py3/libImaging/SgiRleDecode.c
new file mode 100644
index 00000000000..4eef44ba510
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/SgiRleDecode.c
@@ -0,0 +1,288 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for Sgi RLE data.
+ *
+ * history:
+ * 2017-07-28 mb fixed for images larger than 64KB
+ * 2017-07-20 mb created
+ *
+ * Copyright (c) Mickael Bonfill 2017.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+#include "Sgi.h"
+
+#define SGI_HEADER_SIZE 512
+#define RLE_COPY_FLAG 0x80
+#define RLE_MAX_RUN 0x7f
+
+static void
+read4B(UINT32 *dest, UINT8 *buf) {
+ *dest = (UINT32)((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
+}
+
+/*
+ SgiRleDecoding is done in a single channel row oriented set of RLE chunks.
+
+ * The file is arranged as
+ - SGI Header
+ - Rle Offset Table
+ - Rle Length Table
+ - Scanline Data
+
+ * Each RLE atom is c->bpc bytes wide (1 or 2)
+
+ * Each RLE Chunk is [specifier atom] [ 1 or n data atoms ]
+
+ * Copy Atoms are a byte with the high bit set, and the low 7 are
+ the number of bytes to copy from the source to the
+ destination. e.g.
+
+ CBBBBBBBB or 0CHLHLHLHLHLHL (B=byte, H/L = Hi low bytes)
+
+ * Run atoms do not have the high bit set, and the low 7 bits are
+ the number of copies of the next atom to copy to the
+ destination. e.g.:
+
+ RB -> BBBBB or RHL -> HLHLHLHLHL
+
+ The upshot of this is, there is no way to determine the required
+ length of the input buffer from reloffset and rlelength without
+ going through the data at that scan line.
+
+ Furthermore, there's no requirement that individual scan lines
+ pointed to from the rleoffset table are in any sort of order or
+ used only once, or even disjoint. There's also no requirement that
+ all of the data in the scan line area of the image file be used
+
+ */
+static int
+expandrow(UINT8 *dest, UINT8 *src, int n, int z, int xsize, UINT8 *end_of_buffer) {
+ /*
+ * n here is the number of rlechunks
+ * z is the number of channels, for calculating the interleave
+ * offset to go to RGBA style pixels
+ * xsize is the row width
+ * end_of_buffer is the address of the end of the input buffer
+ */
+
+ UINT8 pixel, count;
+ int x = 0;
+
+ for (; n > 0; n--) {
+ if (src > end_of_buffer) {
+ return -1;
+ }
+ pixel = *src++;
+ if (n == 1 && pixel != 0) {
+ return n;
+ }
+ count = pixel & RLE_MAX_RUN;
+ if (!count) {
+ return count;
+ }
+ if (x + count > xsize) {
+ return -1;
+ }
+ x += count;
+ if (pixel & RLE_COPY_FLAG) {
+ if (src + count > end_of_buffer) {
+ return -1;
+ }
+ while (count--) {
+ *dest = *src++;
+ dest += z;
+ }
+
+ } else {
+ if (src > end_of_buffer) {
+ return -1;
+ }
+ pixel = *src++;
+ while (count--) {
+ *dest = pixel;
+ dest += z;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+expandrow2(UINT8 *dest, const UINT8 *src, int n, int z, int xsize, UINT8 *end_of_buffer) {
+ UINT8 pixel, count;
+ int x = 0;
+
+ for (; n > 0; n--) {
+ if (src + 1 > end_of_buffer) {
+ return -1;
+ }
+ pixel = src[1];
+ src += 2;
+ if (n == 1 && pixel != 0) {
+ return n;
+ }
+ count = pixel & RLE_MAX_RUN;
+ if (!count) {
+ return count;
+ }
+ if (x + count > xsize) {
+ return -1;
+ }
+ x += count;
+ if (pixel & RLE_COPY_FLAG) {
+ if (src + 2 * count > end_of_buffer) {
+ return -1;
+ }
+ while (count--) {
+ memcpy(dest, src, 2);
+ src += 2;
+ dest += z * 2;
+ }
+ } else {
+ if (src + 2 > end_of_buffer) {
+ return -1;
+ }
+ while (count--) {
+ memcpy(dest, src, 2);
+ dest += z * 2;
+ }
+ src += 2;
+ }
+ }
+ return 0;
+}
+
+int
+ImagingSgiRleDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ UINT8 *ptr;
+ SGISTATE *c;
+ int err = 0;
+ int status;
+
+ /* size check */
+ if (im->xsize > INT_MAX / im->bands || im->ysize > INT_MAX / im->bands) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+
+ /* Get all data from File descriptor */
+ c = (SGISTATE *)state->context;
+ _imaging_seek_pyFd(state->fd, 0L, SEEK_END);
+ c->bufsize = _imaging_tell_pyFd(state->fd);
+ c->bufsize -= SGI_HEADER_SIZE;
+
+ c->tablen = im->bands * im->ysize;
+ /* below, we populate the starttab and lentab into the bufsize,
+ each with 4 bytes per element of tablen
+ Check here before we allocate any memory
+ */
+ if (c->bufsize < 8 * c->tablen) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+
+ ptr = malloc(sizeof(UINT8) * c->bufsize);
+ if (!ptr) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+ _imaging_seek_pyFd(state->fd, SGI_HEADER_SIZE, SEEK_SET);
+ if (_imaging_read_pyFd(state->fd, (char *)ptr, c->bufsize) != c->bufsize) {
+ state->errcode = IMAGING_CODEC_UNKNOWN;
+ return -1;
+ }
+
+
+ /* decoder initialization */
+ state->count = 0;
+ state->y = 0;
+ if (state->ystep < 0) {
+ state->y = im->ysize - 1;
+ } else {
+ state->ystep = 1;
+ }
+
+ /* Allocate memory for RLE tables and rows */
+ free(state->buffer);
+ state->buffer = NULL;
+ /* malloc overflow check above */
+ state->buffer = calloc(im->xsize * im->bands, sizeof(UINT8) * 2);
+ c->starttab = calloc(c->tablen, sizeof(UINT32));
+ c->lengthtab = calloc(c->tablen, sizeof(UINT32));
+ if (!state->buffer || !c->starttab || !c->lengthtab) {
+ err = IMAGING_CODEC_MEMORY;
+ goto sgi_finish_decode;
+ }
+ /* populate offsets table */
+ for (c->tabindex = 0, c->bufindex = 0; c->tabindex < c->tablen;
+ c->tabindex++, c->bufindex += 4) {
+ read4B(&c->starttab[c->tabindex], &ptr[c->bufindex]);
+ }
+ /* populate lengths table */
+ for (c->tabindex = 0, c->bufindex = c->tablen * sizeof(UINT32);
+ c->tabindex < c->tablen;
+ c->tabindex++, c->bufindex += 4) {
+ read4B(&c->lengthtab[c->tabindex], &ptr[c->bufindex]);
+ }
+
+ /* read compressed rows */
+ for (c->rowno = 0; c->rowno < im->ysize; c->rowno++, state->y += state->ystep) {
+ for (c->channo = 0; c->channo < im->bands; c->channo++) {
+ c->rleoffset = c->starttab[c->rowno + c->channo * im->ysize];
+ c->rlelength = c->lengthtab[c->rowno + c->channo * im->ysize];
+
+ // Check for underflow of rleoffset-SGI_HEADER_SIZE
+ if (c->rleoffset < SGI_HEADER_SIZE) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ goto sgi_finish_decode;
+ }
+
+ c->rleoffset -= SGI_HEADER_SIZE;
+
+ /* row decompression */
+ if (c->bpc == 1) {
+ status = expandrow(
+ &state->buffer[c->channo],
+ &ptr[c->rleoffset],
+ c->rlelength,
+ im->bands,
+ im->xsize,
+ &ptr[c->bufsize-1]);
+ } else {
+ status = expandrow2(
+ &state->buffer[c->channo * 2],
+ &ptr[c->rleoffset],
+ c->rlelength,
+ im->bands,
+ im->xsize,
+ &ptr[c->bufsize-1]);
+ }
+ if (status == -1) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ goto sgi_finish_decode;
+ } else if (status == 1) {
+ goto sgi_finish_decode;
+ }
+
+ }
+
+ /* store decompressed data in image */
+ state->shuffle((UINT8 *)im->image[state->y], state->buffer, im->xsize);
+ }
+
+sgi_finish_decode:;
+
+ free(c->starttab);
+ free(c->lengthtab);
+ free(ptr);
+ if (err != 0) {
+ state->errcode = err;
+ return -1;
+ }
+ return 0;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/Storage.c b/contrib/python/Pillow/py3/libImaging/Storage.c
new file mode 100644
index 00000000000..128595f6547
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Storage.c
@@ -0,0 +1,577 @@
+/*
+ * The Python Imaging Library
+ * $Id$
+ *
+ * imaging storage object
+ *
+ * This baseline implementation is designed to efficiently handle
+ * large images, provided they fit into the available memory.
+ *
+ * history:
+ * 1995-06-15 fl Created
+ * 1995-09-12 fl Updated API, compiles silently under ANSI C++
+ * 1995-11-26 fl Compiles silently under Borland 4.5 as well
+ * 1996-05-05 fl Correctly test status from Prologue
+ * 1997-05-12 fl Increased THRESHOLD (to speed up Tk interface)
+ * 1997-05-30 fl Added support for floating point images
+ * 1997-11-17 fl Added support for "RGBX" images
+ * 1998-01-11 fl Added support for integer images
+ * 1998-03-05 fl Exported Prologue/Epilogue functions
+ * 1998-07-01 fl Added basic "YCrCb" support
+ * 1998-07-03 fl Attach palette in prologue for "P" images
+ * 1998-07-09 hk Don't report MemoryError on zero-size images
+ * 1998-07-12 fl Change "YCrCb" to "YCbCr" (!)
+ * 1998-10-26 fl Added "I;16" and "I;16B" storage modes (experimental)
+ * 1998-12-29 fl Fixed allocation bug caused by previous fix
+ * 1999-02-03 fl Added "RGBa" and "BGR" modes (experimental)
+ * 2001-04-22 fl Fixed potential memory leak in ImagingCopyPalette
+ * 2003-09-26 fl Added "LA" and "PA" modes (experimental)
+ * 2005-10-02 fl Added image counter
+ *
+ * Copyright (c) 1998-2005 by Secret Labs AB
+ * Copyright (c) 1995-2005 by Fredrik Lundh
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+#include <string.h>
+
+/* --------------------------------------------------------------------
+ * Standard image object.
+ */
+
+Imaging
+ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) {
+ Imaging im;
+
+ /* linesize overflow check, roughly the current largest space req'd */
+ if (xsize > (INT_MAX / 4) - 1) {
+ return (Imaging)ImagingError_MemoryError();
+ }
+
+ im = (Imaging)calloc(1, size);
+ if (!im) {
+ return (Imaging)ImagingError_MemoryError();
+ }
+
+ /* Setup image descriptor */
+ im->xsize = xsize;
+ im->ysize = ysize;
+
+ im->type = IMAGING_TYPE_UINT8;
+
+ if (strcmp(mode, "1") == 0) {
+ /* 1-bit images */
+ im->bands = im->pixelsize = 1;
+ im->linesize = xsize;
+
+ } else if (strcmp(mode, "P") == 0) {
+ /* 8-bit palette mapped images */
+ im->bands = im->pixelsize = 1;
+ im->linesize = xsize;
+ im->palette = ImagingPaletteNew("RGB");
+
+ } else if (strcmp(mode, "PA") == 0) {
+ /* 8-bit palette with alpha */
+ im->bands = 2;
+ im->pixelsize = 4; /* store in image32 memory */
+ im->linesize = xsize * 4;
+ im->palette = ImagingPaletteNew("RGB");
+
+ } else if (strcmp(mode, "L") == 0) {
+ /* 8-bit greyscale (luminance) images */
+ im->bands = im->pixelsize = 1;
+ im->linesize = xsize;
+
+ } else if (strcmp(mode, "LA") == 0) {
+ /* 8-bit greyscale (luminance) with alpha */
+ im->bands = 2;
+ im->pixelsize = 4; /* store in image32 memory */
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "La") == 0) {
+ /* 8-bit greyscale (luminance) with premultiplied alpha */
+ im->bands = 2;
+ im->pixelsize = 4; /* store in image32 memory */
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "F") == 0) {
+ /* 32-bit floating point images */
+ im->bands = 1;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+ im->type = IMAGING_TYPE_FLOAT32;
+
+ } else if (strcmp(mode, "I") == 0) {
+ /* 32-bit integer images */
+ im->bands = 1;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+ im->type = IMAGING_TYPE_INT32;
+
+ } else if (
+ strcmp(mode, "I;16") == 0 || strcmp(mode, "I;16L") == 0 ||
+ strcmp(mode, "I;16B") == 0 || strcmp(mode, "I;16N") == 0) {
+ /* EXPERIMENTAL */
+ /* 16-bit raw integer images */
+ im->bands = 1;
+ im->pixelsize = 2;
+ im->linesize = xsize * 2;
+ im->type = IMAGING_TYPE_SPECIAL;
+
+ } else if (strcmp(mode, "RGB") == 0) {
+ /* 24-bit true colour images */
+ im->bands = 3;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "BGR;15") == 0) {
+ /* EXPERIMENTAL */
+ /* 15-bit reversed true colour */
+ im->bands = 3;
+ im->pixelsize = 2;
+ im->linesize = (xsize * 2 + 3) & -4;
+ im->type = IMAGING_TYPE_SPECIAL;
+
+ } else if (strcmp(mode, "BGR;16") == 0) {
+ /* EXPERIMENTAL */
+ /* 16-bit reversed true colour */
+ im->bands = 3;
+ im->pixelsize = 2;
+ im->linesize = (xsize * 2 + 3) & -4;
+ im->type = IMAGING_TYPE_SPECIAL;
+
+ } else if (strcmp(mode, "BGR;24") == 0) {
+ /* EXPERIMENTAL */
+ /* 24-bit reversed true colour */
+ im->bands = 3;
+ im->pixelsize = 3;
+ im->linesize = (xsize * 3 + 3) & -4;
+ im->type = IMAGING_TYPE_SPECIAL;
+
+ } else if (strcmp(mode, "RGBX") == 0) {
+ /* 32-bit true colour images with padding */
+ im->bands = im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "RGBA") == 0) {
+ /* 32-bit true colour images with alpha */
+ im->bands = im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "RGBa") == 0) {
+ /* 32-bit true colour images with premultiplied alpha */
+ im->bands = im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "CMYK") == 0) {
+ /* 32-bit colour separation */
+ im->bands = im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "YCbCr") == 0) {
+ /* 24-bit video format */
+ im->bands = 3;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "LAB") == 0) {
+ /* 24-bit color, luminance, + 2 color channels */
+ /* L is uint8, a,b are int8 */
+ im->bands = 3;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "HSV") == 0) {
+ /* 24-bit color, luminance, + 2 color channels */
+ /* L is uint8, a,b are int8 */
+ im->bands = 3;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else {
+ free(im);
+ return (Imaging)ImagingError_ValueError("unrecognized image mode");
+ }
+
+ /* Setup image descriptor */
+ strcpy(im->mode, mode);
+
+ /* Pointer array (allocate at least one line, to avoid MemoryError
+ exceptions on platforms where calloc(0, x) returns NULL) */
+ im->image = (char **)calloc((ysize > 0) ? ysize : 1, sizeof(void *));
+
+ if (!im->image) {
+ free(im);
+ return (Imaging)ImagingError_MemoryError();
+ }
+
+ /* Initialize alias pointers to pixel data. */
+ switch (im->pixelsize) {
+ case 1:
+ case 2:
+ case 3:
+ im->image8 = (UINT8 **)im->image;
+ break;
+ case 4:
+ im->image32 = (INT32 **)im->image;
+ break;
+ }
+
+ ImagingDefaultArena.stats_new_count += 1;
+
+ return im;
+}
+
+Imaging
+ImagingNewPrologue(const char *mode, int xsize, int ysize) {
+ return ImagingNewPrologueSubtype(
+ mode, xsize, ysize, sizeof(struct ImagingMemoryInstance));
+}
+
+void
+ImagingDelete(Imaging im) {
+ if (!im) {
+ return;
+ }
+
+ if (im->palette) {
+ ImagingPaletteDelete(im->palette);
+ }
+
+ if (im->destroy) {
+ im->destroy(im);
+ }
+
+ if (im->image) {
+ free(im->image);
+ }
+
+ free(im);
+}
+
+/* Array Storage Type */
+/* ------------------ */
+/* Allocate image as an array of line buffers. */
+
+#define IMAGING_PAGE_SIZE (4096)
+
+struct ImagingMemoryArena ImagingDefaultArena = {
+ 1, // alignment
+ 16 * 1024 * 1024, // block_size
+ 0, // blocks_max
+ 0, // blocks_cached
+ NULL, // blocks_pool
+ 0,
+ 0,
+ 0,
+ 0,
+ 0 // Stats
+};
+
+int
+ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max) {
+ void *p;
+ /* Free already cached blocks */
+ ImagingMemoryClearCache(arena, blocks_max);
+
+ if (blocks_max == 0 && arena->blocks_pool != NULL) {
+ free(arena->blocks_pool);
+ arena->blocks_pool = NULL;
+ } else if (arena->blocks_pool != NULL) {
+ p = realloc(arena->blocks_pool, sizeof(*arena->blocks_pool) * blocks_max);
+ if (!p) {
+ // Leave previous blocks_max value
+ return 0;
+ }
+ arena->blocks_pool = p;
+ } else {
+ arena->blocks_pool = calloc(sizeof(*arena->blocks_pool), blocks_max);
+ if (!arena->blocks_pool) {
+ return 0;
+ }
+ }
+ arena->blocks_max = blocks_max;
+
+ return 1;
+}
+
+void
+ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size) {
+ while (arena->blocks_cached > new_size) {
+ arena->blocks_cached -= 1;
+ free(arena->blocks_pool[arena->blocks_cached].ptr);
+ arena->stats_freed_blocks += 1;
+ }
+}
+
+ImagingMemoryBlock
+memory_get_block(ImagingMemoryArena arena, int requested_size, int dirty) {
+ ImagingMemoryBlock block = {NULL, 0};
+
+ if (arena->blocks_cached > 0) {
+ // Get block from cache
+ arena->blocks_cached -= 1;
+ block = arena->blocks_pool[arena->blocks_cached];
+ // Reallocate if needed
+ if (block.size != requested_size) {
+ block.ptr = realloc(block.ptr, requested_size);
+ }
+ if (!block.ptr) {
+ // Can't allocate, free previous pointer (it is still valid)
+ free(arena->blocks_pool[arena->blocks_cached].ptr);
+ arena->stats_freed_blocks += 1;
+ return block;
+ }
+ if (!dirty) {
+ memset(block.ptr, 0, requested_size);
+ }
+ arena->stats_reused_blocks += 1;
+ if (block.ptr != arena->blocks_pool[arena->blocks_cached].ptr) {
+ arena->stats_reallocated_blocks += 1;
+ }
+ } else {
+ if (dirty) {
+ block.ptr = malloc(requested_size);
+ } else {
+ block.ptr = calloc(1, requested_size);
+ }
+ arena->stats_allocated_blocks += 1;
+ }
+ block.size = requested_size;
+ return block;
+}
+
+void
+memory_return_block(ImagingMemoryArena arena, ImagingMemoryBlock block) {
+ if (arena->blocks_cached < arena->blocks_max) {
+ // Reduce block size
+ if (block.size > arena->block_size) {
+ block.size = arena->block_size;
+ block.ptr = realloc(block.ptr, arena->block_size);
+ }
+ arena->blocks_pool[arena->blocks_cached] = block;
+ arena->blocks_cached += 1;
+ } else {
+ free(block.ptr);
+ arena->stats_freed_blocks += 1;
+ }
+}
+
+static void
+ImagingDestroyArray(Imaging im) {
+ int y = 0;
+
+ if (im->blocks) {
+ while (im->blocks[y].ptr) {
+ memory_return_block(&ImagingDefaultArena, im->blocks[y]);
+ y += 1;
+ }
+ free(im->blocks);
+ }
+}
+
+Imaging
+ImagingAllocateArray(Imaging im, int dirty, int block_size) {
+ int y, line_in_block, current_block;
+ ImagingMemoryArena arena = &ImagingDefaultArena;
+ ImagingMemoryBlock block = {NULL, 0};
+ int aligned_linesize, lines_per_block, blocks_count;
+ char *aligned_ptr = NULL;
+
+ /* 0-width or 0-height image. No need to do anything */
+ if (!im->linesize || !im->ysize) {
+ return im;
+ }
+
+ aligned_linesize = (im->linesize + arena->alignment - 1) & -arena->alignment;
+ lines_per_block = (block_size - (arena->alignment - 1)) / aligned_linesize;
+ if (lines_per_block == 0) {
+ lines_per_block = 1;
+ }
+ blocks_count = (im->ysize + lines_per_block - 1) / lines_per_block;
+ // printf("NEW size: %dx%d, ls: %d, lpb: %d, blocks: %d\n",
+ // im->xsize, im->ysize, aligned_linesize, lines_per_block, blocks_count);
+
+ /* One extra pointer is always NULL */
+ im->blocks = calloc(sizeof(*im->blocks), blocks_count + 1);
+ if (!im->blocks) {
+ return (Imaging)ImagingError_MemoryError();
+ }
+
+ /* Allocate image as an array of lines */
+ line_in_block = 0;
+ current_block = 0;
+ for (y = 0; y < im->ysize; y++) {
+ if (line_in_block == 0) {
+ int required;
+ int lines_remaining = lines_per_block;
+ if (lines_remaining > im->ysize - y) {
+ lines_remaining = im->ysize - y;
+ }
+ required = lines_remaining * aligned_linesize + arena->alignment - 1;
+ block = memory_get_block(arena, required, dirty);
+ if (!block.ptr) {
+ ImagingDestroyArray(im);
+ return (Imaging)ImagingError_MemoryError();
+ }
+ im->blocks[current_block] = block;
+ /* Bulletproof code from libc _int_memalign */
+ aligned_ptr = (char *)(
+ ((size_t) (block.ptr + arena->alignment - 1)) &
+ -((Py_ssize_t) arena->alignment));
+ }
+
+ im->image[y] = aligned_ptr + aligned_linesize * line_in_block;
+
+ line_in_block += 1;
+ if (line_in_block >= lines_per_block) {
+ /* Reset counter and start new block */
+ line_in_block = 0;
+ current_block += 1;
+ }
+ }
+
+ im->destroy = ImagingDestroyArray;
+
+ return im;
+}
+
+/* Block Storage Type */
+/* ------------------ */
+/* Allocate image as a single block. */
+
+static void
+ImagingDestroyBlock(Imaging im) {
+ if (im->block) {
+ free(im->block);
+ }
+}
+
+Imaging
+ImagingAllocateBlock(Imaging im) {
+ Py_ssize_t y, i;
+
+ /* overflow check for malloc */
+ if (im->linesize && im->ysize > INT_MAX / im->linesize) {
+ return (Imaging)ImagingError_MemoryError();
+ }
+
+ if (im->ysize * im->linesize <= 0) {
+ /* some platforms return NULL for malloc(0); this fix
+ prevents MemoryError on zero-sized images on such
+ platforms */
+ im->block = (char *)malloc(1);
+ } else {
+ /* malloc check ok, overflow check above */
+ im->block = (char *)calloc(im->ysize, im->linesize);
+ }
+
+ if (!im->block) {
+ return (Imaging)ImagingError_MemoryError();
+ }
+
+ for (y = i = 0; y < im->ysize; y++) {
+ im->image[y] = im->block + i;
+ i += im->linesize;
+ }
+
+ im->destroy = ImagingDestroyBlock;
+
+ return im;
+}
+
+/* --------------------------------------------------------------------
+ * Create a new, internally allocated, image.
+ */
+
+Imaging
+ImagingNewInternal(const char *mode, int xsize, int ysize, int dirty) {
+ Imaging im;
+
+ if (xsize < 0 || ysize < 0) {
+ return (Imaging)ImagingError_ValueError("bad image size");
+ }
+
+ im = ImagingNewPrologue(mode, xsize, ysize);
+ if (!im) {
+ return NULL;
+ }
+
+ if (ImagingAllocateArray(im, dirty, ImagingDefaultArena.block_size)) {
+ return im;
+ }
+
+ ImagingError_Clear();
+
+ // Try to allocate the image once more with smallest possible block size
+ if (ImagingAllocateArray(im, dirty, IMAGING_PAGE_SIZE)) {
+ return im;
+ }
+
+ ImagingDelete(im);
+ return NULL;
+}
+
+Imaging
+ImagingNew(const char *mode, int xsize, int ysize) {
+ return ImagingNewInternal(mode, xsize, ysize, 0);
+}
+
+Imaging
+ImagingNewDirty(const char *mode, int xsize, int ysize) {
+ return ImagingNewInternal(mode, xsize, ysize, 1);
+}
+
+Imaging
+ImagingNewBlock(const char *mode, int xsize, int ysize) {
+ Imaging im;
+
+ if (xsize < 0 || ysize < 0) {
+ return (Imaging)ImagingError_ValueError("bad image size");
+ }
+
+ im = ImagingNewPrologue(mode, xsize, ysize);
+ if (!im) {
+ return NULL;
+ }
+
+ if (ImagingAllocateBlock(im)) {
+ return im;
+ }
+
+ ImagingDelete(im);
+ return NULL;
+}
+
+Imaging
+ImagingNew2Dirty(const char *mode, Imaging imOut, Imaging imIn) {
+ /* allocate or validate output image */
+
+ if (imOut) {
+ /* make sure images match */
+ if (strcmp(imOut->mode, mode) != 0 || imOut->xsize != imIn->xsize ||
+ imOut->ysize != imIn->ysize) {
+ return ImagingError_Mismatch();
+ }
+ } else {
+ /* create new image */
+ imOut = ImagingNewDirty(mode, imIn->xsize, imIn->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+ }
+
+ return imOut;
+}
+
+void
+ImagingCopyPalette(Imaging destination, Imaging source) {
+ if (source->palette) {
+ if (destination->palette) {
+ ImagingPaletteDelete(destination->palette);
+ }
+ destination->palette = ImagingPaletteDuplicate(source->palette);
+ }
+}
diff --git a/contrib/python/Pillow/py3/libImaging/SunRleDecode.c b/contrib/python/Pillow/py3/libImaging/SunRleDecode.c
new file mode 100644
index 00000000000..9d8e1292a47
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/SunRleDecode.c
@@ -0,0 +1,139 @@
+/*
+ * THIS IS WORK IN PROGRESS
+ *
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for SUN RLE data.
+ *
+ * history:
+ * 97-01-04 fl Created
+ *
+ * Copyright (c) Fredrik Lundh 1997.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+int
+ImagingSunRleDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ int n;
+ UINT8 *ptr;
+ UINT8 extra_data = 0;
+ UINT8 extra_bytes = 0;
+
+ ptr = buf;
+
+ for (;;) {
+ if (bytes < 1) {
+ return ptr - buf;
+ }
+
+ if (ptr[0] == 0x80) {
+ if (bytes < 2) {
+ break;
+ }
+
+ n = ptr[1];
+
+ if (n == 0) {
+ /* Literal 0x80 (2 bytes) */
+ n = 1;
+
+ state->buffer[state->x] = 0x80;
+
+ ptr += 2;
+ bytes -= 2;
+
+ } else {
+ /* Run (3 bytes) */
+ if (bytes < 3) {
+ break;
+ }
+
+ /* from (https://www.fileformat.info/format/sunraster/egff.htm)
+
+ For example, a run of 100 pixels with the value of
+ 0Ah would encode as the values 80h 64h 0Ah. A
+ single pixel value of 80h would encode as the
+ values 80h 00h. The four unencoded bytes 12345678h
+ would be stored in the RLE stream as 12h 34h 56h
+ 78h. 100 pixels, n=100, not 100 pixels, n=99.
+
+ But Wait! There's More!
+ (https://www.fileformat.info/format/sunraster/spec/598a59c4fac64c52897585d390d86360/view.htm)
+
+ If the first byte is 0x80, and the second byte is
+ not zero, the record is three bytes long. The
+ second byte is a count and the third byte is a
+ value. Output (count+1) pixels of that value.
+
+ 2 specs, same site, but Imagemagick and GIMP seem
+ to agree on the second one.
+ */
+ n += 1;
+
+ if (state->x + n > state->bytes) {
+ extra_bytes = n; /* full value */
+ n = state->bytes - state->x;
+ extra_bytes -= n;
+ extra_data = ptr[2];
+ }
+
+ memset(state->buffer + state->x, ptr[2], n);
+
+ ptr += 3;
+ bytes -= 3;
+ }
+
+ } else {
+ /* Literal byte */
+ n = 1;
+
+ state->buffer[state->x] = ptr[0];
+
+ ptr += 1;
+ bytes -= 1;
+ }
+
+ for (;;) {
+ state->x += n;
+
+ if (state->x >= state->bytes) {
+ /* Got a full line, unpack it */
+ state->shuffle(
+ (UINT8 *)im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->buffer,
+ state->xsize);
+
+ state->x = 0;
+
+ if (++state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+ }
+
+ if (extra_bytes == 0) {
+ break;
+ }
+
+ if (state->x > 0) {
+ break; // assert
+ }
+
+ if (extra_bytes >= state->bytes) {
+ n = state->bytes;
+ } else {
+ n = extra_bytes;
+ }
+ memset(state->buffer + state->x, extra_data, n);
+ extra_bytes -= n;
+ }
+ }
+
+ return ptr - buf;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/TgaRleDecode.c b/contrib/python/Pillow/py3/libImaging/TgaRleDecode.c
new file mode 100644
index 00000000000..95ae9b62228
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/TgaRleDecode.c
@@ -0,0 +1,129 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for Targa RLE data.
+ *
+ * history:
+ * 97-01-04 fl created
+ * 98-09-11 fl don't one byte per pixel; take orientation into account
+ *
+ * Copyright (c) Fredrik Lundh 1997.
+ * Copyright (c) Secret Labs AB 1997-98.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+int
+ImagingTgaRleDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ int n, depth;
+ UINT8 *ptr;
+ int extra_bytes = 0;
+
+ ptr = buf;
+
+ if (state->state == 0) {
+ /* check image orientation */
+ if (state->ystep < 0) {
+ state->y = state->ysize - 1;
+ state->ystep = -1;
+ } else {
+ state->ystep = 1;
+ }
+
+ state->state = 1;
+ }
+
+ depth = state->count;
+
+ for (;;) {
+ if (bytes < 1) {
+ return ptr - buf;
+ }
+
+ n = depth * ((ptr[0] & 0x7f) + 1);
+ if (ptr[0] & 0x80) {
+ /* Run (1 + pixelsize bytes) */
+ if (bytes < 1 + depth) {
+ break;
+ }
+
+ if (state->x + n > state->bytes) {
+ state->errcode = IMAGING_CODEC_OVERRUN;
+ return -1;
+ }
+
+ if (depth == 1) {
+ memset(state->buffer + state->x, ptr[1], n);
+ } else {
+ int i;
+ for (i = 0; i < n; i += depth) {
+ memcpy(state->buffer + state->x + i, ptr + 1, depth);
+ }
+ }
+
+ ptr += 1 + depth;
+ bytes -= 1 + depth;
+ } else {
+ /* Literal (1+n+1 bytes block) */
+ if (bytes < 1 + n) {
+ break;
+ }
+
+ if (state->x + n > state->bytes) {
+ extra_bytes = n; /* full value */
+ n = state->bytes - state->x;
+ extra_bytes -= n;
+ }
+
+ memcpy(state->buffer + state->x, ptr + 1, n);
+
+ ptr += 1 + n;
+ bytes -= 1 + n;
+ }
+
+ for (;;) {
+ state->x += n;
+
+ if (state->x >= state->bytes) {
+ /* Got a full line, unpack it */
+ state->shuffle(
+ (UINT8 *)im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->buffer,
+ state->xsize);
+
+ state->x = 0;
+
+ state->y += state->ystep;
+
+ if (state->y < 0 || state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+ }
+
+ if (extra_bytes == 0) {
+ break;
+ }
+
+ if (state->x > 0) {
+ break; // assert
+ }
+
+ if (extra_bytes >= state->bytes) {
+ n = state->bytes;
+ } else {
+ n = extra_bytes;
+ }
+ memcpy(state->buffer + state->x, ptr, n);
+ ptr += n;
+ bytes -= n;
+ extra_bytes -= n;
+ }
+ }
+
+ return ptr - buf;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/TgaRleEncode.c b/contrib/python/Pillow/py3/libImaging/TgaRleEncode.c
new file mode 100644
index 00000000000..aa7e7b96d81
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/TgaRleEncode.c
@@ -0,0 +1,157 @@
+
+#include "Imaging.h"
+
+#include <assert.h>
+#include <string.h>
+
+static int
+comparePixels(const UINT8 *buf, int x, int bytesPerPixel) {
+ buf += x * bytesPerPixel;
+ return memcmp(buf, buf + bytesPerPixel, bytesPerPixel) == 0;
+}
+
+int
+ImagingTgaRleEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
+ UINT8 *dst;
+ int bytesPerPixel;
+
+ if (state->state == 0) {
+ if (state->ystep < 0) {
+ state->ystep = -1;
+ state->y = state->ysize - 1;
+ } else {
+ state->ystep = 1;
+ }
+
+ state->state = 1;
+ }
+
+ dst = buf;
+ bytesPerPixel = (state->bits + 7) / 8;
+
+ while (1) {
+ int flushCount;
+
+ /*
+ * state->count is the numbers of bytes in the packet,
+ * excluding the 1-byte descriptor.
+ */
+ if (state->count == 0) {
+ UINT8 *row;
+ UINT8 descriptor;
+ int startX;
+
+ assert(state->x <= state->xsize);
+
+ /* Make sure we have space for the descriptor. */
+ if (bytes < 1) {
+ break;
+ }
+
+ if (state->x == state->xsize) {
+ state->x = 0;
+
+ state->y += state->ystep;
+ if (state->y < 0 || state->y >= state->ysize) {
+ state->errcode = IMAGING_CODEC_END;
+ break;
+ }
+ }
+
+ if (state->x == 0) {
+ state->shuffle(
+ state->buffer,
+ (UINT8 *)im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->xsize);
+ }
+
+ row = state->buffer;
+
+ /* Start with a raw packet for 1 px. */
+ descriptor = 0;
+ startX = state->x;
+ state->count = bytesPerPixel;
+
+ if (state->x + 1 < state->xsize) {
+ int maxLookup;
+ int isRaw;
+
+ isRaw = !comparePixels(row, state->x, bytesPerPixel);
+ ++state->x;
+
+ /*
+ * A packet can contain up to 128 pixels;
+ * 2 are already behind (state->x points to
+ * the second one).
+ */
+ maxLookup = state->x + 126;
+ /* A packet must not span multiple rows. */
+ if (maxLookup > state->xsize - 1) {
+ maxLookup = state->xsize - 1;
+ }
+
+ if (isRaw) {
+ while (state->x < maxLookup) {
+ if (!comparePixels(row, state->x, bytesPerPixel)) {
+ ++state->x;
+ } else {
+ /* Two identical pixels will go to RLE packet. */
+ --state->x;
+ break;
+ }
+ }
+
+ state->count += (state->x - startX) * bytesPerPixel;
+ } else {
+ descriptor |= 0x80;
+
+ while (state->x < maxLookup) {
+ if (comparePixels(row, state->x, bytesPerPixel)) {
+ ++state->x;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ /*
+ * state->x currently points to the last pixel to be
+ * included in the packet. The pixel count in the
+ * descriptor is 1 less than actual number of pixels in
+ * the packet, that is, state->x == startX if we encode
+ * only 1 pixel.
+ */
+ descriptor += state->x - startX;
+ *dst++ = descriptor;
+ --bytes;
+
+ /* Advance to past-the-last encoded pixel. */
+ ++state->x;
+ }
+
+ assert(bytes >= 0);
+ assert(state->count > 0);
+ assert(state->x > 0);
+ assert(state->count <= state->x * bytesPerPixel);
+
+ if (bytes == 0) {
+ break;
+ }
+
+ flushCount = state->count;
+ if (flushCount > bytes) {
+ flushCount = bytes;
+ }
+
+ memcpy(
+ dst, state->buffer + (state->x * bytesPerPixel - state->count), flushCount);
+ dst += flushCount;
+ bytes -= flushCount;
+
+ state->count -= flushCount;
+ }
+
+ return dst - buf;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/TiffDecode.c b/contrib/python/Pillow/py3/libImaging/TiffDecode.c
new file mode 100644
index 00000000000..35122f18245
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/TiffDecode.c
@@ -0,0 +1,997 @@
+/*
+ * The Python Imaging Library.
+ * $Id: //modules/pil/libImaging/TiffDecode.c#1 $
+ *
+ * LibTiff-based Group3 and Group4 decoder
+ *
+ *
+ * started modding to use non-private tiff functions to port to libtiff 4.x
+ * eds 3/12/12
+ *
+ */
+
+#include "Imaging.h"
+
+#ifdef HAVE_LIBTIFF
+
+#ifndef uint
+#define uint uint32
+#endif
+
+#include "TiffDecode.h"
+
+/* Convert C file descriptor to WinApi HFILE if LibTiff was compiled with tif_win32.c
+ *
+ * This cast is safe, as the top 32-bits of HFILE are guaranteed to be zero,
+ * see
+ * https://learn.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication
+ */
+#ifndef USE_WIN32_FILEIO
+#define fd_to_tiff_fd(fd) (fd)
+#else
+#define fd_to_tiff_fd(fd) ((int)_get_osfhandle(fd))
+#endif
+
+void
+dump_state(const TIFFSTATE *state) {
+ TRACE(
+ ("State: Location %u size %d eof %d data: %p ifd: %d\n",
+ (uint)state->loc,
+ (int)state->size,
+ (uint)state->eof,
+ state->data,
+ state->ifd));
+}
+
+/*
+ procs for TIFFOpenClient
+*/
+
+tsize_t
+_tiffReadProc(thandle_t hdata, tdata_t buf, tsize_t size) {
+ TIFFSTATE *state = (TIFFSTATE *)hdata;
+ tsize_t to_read;
+
+ TRACE(("_tiffReadProc: %d \n", (int)size));
+ dump_state(state);
+
+ if (state->loc > state->eof) {
+ TIFFError("_tiffReadProc", "Invalid Read at loc %" PRIu64 ", eof: %" PRIu64, state->loc, state->eof);
+ return 0;
+ }
+ to_read = min(size, min(state->size, (tsize_t)state->eof) - (tsize_t)state->loc);
+ TRACE(("to_read: %d\n", (int)to_read));
+
+ _TIFFmemcpy(buf, (UINT8 *)state->data + state->loc, to_read);
+ state->loc += (toff_t)to_read;
+
+ TRACE(("location: %u\n", (uint)state->loc));
+ return to_read;
+}
+
+tsize_t
+_tiffWriteProc(thandle_t hdata, tdata_t buf, tsize_t size) {
+ TIFFSTATE *state = (TIFFSTATE *)hdata;
+ tsize_t to_write;
+
+ TRACE(("_tiffWriteProc: %d \n", (int)size));
+ dump_state(state);
+
+ to_write = min(size, state->size - (tsize_t)state->loc);
+ if (state->flrealloc && size > to_write) {
+ tdata_t new_data;
+ tsize_t newsize = state->size;
+ while (newsize < (size + state->size)) {
+ if (newsize > INT_MAX - 64 * 1024) {
+ return 0;
+ }
+ newsize += 64 * 1024;
+ // newsize*=2; // UNDONE, by 64k chunks?
+ }
+ TRACE(("Reallocing in write to %d bytes\n", (int)newsize));
+ /* malloc check ok, overflow checked above */
+ new_data = realloc(state->data, newsize);
+ if (!new_data) {
+ // fail out
+ return 0;
+ }
+ state->data = new_data;
+ state->size = newsize;
+ to_write = size;
+ }
+
+ TRACE(("to_write: %d\n", (int)to_write));
+
+ _TIFFmemcpy((UINT8 *)state->data + state->loc, buf, to_write);
+ state->loc += (toff_t)to_write;
+ state->eof = max(state->loc, state->eof);
+
+ dump_state(state);
+ return to_write;
+}
+
+toff_t
+_tiffSeekProc(thandle_t hdata, toff_t off, int whence) {
+ TIFFSTATE *state = (TIFFSTATE *)hdata;
+
+ TRACE(("_tiffSeekProc: off: %u whence: %d \n", (uint)off, whence));
+ dump_state(state);
+ switch (whence) {
+ case 0:
+ state->loc = off;
+ break;
+ case 1:
+ state->loc += off;
+ break;
+ case 2:
+ state->loc = state->eof + off;
+ break;
+ }
+ dump_state(state);
+ return state->loc;
+}
+
+int
+_tiffCloseProc(thandle_t hdata) {
+ TIFFSTATE *state = (TIFFSTATE *)hdata;
+
+ TRACE(("_tiffCloseProc \n"));
+ dump_state(state);
+
+ return 0;
+}
+
+toff_t
+_tiffSizeProc(thandle_t hdata) {
+ TIFFSTATE *state = (TIFFSTATE *)hdata;
+
+ TRACE(("_tiffSizeProc \n"));
+ dump_state(state);
+
+ return (toff_t)state->size;
+}
+
+int
+_tiffMapProc(thandle_t hdata, tdata_t *pbase, toff_t *psize) {
+ TIFFSTATE *state = (TIFFSTATE *)hdata;
+
+ TRACE(("_tiffMapProc input size: %u, data: %p\n", (uint)*psize, *pbase));
+ dump_state(state);
+
+ *pbase = state->data;
+ *psize = state->size;
+ TRACE(("_tiffMapProc returning size: %u, data: %p\n", (uint)*psize, *pbase));
+ return (1);
+}
+
+int
+_tiffNullMapProc(thandle_t hdata, tdata_t *pbase, toff_t *psize) {
+ (void)hdata;
+ (void)pbase;
+ (void)psize;
+ return (0);
+}
+
+void
+_tiffUnmapProc(thandle_t hdata, tdata_t base, toff_t size) {
+ TRACE(("_tiffUnMapProc\n"));
+ (void)hdata;
+ (void)base;
+ (void)size;
+}
+
+int
+ImagingLibTiffInit(ImagingCodecState state, int fp, uint32_t offset) {
+ TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
+
+ TRACE(("initing libtiff\n"));
+ TRACE(("filepointer: %d \n", fp));
+ TRACE(
+ ("State: count %d, state %d, x %d, y %d, ystep %d\n",
+ state->count,
+ state->state,
+ state->x,
+ state->y,
+ state->ystep));
+ TRACE(
+ ("State: xsize %d, ysize %d, xoff %d, yoff %d \n",
+ state->xsize,
+ state->ysize,
+ state->xoff,
+ state->yoff));
+ TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
+ TRACE(("State: context %p \n", state->context));
+
+ clientstate->loc = 0;
+ clientstate->size = 0;
+ clientstate->data = 0;
+ clientstate->fp = fp;
+ clientstate->ifd = offset;
+ clientstate->eof = 0;
+
+ return 1;
+}
+
+int
+_pickUnpackers(Imaging im, ImagingCodecState state, TIFF *tiff, uint16_t planarconfig, ImagingShuffler *unpackers) {
+ // if number of bands is 1, there is no difference with contig case
+ if (planarconfig == PLANARCONFIG_SEPARATE && im->bands > 1) {
+ uint16_t bits_per_sample = 8;
+
+ TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
+ if (bits_per_sample != 8 && bits_per_sample != 16) {
+ TRACE(("Invalid value for bits per sample: %d\n", bits_per_sample));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ // We'll pick appropriate set of unpackers depending on planar_configuration
+ // It does not matter if data is RGB(A), CMYK or LUV really,
+ // we just copy it plane by plane
+ unpackers[0] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "R;16N" : "R", NULL);
+ unpackers[1] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "G;16N" : "G", NULL);
+ unpackers[2] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "B;16N" : "B", NULL);
+ unpackers[3] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "A;16N" : "A", NULL);
+
+ return im->bands;
+ } else {
+ unpackers[0] = state->shuffle;
+
+ return 1;
+ }
+}
+
+int
+_decodeAsRGBA(Imaging im, ImagingCodecState state, TIFF *tiff) {
+ // To avoid dealing with YCbCr subsampling and other complications, let libtiff handle it
+ // Use a TIFFRGBAImage wrapping the tiff image, and let libtiff handle
+ // all of the conversion. Metadata read from the TIFFRGBAImage could
+ // be different from the metadata that the base tiff returns.
+
+ INT32 current_row;
+ UINT8 *new_data;
+ UINT32 rows_per_block, row_byte_size, rows_to_read;
+ int ret;
+ TIFFRGBAImage img;
+ char emsg[1024] = "";
+
+ // Since using TIFFRGBAImage* functions, we can read whole tiff into rastrr in one call
+ // Let's select smaller block size. Multiplying image width by (tile length OR rows per strip)
+ // gives us manageable block size in pixels
+ if (TIFFIsTiled(tiff)) {
+ ret = TIFFGetFieldDefaulted(tiff, TIFFTAG_TILELENGTH, &rows_per_block);
+ }
+ else {
+ ret = TIFFGetFieldDefaulted(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_block);
+ }
+
+ if (ret != 1 || rows_per_block==(UINT32)(-1)) {
+ rows_per_block = state->ysize;
+ }
+
+ TRACE(("RowsPerBlock: %u \n", rows_per_block));
+
+ if (!(TIFFRGBAImageOK(tiff, emsg) && TIFFRGBAImageBegin(&img, tiff, 0, emsg))) {
+ TRACE(("Decode error, msg: %s", emsg));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ // nothing to clean up, just return
+ return -1;
+ }
+
+ img.req_orientation = ORIENTATION_TOPLEFT;
+ img.col_offset = 0;
+
+ /* overflow check for row byte size */
+ if (INT_MAX / 4 < img.width) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ goto decodergba_err;
+ }
+
+ // TiffRGBAImages are 32bits/pixel.
+ row_byte_size = img.width * 4;
+
+ /* overflow check for realloc */
+ if (INT_MAX / row_byte_size < rows_per_block) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ goto decodergba_err;
+ }
+
+ state->bytes = rows_per_block * row_byte_size;
+
+ TRACE(("BlockSize: %d \n", state->bytes));
+
+ /* realloc to fit whole strip */
+ /* malloc check above */
+ new_data = realloc(state->buffer, state->bytes);
+ if (!new_data) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ goto decodergba_err;
+ }
+
+ state->buffer = new_data;
+
+ for (; state->y < state->ysize; state->y += rows_per_block) {
+ img.row_offset = state->y;
+ rows_to_read = min(rows_per_block, img.height - state->y);
+
+ if (!TIFFRGBAImageGet(&img, (UINT32 *)state->buffer, img.width, rows_to_read)) {
+ TRACE(("Decode Error, y: %d\n", state->y));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ goto decodergba_err;
+ }
+
+#if WORDS_BIGENDIAN
+ TIFFSwabArrayOfLong((UINT32 *)state->buffer, img.width * rows_to_read);
+#endif
+
+ TRACE(("Decoded strip for row %d \n", state->y));
+
+ // iterate over each row in the strip and stuff data into image
+ for (current_row = 0;
+ current_row < min((INT32)rows_per_block, state->ysize - state->y);
+ current_row++) {
+ TRACE(("Writing data into line %d ; \n", state->y + current_row));
+
+ // UINT8 * bbb = state->buffer + current_row * (state->bytes /
+ // rows_per_block); TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0],
+ // ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));
+
+ state->shuffle(
+ (UINT8 *)im->image[state->y + state->yoff + current_row] +
+ state->xoff * im->pixelsize,
+ state->buffer + current_row * row_byte_size,
+ state->xsize);
+ }
+ }
+
+decodergba_err:
+ TIFFRGBAImageEnd(&img);
+ if (state->errcode != 0) {
+ return -1;
+ }
+ return 0;
+}
+
+int
+_decodeTile(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, ImagingShuffler *unpackers) {
+ INT32 x, y, tile_y, current_tile_length, current_tile_width;
+ UINT32 tile_width, tile_length;
+ tsize_t tile_bytes_size, row_byte_size;
+ UINT8 *new_data;
+
+ tile_bytes_size = TIFFTileSize(tiff);
+
+ if (tile_bytes_size == 0) {
+ TRACE(("Decode Error, Can not calculate TileSize\n"));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ row_byte_size = TIFFTileRowSize(tiff);
+
+ if (row_byte_size == 0 || row_byte_size > tile_bytes_size) {
+ TRACE(("Decode Error, Can not calculate TileRowSize\n"));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ /* overflow check for realloc */
+ if (tile_bytes_size > INT_MAX - 1) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+
+ TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width);
+ TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length);
+
+ if (tile_width > INT_MAX || tile_length > INT_MAX) {
+ // state->x and state->y are ints
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+
+ if (tile_bytes_size > ((tile_length * state->bits / planes + 7) / 8) * tile_width) {
+ // If the tile size as expected by LibTiff isn't what we're expecting, abort.
+ // man: TIFFTileSize returns the equivalent size for a tile of data as it would be returned in a
+ // call to TIFFReadTile ...
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ state->bytes = tile_bytes_size;
+
+ TRACE(("TIFFTileSize: %d\n", state->bytes));
+
+ /* realloc to fit whole tile */
+ /* malloc check above */
+ new_data = realloc(state->buffer, state->bytes);
+ if (!new_data) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+ state->buffer = new_data;
+
+ for (y = state->yoff; y < state->ysize; y += tile_length) {
+ int plane;
+ for (plane = 0; plane < planes; plane++) {
+ ImagingShuffler shuffler = unpackers[plane];
+ for (x = state->xoff; x < state->xsize; x += tile_width) {
+ if (TIFFReadTile(tiff, (tdata_t)state->buffer, x, y, 0, plane) == -1) {
+ TRACE(("Decode Error, Tile at %dx%d\n", x, y));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ TRACE(("Read tile at %dx%d; \n\n", x, y));
+
+ current_tile_width = min((INT32) tile_width, state->xsize - x);
+ current_tile_length = min((INT32) tile_length, state->ysize - y);
+ // iterate over each line in the tile and stuff data into image
+ for (tile_y = 0; tile_y < current_tile_length; tile_y++) {
+ TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width));
+
+ // UINT8 * bbb = state->buffer + tile_y * row_byte_size;
+ // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));
+
+ shuffler((UINT8*) im->image[tile_y + y] + x * im->pixelsize,
+ state->buffer + tile_y * row_byte_size,
+ current_tile_width
+ );
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int
+_decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, ImagingShuffler *unpackers) {
+ INT32 strip_row = 0;
+ UINT8 *new_data;
+ UINT32 rows_per_strip;
+ int ret;
+ tsize_t strip_size, row_byte_size, unpacker_row_byte_size;
+
+ ret = TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip);
+ if (ret != 1 || rows_per_strip==(UINT32)(-1)) {
+ rows_per_strip = state->ysize;
+ }
+
+ if (rows_per_strip > INT_MAX) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+
+ TRACE(("RowsPerStrip: %u\n", rows_per_strip));
+
+ strip_size = TIFFStripSize(tiff);
+ if (strip_size > INT_MAX - 1) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+
+ unpacker_row_byte_size = (state->xsize * state->bits / planes + 7) / 8;
+ if (strip_size > (unpacker_row_byte_size * rows_per_strip)) {
+ // If the strip size as expected by LibTiff isn't what we're expecting, abort.
+ // man: TIFFStripSize returns the equivalent size for a strip of data as it would be returned in a
+ // call to TIFFReadEncodedStrip ...
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ state->bytes = strip_size;
+
+ TRACE(("StripSize: %d \n", state->bytes));
+
+ row_byte_size = TIFFScanlineSize(tiff);
+
+ // if the unpacker calculated row size is > row byte size, (at least) the last
+ // row of the strip will have a read buffer overflow.
+ if (row_byte_size == 0 || unpacker_row_byte_size > row_byte_size) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ TRACE(("RowsByteSize: %u \n", row_byte_size));
+
+ /* realloc to fit whole strip */
+ /* malloc check above */
+ new_data = realloc(state->buffer, state->bytes);
+ if (!new_data) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+
+ state->buffer = new_data;
+
+ for (; state->y < state->ysize; state->y += rows_per_strip) {
+ int plane;
+ for (plane = 0; plane < planes; plane++) {
+ ImagingShuffler shuffler = unpackers[plane];
+ if (TIFFReadEncodedStrip(tiff, TIFFComputeStrip(tiff, state->y, plane), (tdata_t)state->buffer, strip_size) == -1) {
+ TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0)));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ TRACE(("Decoded strip for row %d \n", state->y));
+
+ // iterate over each row in the strip and stuff data into image
+ for (strip_row = 0;
+ strip_row < min((INT32) rows_per_strip, state->ysize - state->y);
+ strip_row++) {
+ TRACE(("Writing data into line %d ; \n", state->y + strip_row));
+
+ // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip);
+ // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));
+
+ shuffler(
+ (UINT8*) im->image[state->y + state->yoff + strip_row] +
+ state->xoff * im->pixelsize,
+ state->buffer + strip_row * row_byte_size,
+ state->xsize);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int
+ImagingLibTiffDecode(
+ Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t bytes) {
+ TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
+ char *filename = "tempfile.tif";
+ char *mode = "rC";
+ TIFF *tiff;
+ uint16_t photometric = 0; // init to not PHOTOMETRIC_YCBCR
+ uint16_t compression;
+ int readAsRGBA = 0;
+ uint16_t planarconfig = 0;
+ int planes = 1;
+ ImagingShuffler unpackers[4];
+ INT32 img_width, img_height;
+
+ memset(unpackers, 0, sizeof(ImagingShuffler) * 4);
+
+ /* buffer is the encoded file, bytes is the length of the encoded file */
+ /* it all ends up in state->buffer, which is a uint8* from Imaging.h */
+
+ TRACE(("in decoder: bytes %d\n", bytes));
+ TRACE(
+ ("State: count %d, state %d, x %d, y %d, ystep %d\n",
+ state->count,
+ state->state,
+ state->x,
+ state->y,
+ state->ystep));
+ TRACE(
+ ("State: xsize %d, ysize %d, xoff %d, yoff %d \n",
+ state->xsize,
+ state->ysize,
+ state->xoff,
+ state->yoff));
+ TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
+ TRACE(
+ ("Buffer: %p: %c%c%c%c\n",
+ buffer,
+ (char)buffer[0],
+ (char)buffer[1],
+ (char)buffer[2],
+ (char)buffer[3]));
+ TRACE(
+ ("State->Buffer: %c%c%c%c\n",
+ (char)state->buffer[0],
+ (char)state->buffer[1],
+ (char)state->buffer[2],
+ (char)state->buffer[3]));
+ TRACE(
+ ("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n",
+ im->mode,
+ im->type,
+ im->bands,
+ im->xsize,
+ im->ysize));
+ TRACE(
+ ("Image: image8 %p, image32 %p, image %p, block %p \n",
+ im->image8,
+ im->image32,
+ im->image,
+ im->block));
+ TRACE(("Image: pixelsize: %d, linesize %d \n", im->pixelsize, im->linesize));
+
+ dump_state(clientstate);
+ clientstate->size = bytes;
+ clientstate->eof = clientstate->size;
+ clientstate->loc = 0;
+ clientstate->data = (tdata_t)buffer;
+ clientstate->flrealloc = 0;
+ dump_state(clientstate);
+
+ TIFFSetWarningHandler(NULL);
+ TIFFSetWarningHandlerExt(NULL);
+
+ if (clientstate->fp) {
+ TRACE(("Opening using fd: %d\n", clientstate->fp));
+ lseek(clientstate->fp, 0, SEEK_SET); // Sometimes, I get it set to the end.
+ tiff = TIFFFdOpen(fd_to_tiff_fd(clientstate->fp), filename, mode);
+ } else {
+ TRACE(("Opening from string\n"));
+ tiff = TIFFClientOpen(
+ filename,
+ mode,
+ (thandle_t)clientstate,
+ _tiffReadProc,
+ _tiffWriteProc,
+ _tiffSeekProc,
+ _tiffCloseProc,
+ _tiffSizeProc,
+ _tiffMapProc,
+ _tiffUnmapProc);
+ }
+
+ if (!tiff) {
+ TRACE(("Error, didn't get the tiff\n"));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ return -1;
+ }
+
+ if (clientstate->ifd) {
+ int rv;
+ uint32_t ifdoffset = clientstate->ifd;
+ TRACE(("reading tiff ifd %u\n", ifdoffset));
+ rv = TIFFSetSubDirectory(tiff, ifdoffset);
+ if (!rv) {
+ TRACE(("error in TIFFSetSubDirectory"));
+ goto decode_err;
+ }
+ }
+
+ TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &img_width);
+ TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &img_height);
+
+ if (state->xsize != img_width || state->ysize != img_height) {
+ TRACE(
+ ("Inconsistent Image Error: %d =? %d, %d =? %d",
+ state->xsize,
+ img_width,
+ state->ysize,
+ img_height));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ goto decode_err;
+ }
+
+
+ TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
+ TIFFGetField(tiff, TIFFTAG_COMPRESSION, &compression);
+ TIFFGetFieldDefaulted(tiff, TIFFTAG_PLANARCONFIG, &planarconfig);
+
+ // Dealing with YCbCr images is complicated in case if subsampling
+ // Let LibTiff read them as RGBA
+ readAsRGBA = photometric == PHOTOMETRIC_YCBCR;
+
+ if (readAsRGBA && compression == COMPRESSION_JPEG && planarconfig == PLANARCONFIG_CONTIG) {
+ // If using new JPEG compression, let libjpeg do RGB conversion for performance reasons
+ TIFFSetField(tiff, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ readAsRGBA = 0;
+ }
+
+ if (readAsRGBA) {
+ _decodeAsRGBA(im, state, tiff);
+ }
+ else {
+ planes = _pickUnpackers(im, state, tiff, planarconfig, unpackers);
+ if (planes <= 0) {
+ goto decode_err;
+ }
+
+ if (TIFFIsTiled(tiff)) {
+ _decodeTile(im, state, tiff, planes, unpackers);
+ }
+ else {
+ _decodeStrip(im, state, tiff, planes, unpackers);
+ }
+
+ if (!state->errcode) {
+ // Check if raw mode was RGBa and it was stored on separate planes
+ // so we have to convert it to RGBA
+ if (planes > 3 && strcmp(im->mode, "RGBA") == 0) {
+ uint16_t extrasamples;
+ uint16_t* sampleinfo;
+ ImagingShuffler shuffle;
+ INT32 y;
+
+ TIFFGetFieldDefaulted(tiff, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo);
+
+ if (extrasamples >= 1 &&
+ (sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED || sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA)
+ ) {
+ shuffle = ImagingFindUnpacker("RGBA", "RGBa", NULL);
+
+ for (y = state->yoff; y < state->ysize; y++) {
+ UINT8* ptr = (UINT8*) im->image[y + state->yoff] +
+ state->xoff * im->pixelsize;
+ shuffle(ptr, ptr, state->xsize);
+ }
+ }
+ }
+ }
+ }
+
+ decode_err:
+ // TIFFClose in libtiff calls tif_closeproc and TIFFCleanup
+ if (clientstate->fp) {
+ // Pillow will manage the closing of the file rather than libtiff
+ // So only call TIFFCleanup
+ TIFFCleanup(tiff);
+ } else {
+ // When tif_closeproc refers to our custom _tiffCloseProc though,
+ // that is fine, as it does not close the file
+ TIFFClose(tiff);
+ }
+ TRACE(("Done Decoding, Returning \n"));
+ // Returning -1 here to force ImageFile.load to break, rather than
+ // even think about looping back around.
+ return -1;
+}
+
+int
+ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp) {
+ // Open the FD or the pointer as a tiff file, for writing.
+ // We may have to do some monkeying around to make this really work.
+ // If we have a fp, then we're good.
+ // If we have a memory string, we're probably going to have to malloc, then
+ // shuffle bytes into the writescanline process.
+ // Going to have to deal with the directory as well.
+
+ TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
+ int bufsize = 64 * 1024;
+ char *mode = "w";
+
+ TRACE(("initing libtiff\n"));
+ TRACE(("Filename %s, filepointer: %d \n", filename, fp));
+ TRACE(
+ ("State: count %d, state %d, x %d, y %d, ystep %d\n",
+ state->count,
+ state->state,
+ state->x,
+ state->y,
+ state->ystep));
+ TRACE(
+ ("State: xsize %d, ysize %d, xoff %d, yoff %d \n",
+ state->xsize,
+ state->ysize,
+ state->xoff,
+ state->yoff));
+ TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
+ TRACE(("State: context %p \n", state->context));
+
+ clientstate->loc = 0;
+ clientstate->size = 0;
+ clientstate->eof = 0;
+ clientstate->data = 0;
+ clientstate->flrealloc = 0;
+ clientstate->fp = fp;
+
+ state->state = 0;
+
+ if (fp) {
+ TRACE(("Opening using fd: %d for writing \n", clientstate->fp));
+ clientstate->tiff = TIFFFdOpen(fd_to_tiff_fd(clientstate->fp), filename, mode);
+ } else {
+ // calloc a buffer to write the tif, we're going to need to realloc or something
+ // if we need bigger.
+ TRACE(("Opening a buffer for writing \n"));
+ /* calloc check ok, small constant allocation */
+ clientstate->data = calloc(bufsize, 1);
+ clientstate->size = bufsize;
+ clientstate->flrealloc = 1;
+
+ if (!clientstate->data) {
+ TRACE(("Error, couldn't allocate a buffer of size %d\n", bufsize));
+ return 0;
+ }
+
+ clientstate->tiff = TIFFClientOpen(
+ filename,
+ mode,
+ (thandle_t)clientstate,
+ _tiffReadProc,
+ _tiffWriteProc,
+ _tiffSeekProc,
+ _tiffCloseProc,
+ _tiffSizeProc,
+ _tiffNullMapProc,
+ _tiffUnmapProc); /*force no mmap*/
+ }
+
+ if (!clientstate->tiff) {
+ TRACE(("Error, couldn't open tiff file\n"));
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+ImagingLibTiffMergeFieldInfo(
+ ImagingCodecState state, TIFFDataType field_type, int key, int is_var_length) {
+ // Refer to libtiff docs (http://www.simplesystems.org/libtiff/addingtags.html)
+ TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
+ uint32_t n;
+ int status = 0;
+
+ // custom fields added with ImagingLibTiffMergeFieldInfo are only used for
+ // decoding, ignore readcount;
+ int readcount = is_var_length ? TIFF_VARIABLE : 1;
+ // we support writing a single value, or a variable number of values
+ int writecount = is_var_length ? TIFF_VARIABLE : 1;
+ // whether the first value should encode the number of values.
+ int passcount = (is_var_length && field_type != TIFF_ASCII) ? 1 : 0;
+
+ TIFFFieldInfo info[] = {
+ {key,
+ readcount,
+ writecount,
+ field_type,
+ FIELD_CUSTOM,
+ 1,
+ passcount,
+ "CustomField"}};
+
+ n = sizeof(info) / sizeof(info[0]);
+
+ // Test for libtiff 4.0 or later, excluding libtiff 3.9.6 and 3.9.7
+#if TIFFLIB_VERSION >= 20111221 && TIFFLIB_VERSION != 20120218 && \
+ TIFFLIB_VERSION != 20120922
+ status = TIFFMergeFieldInfo(clientstate->tiff, info, n);
+#else
+ TIFFMergeFieldInfo(clientstate->tiff, info, n);
+#endif
+ return status;
+}
+
+int
+ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...) {
+ // after tif_dir.c->TIFFSetField.
+ TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
+ va_list ap;
+ int status;
+
+ va_start(ap, tag);
+ status = TIFFVSetField(clientstate->tiff, tag, ap);
+ va_end(ap);
+ return status;
+}
+
+int
+ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes) {
+ /* One shot encoder. Encode everything to the tiff in the clientstate.
+ If we're running off of a FD, then run once, we're good, everything
+ ends up in the file, we close and we're done.
+
+ If we're going to memory, then we need to write the whole file into memory, then
+ parcel it back out to the pystring buffer bytes at a time.
+
+ */
+
+ TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
+ TIFF *tiff = clientstate->tiff;
+
+ TRACE(("in encoder: bytes %d\n", bytes));
+ TRACE(
+ ("State: count %d, state %d, x %d, y %d, ystep %d\n",
+ state->count,
+ state->state,
+ state->x,
+ state->y,
+ state->ystep));
+ TRACE(
+ ("State: xsize %d, ysize %d, xoff %d, yoff %d \n",
+ state->xsize,
+ state->ysize,
+ state->xoff,
+ state->yoff));
+ TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
+ TRACE(
+ ("Buffer: %p: %c%c%c%c\n",
+ buffer,
+ (char)buffer[0],
+ (char)buffer[1],
+ (char)buffer[2],
+ (char)buffer[3]));
+ TRACE(
+ ("State->Buffer: %c%c%c%c\n",
+ (char)state->buffer[0],
+ (char)state->buffer[1],
+ (char)state->buffer[2],
+ (char)state->buffer[3]));
+ TRACE(
+ ("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n",
+ im->mode,
+ im->type,
+ im->bands,
+ im->xsize,
+ im->ysize));
+ TRACE(
+ ("Image: image8 %p, image32 %p, image %p, block %p \n",
+ im->image8,
+ im->image32,
+ im->image,
+ im->block));
+ TRACE(("Image: pixelsize: %d, linesize %d \n", im->pixelsize, im->linesize));
+
+ dump_state(clientstate);
+
+ if (state->state == 0) {
+ TRACE(("Encoding line by line"));
+ while (state->y < state->ysize) {
+ state->shuffle(
+ state->buffer,
+ (UINT8 *)im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->xsize);
+
+ if (TIFFWriteScanline(
+ tiff, (tdata_t)(state->buffer), (uint32_t)state->y, 0) == -1) {
+ TRACE(("Encode Error, row %d\n", state->y));
+ state->errcode = IMAGING_CODEC_BROKEN;
+ TIFFClose(tiff);
+ if (!clientstate->fp) {
+ free(clientstate->data);
+ }
+ return -1;
+ }
+ state->y++;
+ }
+
+ if (state->y == state->ysize) {
+ state->state = 1;
+
+ TRACE(("Flushing \n"));
+ if (!TIFFFlush(tiff)) {
+ TRACE(("Error flushing the tiff"));
+ // likely reason is memory.
+ state->errcode = IMAGING_CODEC_MEMORY;
+ TIFFClose(tiff);
+ if (!clientstate->fp) {
+ free(clientstate->data);
+ }
+ return -1;
+ }
+ TRACE(("Closing \n"));
+ TIFFClose(tiff);
+ // reset the clientstate metadata to use it to read out the buffer.
+ clientstate->loc = 0;
+ clientstate->size = clientstate->eof; // redundant?
+ }
+ }
+
+ if (state->state == 1 && !clientstate->fp) {
+ int read = (int)_tiffReadProc(clientstate, (tdata_t)buffer, (tsize_t)bytes);
+ TRACE(
+ ("Buffer: %p: %c%c%c%c\n",
+ buffer,
+ (char)buffer[0],
+ (char)buffer[1],
+ (char)buffer[2],
+ (char)buffer[3]));
+ if (clientstate->loc == clientstate->eof) {
+ TRACE(("Hit EOF, calling an end, freeing data"));
+ state->errcode = IMAGING_CODEC_END;
+ free(clientstate->data);
+ }
+ return read;
+ }
+
+ state->errcode = IMAGING_CODEC_END;
+ return 0;
+}
+
+const char *
+ImagingTiffVersion(void) {
+ return TIFFGetVersion();
+}
+
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/TiffDecode.h b/contrib/python/Pillow/py3/libImaging/TiffDecode.h
new file mode 100644
index 00000000000..c7c7d48ed02
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/TiffDecode.h
@@ -0,0 +1,66 @@
+/*
+ * The Python Imaging Library.
+ * $Id: //modules/pil/libImaging/Tiff.h#1 $
+ *
+ * declarations for the LibTiff-based Group3 and Group4 decoder
+ *
+ */
+
+#ifndef _TIFFIO_
+#include <tiffio.h>
+#endif
+#ifndef _TIFF_
+#include <tiff.h>
+#endif
+
+/* UNDONE -- what are we using from this? */
+/*#ifndef _UNISTD_H
+ # include <unistd.h>
+ # endif
+*/
+
+#ifndef min
+#define min(x, y) ((x > y) ? y : x)
+#define max(x, y) ((x < y) ? y : x)
+#endif
+
+#ifndef _PIL_LIBTIFF_
+#define _PIL_LIBTIFF_
+
+typedef struct {
+ tdata_t data; /* tdata_t == void* */
+ toff_t loc; /* toff_t == uint32 */
+ tsize_t size; /* tsize_t == int32 */
+ int fp;
+ uint32_t ifd; /* offset of the ifd, used for multipage
+ * Should be uint32 for libtiff 3.9.x
+ * uint64 for libtiff 4.0.x
+ */
+ TIFF *tiff; /* Used in write */
+ toff_t eof;
+ int flrealloc; /* may we realloc */
+} TIFFSTATE;
+
+extern int
+ImagingLibTiffInit(ImagingCodecState state, int fp, uint32_t offset);
+extern int
+ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp);
+extern int
+ImagingLibTiffMergeFieldInfo(
+ ImagingCodecState state, TIFFDataType field_type, int key, int is_var_length);
+extern int
+ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...);
+
+/*
+ Trace debugging
+ legacy, don't enable for Python 3.x, unicode issues.
+*/
+
+/*
+#define VA_ARGS(...) __VA_ARGS__
+#define TRACE(args) fprintf(stderr, VA_ARGS args)
+*/
+
+#define TRACE(args)
+
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/Unpack.c b/contrib/python/Pillow/py3/libImaging/Unpack.c
new file mode 100644
index 00000000000..279bdcdc8ad
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Unpack.c
@@ -0,0 +1,1821 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * code to unpack raw data from various file formats
+ *
+ * history:
+ * 1996-03-07 fl Created (from various decoders)
+ * 1996-04-19 fl Added band unpackers
+ * 1996-05-12 fl Published RGB unpackers
+ * 1996-05-27 fl Added nibble unpacker
+ * 1996-12-10 fl Added complete set of PNG unpackers
+ * 1996-12-29 fl Set alpha byte in RGB unpackers
+ * 1997-01-05 fl Added remaining TGA unpackers
+ * 1997-01-18 fl Added inverting band unpackers
+ * 1997-01-25 fl Added FlashPix unpackers
+ * 1997-05-31 fl Added floating point unpackers
+ * 1998-02-08 fl Added I unpacker
+ * 1998-07-01 fl Added YCbCr unpacker
+ * 1998-07-02 fl Added full set of integer unpackers
+ * 1998-12-29 fl Added mode field, I;16 unpackers
+ * 1998-12-30 fl Added RGBX modes
+ * 1999-02-04 fl Fixed I;16 unpackers
+ * 2003-05-13 fl Added L/RGB reversed unpackers
+ * 2003-09-26 fl Added LA/PA and RGBa->RGB unpackers
+ *
+ * Copyright (c) 1997-2003 by Secret Labs AB.
+ * Copyright (c) 1996-1997 by Fredrik Lundh.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+#include "Convert.h"
+
+#define R 0
+#define G 1
+#define B 2
+#define X 3
+
+#define A 3
+
+#define C 0
+#define M 1
+#define Y 2
+#define K 3
+
+/* byte-swapping macros */
+
+#define C16N (tmp[0] = in[0], tmp[1] = in[1]);
+#define C16S (tmp[1] = in[0], tmp[0] = in[1]);
+#define C32N (tmp[0] = in[0], tmp[1] = in[1], tmp[2] = in[2], tmp[3] = in[3]);
+#define C32S (tmp[3] = in[0], tmp[2] = in[1], tmp[1] = in[2], tmp[0] = in[3]);
+#define C64N \
+ (tmp[0] = in[0], \
+ tmp[1] = in[1], \
+ tmp[2] = in[2], \
+ tmp[3] = in[3], \
+ tmp[4] = in[4], \
+ tmp[5] = in[5], \
+ tmp[6] = in[6], \
+ tmp[7] = in[7]);
+#define C64S \
+ (tmp[7] = in[0], \
+ tmp[6] = in[1], \
+ tmp[5] = in[2], \
+ tmp[4] = in[3], \
+ tmp[3] = in[4], \
+ tmp[2] = in[5], \
+ tmp[1] = in[6], \
+ tmp[0] = in[7]);
+
+#ifdef WORDS_BIGENDIAN
+#define C16B C16N
+#define C16L C16S
+#define C32B C32N
+#define C32L C32S
+#define C64B C64N
+#define C64L C64S
+#else
+#define C16B C16S
+#define C16L C16N
+#define C32B C32S
+#define C32L C32N
+#define C64B C64S
+#define C64L C64N
+#endif
+
+/* bit-swapping */
+
+static UINT8 BITFLIP[] = {
+ 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
+ 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
+ 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
+ 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
+ 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
+ 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
+ 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
+ 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
+ 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
+ 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
+ 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
+ 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
+ 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
+ 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
+ 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
+ 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255};
+
+/* Unpack to "1" image */
+
+static void
+unpack1(UINT8 *out, const UINT8 *in, int pixels) {
+ /* bits (msb first, white is non-zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default:
+ *out++ = (byte & 128) ? 255 : 0;
+ byte <<= 1;
+ case 7:
+ *out++ = (byte & 128) ? 255 : 0;
+ byte <<= 1;
+ case 6:
+ *out++ = (byte & 128) ? 255 : 0;
+ byte <<= 1;
+ case 5:
+ *out++ = (byte & 128) ? 255 : 0;
+ byte <<= 1;
+ case 4:
+ *out++ = (byte & 128) ? 255 : 0;
+ byte <<= 1;
+ case 3:
+ *out++ = (byte & 128) ? 255 : 0;
+ byte <<= 1;
+ case 2:
+ *out++ = (byte & 128) ? 255 : 0;
+ byte <<= 1;
+ case 1:
+ *out++ = (byte & 128) ? 255 : 0;
+ }
+ pixels -= 8;
+ }
+}
+
+static void
+unpack1I(UINT8 *out, const UINT8 *in, int pixels) {
+ /* bits (msb first, white is zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default:
+ *out++ = (byte & 128) ? 0 : 255;
+ byte <<= 1;
+ case 7:
+ *out++ = (byte & 128) ? 0 : 255;
+ byte <<= 1;
+ case 6:
+ *out++ = (byte & 128) ? 0 : 255;
+ byte <<= 1;
+ case 5:
+ *out++ = (byte & 128) ? 0 : 255;
+ byte <<= 1;
+ case 4:
+ *out++ = (byte & 128) ? 0 : 255;
+ byte <<= 1;
+ case 3:
+ *out++ = (byte & 128) ? 0 : 255;
+ byte <<= 1;
+ case 2:
+ *out++ = (byte & 128) ? 0 : 255;
+ byte <<= 1;
+ case 1:
+ *out++ = (byte & 128) ? 0 : 255;
+ }
+ pixels -= 8;
+ }
+}
+
+static void
+unpack1R(UINT8 *out, const UINT8 *in, int pixels) {
+ /* bits (lsb first, white is non-zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default:
+ *out++ = (byte & 1) ? 255 : 0;
+ byte >>= 1;
+ case 7:
+ *out++ = (byte & 1) ? 255 : 0;
+ byte >>= 1;
+ case 6:
+ *out++ = (byte & 1) ? 255 : 0;
+ byte >>= 1;
+ case 5:
+ *out++ = (byte & 1) ? 255 : 0;
+ byte >>= 1;
+ case 4:
+ *out++ = (byte & 1) ? 255 : 0;
+ byte >>= 1;
+ case 3:
+ *out++ = (byte & 1) ? 255 : 0;
+ byte >>= 1;
+ case 2:
+ *out++ = (byte & 1) ? 255 : 0;
+ byte >>= 1;
+ case 1:
+ *out++ = (byte & 1) ? 255 : 0;
+ }
+ pixels -= 8;
+ }
+}
+
+static void
+unpack1IR(UINT8 *out, const UINT8 *in, int pixels) {
+ /* bits (lsb first, white is zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default:
+ *out++ = (byte & 1) ? 0 : 255;
+ byte >>= 1;
+ case 7:
+ *out++ = (byte & 1) ? 0 : 255;
+ byte >>= 1;
+ case 6:
+ *out++ = (byte & 1) ? 0 : 255;
+ byte >>= 1;
+ case 5:
+ *out++ = (byte & 1) ? 0 : 255;
+ byte >>= 1;
+ case 4:
+ *out++ = (byte & 1) ? 0 : 255;
+ byte >>= 1;
+ case 3:
+ *out++ = (byte & 1) ? 0 : 255;
+ byte >>= 1;
+ case 2:
+ *out++ = (byte & 1) ? 0 : 255;
+ byte >>= 1;
+ case 1:
+ *out++ = (byte & 1) ? 0 : 255;
+ }
+ pixels -= 8;
+ }
+}
+
+static void
+unpack18(UINT8 *out, const UINT8 *in, int pixels) {
+ /* Unpack a '|b1' image, which is a numpy boolean.
+ 1 == true, 0==false, in bytes */
+
+ int i;
+ for (i = 0; i < pixels; i++) {
+ out[i] = in[i] > 0 ? 255 : 0;
+ }
+}
+
+/* Unpack to "L" image */
+
+static void
+unpackL2(UINT8 *out, const UINT8 *in, int pixels) {
+ /* nibbles (msb first, white is non-zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default:
+ *out++ = ((byte >> 6) & 0x03U) * 0x55U;
+ byte <<= 2;
+ case 3:
+ *out++ = ((byte >> 6) & 0x03U) * 0x55U;
+ byte <<= 2;
+ case 2:
+ *out++ = ((byte >> 6) & 0x03U) * 0x55U;
+ byte <<= 2;
+ case 1:
+ *out++ = ((byte >> 6) & 0x03U) * 0x55U;
+ }
+ pixels -= 4;
+ }
+}
+
+static void
+unpackL2I(UINT8 *out, const UINT8 *in, int pixels) {
+ /* nibbles (msb first, white is zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default:
+ *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U);
+ byte <<= 2;
+ case 3:
+ *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U);
+ byte <<= 2;
+ case 2:
+ *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U);
+ byte <<= 2;
+ case 1:
+ *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U);
+ }
+ pixels -= 4;
+ }
+}
+
+static void
+unpackL2R(UINT8 *out, const UINT8 *in, int pixels) {
+ /* nibbles (bit order reversed, white is non-zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ byte = BITFLIP[byte];
+ switch (pixels) {
+ default:
+ *out++ = ((byte >> 6) & 0x03U) * 0x55U;
+ byte <<= 2;
+ case 3:
+ *out++ = ((byte >> 6) & 0x03U) * 0x55U;
+ byte <<= 2;
+ case 2:
+ *out++ = ((byte >> 6) & 0x03U) * 0x55U;
+ byte <<= 2;
+ case 1:
+ *out++ = ((byte >> 6) & 0x03U) * 0x55U;
+ }
+ pixels -= 4;
+ }
+}
+
+static void
+unpackL2IR(UINT8 *out, const UINT8 *in, int pixels) {
+ /* nibbles (bit order reversed, white is zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ byte = BITFLIP[byte];
+ switch (pixels) {
+ default:
+ *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U);
+ byte <<= 2;
+ case 3:
+ *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U);
+ byte <<= 2;
+ case 2:
+ *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U);
+ byte <<= 2;
+ case 1:
+ *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U);
+ }
+ pixels -= 4;
+ }
+}
+
+static void
+unpackL4(UINT8 *out, const UINT8 *in, int pixels) {
+ /* nibbles (msb first, white is non-zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default:
+ *out++ = ((byte >> 4) & 0x0FU) * 0x11U;
+ byte <<= 4;
+ case 1:
+ *out++ = ((byte >> 4) & 0x0FU) * 0x11U;
+ }
+ pixels -= 2;
+ }
+}
+
+static void
+unpackL4I(UINT8 *out, const UINT8 *in, int pixels) {
+ /* nibbles (msb first, white is zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default:
+ *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U);
+ byte <<= 4;
+ case 1:
+ *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U);
+ }
+ pixels -= 2;
+ }
+}
+
+static void
+unpackL4R(UINT8 *out, const UINT8 *in, int pixels) {
+ /* nibbles (bit order reversed, white is non-zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ byte = BITFLIP[byte];
+ switch (pixels) {
+ default:
+ *out++ = ((byte >> 4) & 0x0FU) * 0x11U;
+ byte <<= 4;
+ case 1:
+ *out++ = ((byte >> 4) & 0x0FU) * 0x11U;
+ }
+ pixels -= 2;
+ }
+}
+
+static void
+unpackL4IR(UINT8 *out, const UINT8 *in, int pixels) {
+ /* nibbles (bit order reversed, white is zero) */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ byte = BITFLIP[byte];
+ switch (pixels) {
+ default:
+ *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U);
+ byte <<= 4;
+ case 1:
+ *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U);
+ }
+ pixels -= 2;
+ }
+}
+
+static void
+unpackLA(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* LA, pixel interleaved */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[0], in[0], in[0], in[1]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 2;
+ _out += 4;
+ }
+}
+
+static void
+unpackLAL(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* LA, line interleaved */
+ for (i = 0; i < pixels; i++, _out += 4) {
+ UINT32 iv = MAKE_UINT32(in[i], in[i], in[i], in[i + pixels]);
+ memcpy(_out, &iv, sizeof(iv));
+ }
+}
+
+static void
+unpackLI(UINT8 *out, const UINT8 *in, int pixels) {
+ /* negative */
+ int i;
+ for (i = 0; i < pixels; i++) {
+ out[i] = ~in[i];
+ }
+}
+
+static void
+unpackLR(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGB, bit reversed */
+ for (i = 0; i < pixels; i++) {
+ out[i] = BITFLIP[in[i]];
+ }
+}
+
+static void
+unpackL16(UINT8 *out, const UINT8 *in, int pixels) {
+ /* int16 (upper byte, little endian) */
+ int i;
+ for (i = 0; i < pixels; i++) {
+ out[i] = in[1];
+ in += 2;
+ }
+}
+
+static void
+unpackL16B(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* int16 (upper byte, big endian) */
+ for (i = 0; i < pixels; i++) {
+ out[i] = in[0];
+ in += 2;
+ }
+}
+
+/* Unpack to "P" image */
+
+static void
+unpackP1(UINT8 *out, const UINT8 *in, int pixels) {
+ /* bits */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default:
+ *out++ = (byte >> 7) & 1;
+ byte <<= 1;
+ case 7:
+ *out++ = (byte >> 7) & 1;
+ byte <<= 1;
+ case 6:
+ *out++ = (byte >> 7) & 1;
+ byte <<= 1;
+ case 5:
+ *out++ = (byte >> 7) & 1;
+ byte <<= 1;
+ case 4:
+ *out++ = (byte >> 7) & 1;
+ byte <<= 1;
+ case 3:
+ *out++ = (byte >> 7) & 1;
+ byte <<= 1;
+ case 2:
+ *out++ = (byte >> 7) & 1;
+ byte <<= 1;
+ case 1:
+ *out++ = (byte >> 7) & 1;
+ }
+ pixels -= 8;
+ }
+}
+
+static void
+unpackP2(UINT8 *out, const UINT8 *in, int pixels) {
+ /* bit pairs */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default:
+ *out++ = (byte >> 6) & 3;
+ byte <<= 2;
+ case 3:
+ *out++ = (byte >> 6) & 3;
+ byte <<= 2;
+ case 2:
+ *out++ = (byte >> 6) & 3;
+ byte <<= 2;
+ case 1:
+ *out++ = (byte >> 6) & 3;
+ }
+ pixels -= 4;
+ }
+}
+
+static void
+unpackP4(UINT8 *out, const UINT8 *in, int pixels) {
+ /* nibbles */
+ while (pixels > 0) {
+ UINT8 byte = *in++;
+ switch (pixels) {
+ default:
+ *out++ = (byte >> 4) & 15;
+ byte <<= 4;
+ case 1:
+ *out++ = (byte >> 4) & 15;
+ }
+ pixels -= 2;
+ }
+}
+
+static void
+unpackP2L(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, j, m, s;
+ /* bit layers */
+ m = 128;
+ s = (pixels + 7) / 8;
+ for (i = j = 0; i < pixels; i++) {
+ out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0);
+ if ((m >>= 1) == 0) {
+ m = 128;
+ j++;
+ }
+ }
+}
+
+static void
+unpackP4L(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, j, m, s;
+ /* bit layers (trust the optimizer ;-) */
+ m = 128;
+ s = (pixels + 7) / 8;
+ for (i = j = 0; i < pixels; i++) {
+ out[i] = ((in[j] & m) ? 1 : 0) + ((in[j + s] & m) ? 2 : 0) +
+ ((in[j + 2 * s] & m) ? 4 : 0) + ((in[j + 3 * s] & m) ? 8 : 0);
+ if ((m >>= 1) == 0) {
+ m = 128;
+ j++;
+ }
+ }
+}
+
+/* Unpack to "RGB" image */
+
+void
+ImagingUnpackRGB(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i = 0;
+ /* RGB triplets */
+ for (; i < pixels - 1; i++) {
+ UINT32 iv;
+ memcpy(&iv, in, sizeof(iv));
+ iv |= MASK_UINT32_CHANNEL_3;
+ memcpy(_out, &iv, sizeof(iv));
+ in += 3;
+ _out += 4;
+ }
+ for (; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[0], in[1], in[2], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 3;
+ _out += 4;
+ }
+}
+
+void
+unpackRGB16L(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* 16-bit RGB triplets, little-endian order */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[1], in[3], in[5], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 6;
+ _out += 4;
+ }
+}
+
+void
+unpackRGB16B(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* 16-bit RGB triplets, big-endian order */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[0], in[2], in[4], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 6;
+ _out += 4;
+ }
+}
+
+static void
+unpackRGBL(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGB, line interleaved */
+ for (i = 0; i < pixels; i++, _out += 4) {
+ UINT32 iv = MAKE_UINT32(in[i], in[i + pixels], in[i + pixels + pixels], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ }
+}
+
+static void
+unpackRGBR(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGB, bit reversed */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(BITFLIP[in[0]], BITFLIP[in[1]], BITFLIP[in[2]], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 3;
+ _out += 4;
+ }
+}
+
+void
+ImagingUnpackBGR(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGB, reversed bytes */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[2], in[1], in[0], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 3;
+ _out += 4;
+ }
+}
+
+void
+ImagingUnpackRGB15(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, pixel;
+ /* RGB, 5 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[R] = (pixel & 31) * 255 / 31;
+ out[G] = ((pixel >> 5) & 31) * 255 / 31;
+ out[B] = ((pixel >> 10) & 31) * 255 / 31;
+ out[A] = 255;
+ out += 4;
+ in += 2;
+ }
+}
+
+void
+ImagingUnpackRGBA15(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, pixel;
+ /* RGB, 5/5/5/1 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[R] = (pixel & 31) * 255 / 31;
+ out[G] = ((pixel >> 5) & 31) * 255 / 31;
+ out[B] = ((pixel >> 10) & 31) * 255 / 31;
+ out[A] = (pixel >> 15) * 255;
+ out += 4;
+ in += 2;
+ }
+}
+
+void
+ImagingUnpackBGR15(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, pixel;
+ /* RGB, reversed bytes, 5 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[B] = (pixel & 31) * 255 / 31;
+ out[G] = ((pixel >> 5) & 31) * 255 / 31;
+ out[R] = ((pixel >> 10) & 31) * 255 / 31;
+ out[A] = 255;
+ out += 4;
+ in += 2;
+ }
+}
+
+void
+ImagingUnpackBGRA15(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, pixel;
+ /* RGB, rearranged channels, 5/5/5/1 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[B] = (pixel & 31) * 255 / 31;
+ out[G] = ((pixel >> 5) & 31) * 255 / 31;
+ out[R] = ((pixel >> 10) & 31) * 255 / 31;
+ out[A] = (pixel >> 15) * 255;
+ out += 4;
+ in += 2;
+ }
+}
+
+void
+ImagingUnpackRGB16(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, pixel;
+ /* RGB, 5/6/5 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[R] = (pixel & 31) * 255 / 31;
+ out[G] = ((pixel >> 5) & 63) * 255 / 63;
+ out[B] = ((pixel >> 11) & 31) * 255 / 31;
+ out[A] = 255;
+ out += 4;
+ in += 2;
+ }
+}
+
+void
+ImagingUnpackBGR16(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, pixel;
+ /* RGB, reversed bytes, 5/6/5 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[B] = (pixel & 31) * 255 / 31;
+ out[G] = ((pixel >> 5) & 63) * 255 / 63;
+ out[R] = ((pixel >> 11) & 31) * 255 / 31;
+ out[A] = 255;
+ out += 4;
+ in += 2;
+ }
+}
+
+void
+ImagingUnpackRGB4B(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, pixel;
+ /* RGB, 4 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[R] = (pixel & 15) * 17;
+ out[G] = ((pixel >> 4) & 15) * 17;
+ out[B] = ((pixel >> 8) & 15) * 17;
+ out[A] = 255;
+ out += 4;
+ in += 2;
+ }
+}
+
+void
+ImagingUnpackRGBA4B(UINT8 *out, const UINT8 *in, int pixels) {
+ int i, pixel;
+ /* RGBA, 4 bits per pixel */
+ for (i = 0; i < pixels; i++) {
+ pixel = in[0] + (in[1] << 8);
+ out[R] = (pixel & 15) * 17;
+ out[G] = ((pixel >> 4) & 15) * 17;
+ out[B] = ((pixel >> 8) & 15) * 17;
+ out[A] = ((pixel >> 12) & 15) * 17;
+ out += 4;
+ in += 2;
+ }
+}
+
+static void
+ImagingUnpackBGRX(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGB, reversed bytes with padding */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[2], in[1], in[0], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4;
+ _out += 4;
+ }
+}
+
+static void
+ImagingUnpackXRGB(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGB, leading pad */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[1], in[2], in[3], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4;
+ _out += 4;
+ }
+}
+
+static void
+ImagingUnpackXBGR(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGB, reversed bytes, leading pad */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[3], in[2], in[1], 255);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4;
+ _out += 4;
+ }
+}
+
+/* Unpack to "RGBA" image */
+
+static void
+unpackRGBALA(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* greyscale with alpha */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[0], in[0], in[0], in[1]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 2;
+ _out += 4;
+ }
+}
+
+static void
+unpackRGBALA16B(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* 16-bit greyscale with alpha, big-endian */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[0], in[0], in[0], in[2]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4;
+ _out += 4;
+ }
+}
+
+static void
+unpackRGBa16L(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* premultiplied 16-bit RGBA, little-endian */
+ for (i = 0; i < pixels; i++) {
+ int a = in[7];
+ UINT32 iv;
+ if (!a) {
+ iv = 0;
+ } else if (a == 255) {
+ iv = MAKE_UINT32(in[1], in[3], in[5], a);
+ } else {
+ iv = MAKE_UINT32(
+ CLIP8(in[1] * 255 / a),
+ CLIP8(in[3] * 255 / a),
+ CLIP8(in[5] * 255 / a),
+ a);
+ }
+ memcpy(_out, &iv, sizeof(iv));
+ in += 8;
+ _out += 4;
+ }
+}
+
+static void
+unpackRGBa16B(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* premultiplied 16-bit RGBA, big-endian */
+ for (i = 0; i < pixels; i++) {
+ int a = in[6];
+ UINT32 iv;
+ if (!a) {
+ iv = 0;
+ } else if (a == 255) {
+ iv = MAKE_UINT32(in[0], in[2], in[4], a);
+ } else {
+ iv = MAKE_UINT32(
+ CLIP8(in[0] * 255 / a),
+ CLIP8(in[2] * 255 / a),
+ CLIP8(in[4] * 255 / a),
+ a);
+ }
+ memcpy(_out, &iv, sizeof(iv));
+ in += 8;
+ _out += 4;
+ }
+}
+
+static void
+unpackRGBa(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* premultiplied RGBA */
+ for (i = 0; i < pixels; i++) {
+ int a = in[3];
+ UINT32 iv;
+ if (!a) {
+ iv = 0;
+ } else if (a == 255) {
+ iv = MAKE_UINT32(in[0], in[1], in[2], a);
+ } else {
+ iv = MAKE_UINT32(
+ CLIP8(in[0] * 255 / a),
+ CLIP8(in[1] * 255 / a),
+ CLIP8(in[2] * 255 / a),
+ a);
+ }
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4;
+ _out += 4;
+ }
+}
+
+static void
+unpackRGBaskip1(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ UINT32 *out = (UINT32 *)_out;
+ /* premultiplied RGBA */
+ for (i = 0; i < pixels; i++) {
+ int a = in[3];
+ if (!a) {
+ out[i] = 0;
+ } else if (a == 255) {
+ out[i] = MAKE_UINT32(in[0], in[1], in[2], a);
+ } else {
+ out[i] = MAKE_UINT32(
+ CLIP8(in[0] * 255 / a),
+ CLIP8(in[1] * 255 / a),
+ CLIP8(in[2] * 255 / a),
+ a);
+ }
+ in += 5;
+ }
+}
+
+static void
+unpackRGBaskip2(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ UINT32 *out = (UINT32 *)_out;
+ /* premultiplied RGBA */
+ for (i = 0; i < pixels; i++) {
+ int a = in[3];
+ if (!a) {
+ out[i] = 0;
+ } else if (a == 255) {
+ out[i] = MAKE_UINT32(in[0], in[1], in[2], a);
+ } else {
+ out[i] = MAKE_UINT32(
+ CLIP8(in[0] * 255 / a),
+ CLIP8(in[1] * 255 / a),
+ CLIP8(in[2] * 255 / a),
+ a);
+ }
+ in += 6;
+ }
+}
+
+static void
+unpackBGRa(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* premultiplied BGRA */
+ for (i = 0; i < pixels; i++) {
+ int a = in[3];
+ UINT32 iv;
+ if (!a) {
+ iv = 0;
+ } else if (a == 255) {
+ iv = MAKE_UINT32(in[2], in[1], in[0], a);
+ } else {
+ iv = MAKE_UINT32(
+ CLIP8(in[2] * 255 / a),
+ CLIP8(in[1] * 255 / a),
+ CLIP8(in[0] * 255 / a),
+ a);
+ }
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4;
+ _out += 4;
+ }
+}
+
+static void
+unpackRGBAI(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGBA, inverted RGB bytes (FlashPix) */
+ for (i = 0; i < pixels; i++) {
+ out[R] = ~in[0];
+ out[G] = ~in[1];
+ out[B] = ~in[2];
+ out[A] = in[3];
+ out += 4;
+ in += 4;
+ }
+}
+
+static void
+unpackRGBAL(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGBA, line interleaved */
+ for (i = 0; i < pixels; i++, _out += 4) {
+ UINT32 iv = MAKE_UINT32(
+ in[i],
+ in[i + pixels],
+ in[i + pixels + pixels],
+ in[i + pixels + pixels + pixels]);
+ memcpy(_out, &iv, sizeof(iv));
+ }
+}
+
+void
+unpackRGBA16L(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* 16-bit RGBA, little-endian order */
+ for (i = 0; i < pixels; i++, _out += 4) {
+ UINT32 iv = MAKE_UINT32(in[1], in[3], in[5], in[7]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 8;
+ }
+}
+
+void
+unpackRGBA16B(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* 16-bit RGBA, big-endian order */
+ for (i = 0; i < pixels; i++, _out += 4) {
+ UINT32 iv = MAKE_UINT32(in[0], in[2], in[4], in[6]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 8;
+ }
+}
+
+static void
+unpackARGB(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGBA, leading pad */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[1], in[2], in[3], in[0]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4;
+ _out += 4;
+ }
+}
+
+static void
+unpackABGR(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGBA, reversed bytes */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[3], in[2], in[1], in[0]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4;
+ _out += 4;
+ }
+}
+
+static void
+unpackBGRA(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* RGBA, rearranged channels */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[2], in[1], in[0], in[3]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4;
+ _out += 4;
+ }
+}
+
+static void
+unpackBGRA16L(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* 16-bit RGBA, little-endian order, rearranged channels */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[5], in[3], in[1], in[7]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 8;
+ _out += 4;
+ }
+}
+
+static void
+unpackBGRA16B(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* 16-bit RGBA, big-endian order, rearranged channels */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = MAKE_UINT32(in[4], in[2], in[0], in[6]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 8;
+ _out += 4;
+ }
+}
+
+/* Unpack to "CMYK" image */
+
+static void
+unpackCMYKI(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ /* CMYK, inverted bytes (Photoshop 2.5) */
+ for (i = 0; i < pixels; i++) {
+ UINT32 iv = ~MAKE_UINT32(in[0], in[1], in[2], in[3]);
+ memcpy(_out, &iv, sizeof(iv));
+ in += 4;
+ _out += 4;
+ }
+}
+
+/* Unpack to "LAB" image */
+/* There are two representations of LAB images for whatever precision:
+ L: Uint (in PS, it's 0-100)
+ A: Int (in ps, -128 .. 128, or elsewhere 0..255, with 128 as middle.
+ Channels in PS display a 0 value as middle grey,
+ LCMS appears to use 128 as the 0 value for these channels)
+ B: Int (as above)
+
+ Since we don't have any signed ints, we're going with the shifted versions
+ internally, and we'll unshift for saving and whatnot.
+*/
+void
+ImagingUnpackLAB(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* LAB triplets */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[0];
+ out[1] = in[1] ^ 128; /* signed in outside world */
+ out[2] = in[2] ^ 128;
+ out[3] = 255;
+ out += 4;
+ in += 3;
+ }
+}
+
+static void
+unpackI16N_I16B(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ UINT8 *tmp = (UINT8 *)out;
+ for (i = 0; i < pixels; i++) {
+ C16B;
+ in += 2;
+ tmp += 2;
+ }
+}
+static void
+unpackI16N_I16(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ UINT8 *tmp = (UINT8 *)out;
+ for (i = 0; i < pixels; i++) {
+ C16L;
+ in += 2;
+ tmp += 2;
+ }
+}
+static void
+unpackI16B_I16(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[1];
+ out[1] = in[0];
+ in += 2;
+ out += 2;
+ }
+}
+static void
+unpackI16R_I16(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ for (i = 0; i < pixels; i++) {
+ out[0] = BITFLIP[in[0]];
+ out[1] = BITFLIP[in[1]];
+ in += 2;
+ out += 2;
+ }
+}
+
+static void
+unpackI12_I16(UINT8 *out, const UINT8 *in, int pixels) {
+ /* Fillorder 1/MSB -> LittleEndian, for 12bit integer greyscale tiffs.
+
+ According to the TIFF spec:
+
+ FillOrder = 2 should be used only when BitsPerSample = 1 and
+ the data is either uncompressed or compressed using CCITT 1D
+ or 2D compression, to avoid potentially ambiguous situations.
+
+ Yeah. I thought so. We'll see how well people read the spec.
+ We've got several fillorder=2 modes in TiffImagePlugin.py
+
+ There's no spec I can find. It appears that the in storage
+ layout is: 00 80 00 ... -> (128 , 0 ...). The samples are
+ stored in a single big bitian 12bit block, but need to be
+ pulled out to little endian format to be stored in a 2 byte
+ int.
+ */
+
+ int i;
+ UINT16 pixel;
+#ifdef WORDS_BIGENDIAN
+ UINT8 *tmp = (UINT8 *)&pixel;
+#endif
+ for (i = 0; i < pixels - 1; i += 2) {
+ pixel = (((UINT16)in[0]) << 4) + (in[1] >> 4);
+#ifdef WORDS_BIGENDIAN
+ out[0] = tmp[1];
+ out[1] = tmp[0];
+#else
+ memcpy(out, &pixel, sizeof(pixel));
+#endif
+
+ out += 2;
+ pixel = (((UINT16)(in[1] & 0x0F)) << 8) + in[2];
+#ifdef WORDS_BIGENDIAN
+ out[0] = tmp[1];
+ out[1] = tmp[0];
+#else
+ memcpy(out, &pixel, sizeof(pixel));
+#endif
+
+ in += 3;
+ out += 2;
+ }
+ if (i == pixels - 1) {
+ pixel = (((UINT16)in[0]) << 4) + (in[1] >> 4);
+#ifdef WORDS_BIGENDIAN
+ out[0] = tmp[1];
+ out[1] = tmp[0];
+#else
+ memcpy(out, &pixel, sizeof(pixel));
+#endif
+ }
+}
+
+static void
+copy1(UINT8 *out, const UINT8 *in, int pixels) {
+ /* L, P */
+ memcpy(out, in, pixels);
+}
+
+static void
+copy2(UINT8 *out, const UINT8 *in, int pixels) {
+ /* I;16 */
+ memcpy(out, in, pixels * 2);
+}
+
+static void
+copy3(UINT8 *out, const UINT8 *in, int pixels) {
+ /* BGR;24 */
+ memcpy(out, in, pixels * 3);
+}
+
+static void
+copy4(UINT8 *out, const UINT8 *in, int pixels) {
+ /* RGBA, CMYK quadruples */
+ memcpy(out, in, 4 * pixels);
+}
+
+static void
+copy4skip1(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ for (i = 0; i < pixels; i++) {
+ memcpy(_out, in, 4);
+ in += 5;
+ _out += 4;
+ }
+}
+
+static void
+copy4skip2(UINT8 *_out, const UINT8 *in, int pixels) {
+ int i;
+ for (i = 0; i < pixels; i++) {
+ memcpy(_out, in, 4);
+ in += 6;
+ _out += 4;
+ }
+}
+
+/* Unpack to "I" and "F" images */
+
+#define UNPACK_RAW(NAME, GET, INTYPE, OUTTYPE) \
+ static void NAME(UINT8 *out_, const UINT8 *in, int pixels) { \
+ int i; \
+ OUTTYPE *out = (OUTTYPE *)out_; \
+ for (i = 0; i < pixels; i++, in += sizeof(INTYPE)) { \
+ out[i] = (OUTTYPE)((INTYPE)GET); \
+ } \
+ }
+
+#define UNPACK(NAME, COPY, INTYPE, OUTTYPE) \
+ static void NAME(UINT8 *out_, const UINT8 *in, int pixels) { \
+ int i; \
+ OUTTYPE *out = (OUTTYPE *)out_; \
+ INTYPE tmp_; \
+ UINT8 *tmp = (UINT8 *)&tmp_; \
+ for (i = 0; i < pixels; i++, in += sizeof(INTYPE)) { \
+ COPY; \
+ out[i] = (OUTTYPE)tmp_; \
+ } \
+ }
+
+UNPACK_RAW(unpackI8, in[0], UINT8, INT32)
+UNPACK_RAW(unpackI8S, in[0], INT8, INT32)
+UNPACK(unpackI16, C16L, UINT16, INT32)
+UNPACK(unpackI16S, C16L, INT16, INT32)
+UNPACK(unpackI16B, C16B, UINT16, INT32)
+UNPACK(unpackI16BS, C16B, INT16, INT32)
+UNPACK(unpackI16N, C16N, UINT16, INT32)
+UNPACK(unpackI16NS, C16N, INT16, INT32)
+UNPACK(unpackI32, C32L, UINT32, INT32)
+UNPACK(unpackI32S, C32L, INT32, INT32)
+UNPACK(unpackI32B, C32B, UINT32, INT32)
+UNPACK(unpackI32BS, C32B, INT32, INT32)
+UNPACK(unpackI32N, C32N, UINT32, INT32)
+UNPACK(unpackI32NS, C32N, INT32, INT32)
+
+UNPACK_RAW(unpackF8, in[0], UINT8, FLOAT32)
+UNPACK_RAW(unpackF8S, in[0], INT8, FLOAT32)
+UNPACK(unpackF16, C16L, UINT16, FLOAT32)
+UNPACK(unpackF16S, C16L, INT16, FLOAT32)
+UNPACK(unpackF16B, C16B, UINT16, FLOAT32)
+UNPACK(unpackF16BS, C16B, INT16, FLOAT32)
+UNPACK(unpackF16N, C16N, UINT16, FLOAT32)
+UNPACK(unpackF16NS, C16N, INT16, FLOAT32)
+UNPACK(unpackF32, C32L, UINT32, FLOAT32)
+UNPACK(unpackF32S, C32L, INT32, FLOAT32)
+UNPACK(unpackF32B, C32B, UINT32, FLOAT32)
+UNPACK(unpackF32BS, C32B, INT32, FLOAT32)
+UNPACK(unpackF32N, C32N, UINT32, FLOAT32)
+UNPACK(unpackF32NS, C32N, INT32, FLOAT32)
+UNPACK(unpackF32F, C32L, FLOAT32, FLOAT32)
+UNPACK(unpackF32BF, C32B, FLOAT32, FLOAT32)
+UNPACK(unpackF32NF, C32N, FLOAT32, FLOAT32)
+#ifdef FLOAT64
+UNPACK(unpackF64F, C64L, FLOAT64, FLOAT32)
+UNPACK(unpackF64BF, C64B, FLOAT64, FLOAT32)
+UNPACK(unpackF64NF, C64N, FLOAT64, FLOAT32)
+#endif
+
+/* Misc. unpackers */
+
+static void
+band0(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* band 0 only */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[i];
+ out += 4;
+ }
+}
+
+static void
+band1(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* band 1 only */
+ for (i = 0; i < pixels; i++) {
+ out[1] = in[i];
+ out += 4;
+ }
+}
+
+static void
+band2(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* band 2 only */
+ for (i = 0; i < pixels; i++) {
+ out[2] = in[i];
+ out += 4;
+ }
+}
+
+static void
+band3(UINT8 *out, const UINT8 *in, int pixels) {
+ /* band 3 only */
+ int i;
+ for (i = 0; i < pixels; i++) {
+ out[3] = in[i];
+ out += 4;
+ }
+}
+
+static void
+band0I(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* band 0 only */
+ for (i = 0; i < pixels; i++) {
+ out[0] = ~in[i];
+ out += 4;
+ }
+}
+
+static void
+band1I(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* band 1 only */
+ for (i = 0; i < pixels; i++) {
+ out[1] = ~in[i];
+ out += 4;
+ }
+}
+
+static void
+band2I(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* band 2 only */
+ for (i = 0; i < pixels; i++) {
+ out[2] = ~in[i];
+ out += 4;
+ }
+}
+
+static void
+band3I(UINT8 *out, const UINT8 *in, int pixels) {
+ /* band 3 only */
+ int i;
+ for (i = 0; i < pixels; i++) {
+ out[3] = ~in[i];
+ out += 4;
+ }
+}
+
+static void
+band016B(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 0 only, big endian */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[0];
+ out += 4; in += 2;
+ }
+}
+
+static void
+band116B(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 1 only, big endian */
+ for (i = 0; i < pixels; i++) {
+ out[1] = in[0];
+ out += 4; in += 2;
+ }
+}
+
+static void
+band216B(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 2 only, big endian */
+ for (i = 0; i < pixels; i++) {
+ out[2] = in[0];
+ out += 4; in += 2;
+ }
+}
+
+static void
+band316B(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 3 only, big endian */
+ for (i = 0; i < pixels; i++) {
+ out[3] = in[0];
+ out += 4; in += 2;
+ }
+}
+
+static void
+band016L(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 0 only, little endian */
+ for (i = 0; i < pixels; i++) {
+ out[0] = in[1];
+ out += 4; in += 2;
+ }
+}
+
+static void
+band116L(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 1 only, little endian */
+ for (i = 0; i < pixels; i++) {
+ out[1] = in[1];
+ out += 4; in += 2;
+ }
+}
+
+static void
+band216L(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 2 only, little endian */
+ for (i = 0; i < pixels; i++) {
+ out[2] = in[1];
+ out += 4; in += 2;
+ }
+}
+
+static void
+band316L(UINT8* out, const UINT8* in, int pixels)
+{
+ int i;
+ /* band 3 only, little endian */
+ for (i = 0; i < pixels; i++) {
+ out[3] = in[1];
+ out += 4; in += 2;
+ }
+}
+
+static struct {
+ const char *mode;
+ const char *rawmode;
+ int bits;
+ ImagingShuffler unpack;
+} unpackers[] = {
+
+ /* raw mode syntax is "<mode>;<bits><flags>" where "bits" defaults
+ depending on mode (1 for "1", 8 for "P" and "L", etc), and
+ "flags" should be given in alphabetical order. if both bits
+ and flags have their default values, the ; should be left out */
+
+ /* flags: "I" inverted data; "R" reversed bit order; "B" big
+ endian byte order (default is little endian); "L" line
+ interleave, "S" signed, "F" floating point */
+
+ /* exception: rawmodes "I" and "F" are always native endian byte order */
+
+ /* bilevel */
+ {"1", "1", 1, unpack1},
+ {"1", "1;I", 1, unpack1I},
+ {"1", "1;R", 1, unpack1R},
+ {"1", "1;IR", 1, unpack1IR},
+ {"1", "1;8", 8, unpack18},
+
+ /* greyscale */
+ {"L", "L;2", 2, unpackL2},
+ {"L", "L;2I", 2, unpackL2I},
+ {"L", "L;2R", 2, unpackL2R},
+ {"L", "L;2IR", 2, unpackL2IR},
+
+ {"L", "L;4", 4, unpackL4},
+ {"L", "L;4I", 4, unpackL4I},
+ {"L", "L;4R", 4, unpackL4R},
+ {"L", "L;4IR", 4, unpackL4IR},
+
+ {"L", "L", 8, copy1},
+ {"L", "L;I", 8, unpackLI},
+ {"L", "L;R", 8, unpackLR},
+ {"L", "L;16", 16, unpackL16},
+ {"L", "L;16B", 16, unpackL16B},
+
+ /* greyscale w. alpha */
+ {"LA", "LA", 16, unpackLA},
+ {"LA", "LA;L", 16, unpackLAL},
+
+ /* greyscale w. alpha premultiplied */
+ {"La", "La", 16, unpackLA},
+
+ /* palette */
+ {"P", "P;1", 1, unpackP1},
+ {"P", "P;2", 2, unpackP2},
+ {"P", "P;2L", 2, unpackP2L},
+ {"P", "P;4", 4, unpackP4},
+ {"P", "P;4L", 4, unpackP4L},
+ {"P", "P", 8, copy1},
+ {"P", "P;R", 8, unpackLR},
+ {"P", "L", 8, copy1},
+
+ /* palette w. alpha */
+ {"PA", "PA", 16, unpackLA},
+ {"PA", "PA;L", 16, unpackLAL},
+ {"PA", "LA", 16, unpackLA},
+
+ /* true colour */
+ {"RGB", "RGB", 24, ImagingUnpackRGB},
+ {"RGB", "RGB;L", 24, unpackRGBL},
+ {"RGB", "RGB;R", 24, unpackRGBR},
+ {"RGB", "RGB;16L", 48, unpackRGB16L},
+ {"RGB", "RGB;16B", 48, unpackRGB16B},
+ {"RGB", "BGR", 24, ImagingUnpackBGR},
+ {"RGB", "RGB;15", 16, ImagingUnpackRGB15},
+ {"RGB", "BGR;15", 16, ImagingUnpackBGR15},
+ {"RGB", "RGB;16", 16, ImagingUnpackRGB16},
+ {"RGB", "BGR;16", 16, ImagingUnpackBGR16},
+ {"RGB", "RGB;4B", 16, ImagingUnpackRGB4B},
+ {"RGB", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */
+ {"RGB", "RGBX", 32, copy4},
+ {"RGB", "RGBX;L", 32, unpackRGBAL},
+ {"RGB", "RGBA;L", 32, unpackRGBAL},
+ {"RGB", "RGBA;15", 16, ImagingUnpackRGBA15},
+ {"RGB", "BGRX", 32, ImagingUnpackBGRX},
+ {"RGB", "XRGB", 32, ImagingUnpackXRGB},
+ {"RGB", "XBGR", 32, ImagingUnpackXBGR},
+ {"RGB", "YCC;P", 24, ImagingUnpackYCC},
+ {"RGB", "R", 8, band0},
+ {"RGB", "G", 8, band1},
+ {"RGB", "B", 8, band2},
+ {"RGB", "R;16L", 16, band016L},
+ {"RGB", "G;16L", 16, band116L},
+ {"RGB", "B;16L", 16, band216L},
+ {"RGB", "R;16B", 16, band016B},
+ {"RGB", "G;16B", 16, band116B},
+ {"RGB", "B;16B", 16, band216B},
+ {"RGB", "CMYK", 32, cmyk2rgb},
+
+ {"BGR;15", "BGR;15", 16, copy2},
+ {"BGR;16", "BGR;16", 16, copy2},
+ {"BGR;24", "BGR;24", 24, copy3},
+
+ /* true colour w. alpha */
+ {"RGBA", "LA", 16, unpackRGBALA},
+ {"RGBA", "LA;16B", 32, unpackRGBALA16B},
+ {"RGBA", "RGBA", 32, copy4},
+ {"RGBA", "RGBAX", 40, copy4skip1},
+ {"RGBA", "RGBAXX", 48, copy4skip2},
+ {"RGBA", "RGBa", 32, unpackRGBa},
+ {"RGBA", "RGBaX", 40, unpackRGBaskip1},
+ {"RGBA", "RGBaXX", 48, unpackRGBaskip2},
+ {"RGBA", "RGBa;16L", 64, unpackRGBa16L},
+ {"RGBA", "RGBa;16B", 64, unpackRGBa16B},
+ {"RGBA", "BGRa", 32, unpackBGRa},
+ {"RGBA", "RGBA;I", 32, unpackRGBAI},
+ {"RGBA", "RGBA;L", 32, unpackRGBAL},
+ {"RGBA", "RGBA;15", 16, ImagingUnpackRGBA15},
+ {"RGBA", "BGRA;15", 16, ImagingUnpackBGRA15},
+ {"RGBA", "RGBA;4B", 16, ImagingUnpackRGBA4B},
+ {"RGBA", "RGBA;16L", 64, unpackRGBA16L},
+ {"RGBA", "RGBA;16B", 64, unpackRGBA16B},
+ {"RGBA", "BGRA", 32, unpackBGRA},
+ {"RGBA", "BGRA;16L", 64, unpackBGRA16L},
+ {"RGBA", "BGRA;16B", 64, unpackBGRA16B},
+ {"RGBA", "ARGB", 32, unpackARGB},
+ {"RGBA", "ABGR", 32, unpackABGR},
+ {"RGBA", "YCCA;P", 32, ImagingUnpackYCCA},
+ {"RGBA", "R", 8, band0},
+ {"RGBA", "G", 8, band1},
+ {"RGBA", "B", 8, band2},
+ {"RGBA", "A", 8, band3},
+ {"RGBA", "R;16L", 16, band016L},
+ {"RGBA", "G;16L", 16, band116L},
+ {"RGBA", "B;16L", 16, band216L},
+ {"RGBA", "A;16L", 16, band316L},
+ {"RGBA", "R;16B", 16, band016B},
+ {"RGBA", "G;16B", 16, band116B},
+ {"RGBA", "B;16B", 16, band216B},
+ {"RGBA", "A;16B", 16, band316B},
+
+#ifdef WORDS_BIGENDIAN
+ {"RGB", "RGB;16N", 48, unpackRGB16B},
+ {"RGBA", "RGBa;16N", 64, unpackRGBa16B},
+ {"RGBA", "RGBA;16N", 64, unpackRGBA16B},
+ {"RGBX", "RGBX;16N", 64, unpackRGBA16B},
+ {"RGB", "R;16N", 16, band016B},
+ {"RGB", "G;16N", 16, band116B},
+ {"RGB", "B;16N", 16, band216B},
+
+ {"RGBA", "R;16N", 16, band016B},
+ {"RGBA", "G;16N", 16, band116B},
+ {"RGBA", "B;16N", 16, band216B},
+ {"RGBA", "A;16N", 16, band316B},
+#else
+ {"RGB", "RGB;16N", 48, unpackRGB16L},
+ {"RGBA", "RGBa;16N", 64, unpackRGBa16L},
+ {"RGBA", "RGBA;16N", 64, unpackRGBA16L},
+ {"RGBX", "RGBX;16N", 64, unpackRGBA16L},
+ {"RGB", "R;16N", 16, band016L},
+ {"RGB", "G;16N", 16, band116L},
+ {"RGB", "B;16N", 16, band216L},
+
+
+ {"RGBA", "R;16N", 16, band016L},
+ {"RGBA", "G;16N", 16, band116L},
+ {"RGBA", "B;16N", 16, band216L},
+ {"RGBA", "A;16N", 16, band316L},
+#endif
+
+ /* true colour w. alpha premultiplied */
+ {"RGBa", "RGBa", 32, copy4},
+ {"RGBa", "BGRa", 32, unpackBGRA},
+ {"RGBa", "aRGB", 32, unpackARGB},
+ {"RGBa", "aBGR", 32, unpackABGR},
+
+ /* true colour w. padding */
+ {"RGBX", "RGB", 24, ImagingUnpackRGB},
+ {"RGBX", "RGB;L", 24, unpackRGBL},
+ {"RGBX", "RGB;16B", 48, unpackRGB16B},
+ {"RGBX", "BGR", 24, ImagingUnpackBGR},
+ {"RGBX", "RGB;15", 16, ImagingUnpackRGB15},
+ {"RGBX", "BGR;15", 16, ImagingUnpackBGR15},
+ {"RGBX", "RGB;4B", 16, ImagingUnpackRGB4B},
+ {"RGBX", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */
+ {"RGBX", "RGBX", 32, copy4},
+ {"RGBX", "RGBXX", 40, copy4skip1},
+ {"RGBX", "RGBXXX", 48, copy4skip2},
+ {"RGBX", "RGBX;L", 32, unpackRGBAL},
+ {"RGBX", "RGBX;16L", 64, unpackRGBA16L},
+ {"RGBX", "RGBX;16B", 64, unpackRGBA16B},
+ {"RGBX", "BGRX", 32, ImagingUnpackBGRX},
+ {"RGBX", "XRGB", 32, ImagingUnpackXRGB},
+ {"RGBX", "XBGR", 32, ImagingUnpackXBGR},
+ {"RGBX", "YCC;P", 24, ImagingUnpackYCC},
+ {"RGBX", "R", 8, band0},
+ {"RGBX", "G", 8, band1},
+ {"RGBX", "B", 8, band2},
+ {"RGBX", "X", 8, band3},
+
+ /* colour separation */
+ {"CMYK", "CMYK", 32, copy4},
+ {"CMYK", "CMYKX", 40, copy4skip1},
+ {"CMYK", "CMYKXX", 48, copy4skip2},
+ {"CMYK", "CMYK;I", 32, unpackCMYKI},
+ {"CMYK", "CMYK;L", 32, unpackRGBAL},
+ {"CMYK", "CMYK;16L", 64, unpackRGBA16L},
+ {"CMYK", "CMYK;16B", 64, unpackRGBA16B},
+ {"CMYK", "C", 8, band0},
+ {"CMYK", "M", 8, band1},
+ {"CMYK", "Y", 8, band2},
+ {"CMYK", "K", 8, band3},
+ {"CMYK", "C;I", 8, band0I},
+ {"CMYK", "M;I", 8, band1I},
+ {"CMYK", "Y;I", 8, band2I},
+ {"CMYK", "K;I", 8, band3I},
+
+#ifdef WORDS_BIGENDIAN
+ {"CMYK", "CMYK;16N", 64, unpackRGBA16B},
+#else
+ {"CMYK", "CMYK;16N", 64, unpackRGBA16L},
+#endif
+
+ /* video (YCbCr) */
+ {"YCbCr", "YCbCr", 24, ImagingUnpackRGB},
+ {"YCbCr", "YCbCr;L", 24, unpackRGBL},
+ {"YCbCr", "YCbCrX", 32, copy4},
+ {"YCbCr", "YCbCrK", 32, copy4},
+
+ /* LAB Color */
+ {"LAB", "LAB", 24, ImagingUnpackLAB},
+ {"LAB", "L", 8, band0},
+ {"LAB", "A", 8, band1},
+ {"LAB", "B", 8, band2},
+
+ /* HSV Color */
+ {"HSV", "HSV", 24, ImagingUnpackRGB},
+ {"HSV", "H", 8, band0},
+ {"HSV", "S", 8, band1},
+ {"HSV", "V", 8, band2},
+
+ /* integer variations */
+ {"I", "I", 32, copy4},
+ {"I", "I;8", 8, unpackI8},
+ {"I", "I;8S", 8, unpackI8S},
+ {"I", "I;16", 16, unpackI16},
+ {"I", "I;16S", 16, unpackI16S},
+ {"I", "I;16B", 16, unpackI16B},
+ {"I", "I;16BS", 16, unpackI16BS},
+ {"I", "I;16N", 16, unpackI16N},
+ {"I", "I;16NS", 16, unpackI16NS},
+ {"I", "I;32", 32, unpackI32},
+ {"I", "I;32S", 32, unpackI32S},
+ {"I", "I;32B", 32, unpackI32B},
+ {"I", "I;32BS", 32, unpackI32BS},
+ {"I", "I;32N", 32, unpackI32N},
+ {"I", "I;32NS", 32, unpackI32NS},
+
+ /* floating point variations */
+ {"F", "F", 32, copy4},
+ {"F", "F;8", 8, unpackF8},
+ {"F", "F;8S", 8, unpackF8S},
+ {"F", "F;16", 16, unpackF16},
+ {"F", "F;16S", 16, unpackF16S},
+ {"F", "F;16B", 16, unpackF16B},
+ {"F", "F;16BS", 16, unpackF16BS},
+ {"F", "F;16N", 16, unpackF16N},
+ {"F", "F;16NS", 16, unpackF16NS},
+ {"F", "F;32", 32, unpackF32},
+ {"F", "F;32S", 32, unpackF32S},
+ {"F", "F;32B", 32, unpackF32B},
+ {"F", "F;32BS", 32, unpackF32BS},
+ {"F", "F;32N", 32, unpackF32N},
+ {"F", "F;32NS", 32, unpackF32NS},
+ {"F", "F;32F", 32, unpackF32F},
+ {"F", "F;32BF", 32, unpackF32BF},
+ {"F", "F;32NF", 32, unpackF32NF},
+#ifdef FLOAT64
+ {"F", "F;64F", 64, unpackF64F},
+ {"F", "F;64BF", 64, unpackF64BF},
+ {"F", "F;64NF", 64, unpackF64NF},
+#endif
+
+ /* storage modes */
+ {"I;16", "I;16", 16, copy2},
+ {"I;16B", "I;16B", 16, copy2},
+ {"I;16L", "I;16L", 16, copy2},
+ {"I;16N", "I;16N", 16, copy2},
+
+ {"I;16", "I;16B", 16, unpackI16B_I16},
+ {"I;16", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian.
+ {"I;16L", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian.
+ {"I;16B", "I;16N", 16, unpackI16N_I16B},
+
+ {"I;16", "I;16R", 16, unpackI16R_I16},
+
+ {"I;16", "I;12", 12, unpackI12_I16}, // 12 bit Tiffs stored in 16bits.
+
+ {NULL} /* sentinel */
+};
+
+ImagingShuffler
+ImagingFindUnpacker(const char *mode, const char *rawmode, int *bits_out) {
+ int i;
+
+ /* find a suitable pixel unpacker */
+ for (i = 0; unpackers[i].rawmode; i++) {
+ if (strcmp(unpackers[i].mode, mode) == 0 &&
+ strcmp(unpackers[i].rawmode, rawmode) == 0) {
+ if (bits_out) {
+ *bits_out = unpackers[i].bits;
+ }
+ return unpackers[i].unpack;
+ }
+ }
+
+ /* FIXME: configure a general unpacker based on the type codes... */
+
+ return NULL;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/UnpackYCC.c b/contrib/python/Pillow/py3/libImaging/UnpackYCC.c
new file mode 100644
index 00000000000..0b177bdd4f5
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/UnpackYCC.c
@@ -0,0 +1,163 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * code to convert and unpack PhotoYCC data
+ *
+ * history:
+ * 97-01-25 fl Moved from PcdDecode.c
+ *
+ * Copyright (c) Fredrik Lundh 1996-97.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+/* Tables generated by pcdtables.py, based on transforms taken from
+ the "Colour Space Conversions FAQ" by Roberts/Ford. */
+
+static INT16 L[] = {
+ 0, 1, 3, 4, 5, 7, 8, 10, 11, 12, 14, 15, 16, 18, 19, 20,
+ 22, 23, 24, 26, 27, 29, 30, 31, 33, 34, 35, 37, 38, 39, 41, 42,
+ 43, 45, 46, 48, 49, 50, 52, 53, 54, 56, 57, 58, 60, 61, 62, 64,
+ 65, 67, 68, 69, 71, 72, 73, 75, 76, 77, 79, 80, 82, 83, 84, 86,
+ 87, 88, 90, 91, 92, 94, 95, 96, 98, 99, 101, 102, 103, 105, 106, 107,
+ 109, 110, 111, 113, 114, 115, 117, 118, 120, 121, 122, 124, 125, 126, 128, 129,
+ 130, 132, 133, 134, 136, 137, 139, 140, 141, 143, 144, 145, 147, 148, 149, 151,
+ 152, 153, 155, 156, 158, 159, 160, 162, 163, 164, 166, 167, 168, 170, 171, 173,
+ 174, 175, 177, 178, 179, 181, 182, 183, 185, 186, 187, 189, 190, 192, 193, 194,
+ 196, 197, 198, 200, 201, 202, 204, 205, 206, 208, 209, 211, 212, 213, 215, 216,
+ 217, 219, 220, 221, 223, 224, 225, 227, 228, 230, 231, 232, 234, 235, 236, 238,
+ 239, 240, 242, 243, 245, 246, 247, 249, 250, 251, 253, 254, 255, 257, 258, 259,
+ 261, 262, 264, 265, 266, 268, 269, 270, 272, 273, 274, 276, 277, 278, 280, 281,
+ 283, 284, 285, 287, 288, 289, 291, 292, 293, 295, 296, 297, 299, 300, 302, 303,
+ 304, 306, 307, 308, 310, 311, 312, 314, 315, 317, 318, 319, 321, 322, 323, 325,
+ 326, 327, 329, 330, 331, 333, 334, 336, 337, 338, 340, 341, 342, 344, 345, 346};
+
+static INT16 CB[] = {
+ -345, -343, -341, -338, -336, -334, -332, -329, -327, -325, -323, -321, -318, -316,
+ -314, -312, -310, -307, -305, -303, -301, -298, -296, -294, -292, -290, -287, -285,
+ -283, -281, -278, -276, -274, -272, -270, -267, -265, -263, -261, -258, -256, -254,
+ -252, -250, -247, -245, -243, -241, -239, -236, -234, -232, -230, -227, -225, -223,
+ -221, -219, -216, -214, -212, -210, -207, -205, -203, -201, -199, -196, -194, -192,
+ -190, -188, -185, -183, -181, -179, -176, -174, -172, -170, -168, -165, -163, -161,
+ -159, -156, -154, -152, -150, -148, -145, -143, -141, -139, -137, -134, -132, -130,
+ -128, -125, -123, -121, -119, -117, -114, -112, -110, -108, -105, -103, -101, -99,
+ -97, -94, -92, -90, -88, -85, -83, -81, -79, -77, -74, -72, -70, -68,
+ -66, -63, -61, -59, -57, -54, -52, -50, -48, -46, -43, -41, -39, -37,
+ -34, -32, -30, -28, -26, -23, -21, -19, -17, -15, -12, -10, -8, -6,
+ -3, -1, 0, 2, 4, 7, 9, 11, 13, 16, 18, 20, 22, 24,
+ 27, 29, 31, 33, 35, 38, 40, 42, 44, 47, 49, 51, 53, 55,
+ 58, 60, 62, 64, 67, 69, 71, 73, 75, 78, 80, 82, 84, 86,
+ 89, 91, 93, 95, 98, 100, 102, 104, 106, 109, 111, 113, 115, 118,
+ 120, 122, 124, 126, 129, 131, 133, 135, 138, 140, 142, 144, 146, 149,
+ 151, 153, 155, 157, 160, 162, 164, 166, 169, 171, 173, 175, 177, 180,
+ 182, 184, 186, 189, 191, 193, 195, 197, 200, 202, 204, 206, 208, 211,
+ 213, 215, 217, 220};
+
+static INT16 GB[] = {
+ 67, 67, 66, 66, 65, 65, 65, 64, 64, 63, 63, 62, 62, 62, 61, 61,
+ 60, 60, 59, 59, 59, 58, 58, 57, 57, 56, 56, 56, 55, 55, 54, 54,
+ 53, 53, 52, 52, 52, 51, 51, 50, 50, 49, 49, 49, 48, 48, 47, 47,
+ 46, 46, 46, 45, 45, 44, 44, 43, 43, 43, 42, 42, 41, 41, 40, 40,
+ 40, 39, 39, 38, 38, 37, 37, 37, 36, 36, 35, 35, 34, 34, 34, 33,
+ 33, 32, 32, 31, 31, 31, 30, 30, 29, 29, 28, 28, 28, 27, 27, 26,
+ 26, 25, 25, 25, 24, 24, 23, 23, 22, 22, 22, 21, 21, 20, 20, 19,
+ 19, 19, 18, 18, 17, 17, 16, 16, 15, 15, 15, 14, 14, 13, 13, 12,
+ 12, 12, 11, 11, 10, 10, 9, 9, 9, 8, 8, 7, 7, 6, 6, 6,
+ 5, 5, 4, 4, 3, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0,
+ -1, -1, -2, -2, -2, -3, -3, -4, -4, -5, -5, -5, -6, -6, -7, -7,
+ -8, -8, -8, -9, -9, -10, -10, -11, -11, -11, -12, -12, -13, -13, -14, -14,
+ -14, -15, -15, -16, -16, -17, -17, -18, -18, -18, -19, -19, -20, -20, -21, -21,
+ -21, -22, -22, -23, -23, -24, -24, -24, -25, -25, -26, -26, -27, -27, -27, -28,
+ -28, -29, -29, -30, -30, -30, -31, -31, -32, -32, -33, -33, -33, -34, -34, -35,
+ -35, -36, -36, -36, -37, -37, -38, -38, -39, -39, -39, -40, -40, -41, -41, -42};
+
+static INT16 CR[] = {
+ -249, -247, -245, -243, -241, -239, -238, -236, -234, -232, -230, -229, -227, -225,
+ -223, -221, -219, -218, -216, -214, -212, -210, -208, -207, -205, -203, -201, -199,
+ -198, -196, -194, -192, -190, -188, -187, -185, -183, -181, -179, -178, -176, -174,
+ -172, -170, -168, -167, -165, -163, -161, -159, -157, -156, -154, -152, -150, -148,
+ -147, -145, -143, -141, -139, -137, -136, -134, -132, -130, -128, -127, -125, -123,
+ -121, -119, -117, -116, -114, -112, -110, -108, -106, -105, -103, -101, -99, -97,
+ -96, -94, -92, -90, -88, -86, -85, -83, -81, -79, -77, -76, -74, -72,
+ -70, -68, -66, -65, -63, -61, -59, -57, -55, -54, -52, -50, -48, -46,
+ -45, -43, -41, -39, -37, -35, -34, -32, -30, -28, -26, -25, -23, -21,
+ -19, -17, -15, -14, -12, -10, -8, -6, -4, -3, -1, 0, 2, 4,
+ 5, 7, 9, 11, 13, 15, 16, 18, 20, 22, 24, 26, 27, 29,
+ 31, 33, 35, 36, 38, 40, 42, 44, 46, 47, 49, 51, 53, 55,
+ 56, 58, 60, 62, 64, 66, 67, 69, 71, 73, 75, 77, 78, 80,
+ 82, 84, 86, 87, 89, 91, 93, 95, 97, 98, 100, 102, 104, 106,
+ 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 129, 131,
+ 133, 135, 137, 138, 140, 142, 144, 146, 148, 149, 151, 153, 155, 157,
+ 158, 160, 162, 164, 166, 168, 169, 171, 173, 175, 177, 179, 180, 182,
+ 184, 186, 188, 189, 191, 193, 195, 197, 199, 200, 202, 204, 206, 208,
+ 209, 211, 213, 215};
+
+static INT16 GR[] = {
+ 127, 126, 125, 124, 123, 122, 121, 121, 120, 119, 118, 117, 116, 115, 114,
+ 113, 112, 111, 110, 109, 108, 108, 107, 106, 105, 104, 103, 102, 101, 100,
+ 99, 98, 97, 96, 95, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86,
+ 85, 84, 83, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72,
+ 71, 70, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58,
+ 57, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 45,
+ 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 32, 31,
+ 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 19, 18, 17,
+ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 6, 5, 4, 3,
+ 2, 1, 0, 0, -1, -2, -3, -4, -5, -5, -6, -7, -8, -9, -10,
+ -11, -12, -13, -14, -15, -16, -17, -18, -18, -19, -20, -21, -22, -23, -24,
+ -25, -26, -27, -28, -29, -30, -31, -31, -32, -33, -34, -35, -36, -37, -38,
+ -39, -40, -41, -42, -43, -44, -44, -45, -46, -47, -48, -49, -50, -51, -52,
+ -53, -54, -55, -56, -56, -57, -58, -59, -60, -61, -62, -63, -64, -65, -66,
+ -67, -68, -69, -69, -70, -71, -72, -73, -74, -75, -76, -77, -78, -79, -80,
+ -81, -82, -82, -83, -84, -85, -86, -87, -88, -89, -90, -91, -92, -93, -94,
+ -94, -95, -96, -97, -98, -99, -100, -101, -102, -103, -104, -105, -106, -107, -107,
+ -108};
+
+#define R 0
+#define G 1
+#define B 2
+#define A 3
+
+#define YCC2RGB(rgb, y, cb, cr) \
+ { \
+ int l = L[y]; \
+ int r = l + CR[cr]; \
+ int g = l + GR[cr] + GB[cb]; \
+ int b = l + CB[cb]; \
+ rgb[0] = (r <= 0) ? 0 : (r >= 255) ? 255 : r; \
+ rgb[1] = (g <= 0) ? 0 : (g >= 255) ? 255 : g; \
+ rgb[2] = (b <= 0) ? 0 : (b >= 255) ? 255 : b; \
+ }
+
+void
+ImagingUnpackYCC(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* PhotoYCC triplets */
+ for (i = 0; i < pixels; i++) {
+ YCC2RGB(out, in[0], in[1], in[2]);
+ out[A] = 255;
+ out += 4;
+ in += 3;
+ }
+}
+
+void
+ImagingUnpackYCCA(UINT8 *out, const UINT8 *in, int pixels) {
+ int i;
+ /* PhotoYCC triplets plus premultiplied alpha */
+ for (i = 0; i < pixels; i++) {
+ /* Divide by alpha */
+ UINT8 rgb[3];
+ rgb[0] = (in[3] == 0) ? 0 : (((int)in[0] * 255) / in[3]);
+ rgb[1] = (in[3] == 0) ? 0 : (((int)in[1] * 255) / in[3]);
+ rgb[2] = (in[3] == 0) ? 0 : (((int)in[2] * 255) / in[3]);
+ /* Convert non-multiplied data to RGB */
+ YCC2RGB(out, rgb[0], rgb[1], rgb[2]);
+ out[A] = in[3];
+ out += 4;
+ in += 4;
+ }
+}
diff --git a/contrib/python/Pillow/py3/libImaging/UnsharpMask.c b/contrib/python/Pillow/py3/libImaging/UnsharpMask.c
new file mode 100644
index 00000000000..2853ce903fc
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/UnsharpMask.c
@@ -0,0 +1,97 @@
+/* PILusm, a gaussian blur and unsharp masking library for PIL
+ By Kevin Cazabon, copyright 2003
+
+/* Originally released under LGPL. Graciously donated to PIL
+ for distribution under the standard PIL license in 2009." */
+
+#include "Imaging.h"
+
+typedef UINT8 pixel[4];
+
+static inline UINT8
+clip8(int in) {
+ if (in >= 255) {
+ return 255;
+ }
+ if (in <= 0) {
+ return 0;
+ }
+ return (UINT8)in;
+}
+
+Imaging
+ImagingUnsharpMask(
+ Imaging imOut, Imaging imIn, float radius, int percent, int threshold) {
+ ImagingSectionCookie cookie;
+ Imaging result;
+
+ int x, y, diff;
+
+ pixel *lineIn = NULL;
+ pixel *lineOut = NULL;
+ UINT8 *lineIn8 = NULL;
+ UINT8 *lineOut8 = NULL;
+
+ /* First, do a gaussian blur on the image, putting results in imOut
+ temporarily. All format checks are in gaussian blur. */
+ result = ImagingGaussianBlur(imOut, imIn, radius, radius, 3);
+ if (!result) {
+ return NULL;
+ }
+
+ /* Now, go through each pixel, compare "normal" pixel to blurred
+ pixel. If the difference is more than threshold values, apply
+ the OPPOSITE correction to the amount of blur, multiplied by
+ percent. */
+
+ ImagingSectionEnter(&cookie);
+
+ for (y = 0; y < imIn->ysize; y++) {
+ if (imIn->image8) {
+ lineIn8 = imIn->image8[y];
+ lineOut8 = imOut->image8[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ /* compare in/out pixels, apply sharpening */
+ diff = lineIn8[x] - lineOut8[x];
+ if (abs(diff) > threshold) {
+ /* add the diff*percent to the original pixel */
+ lineOut8[x] = clip8(lineIn8[x] + diff * percent / 100);
+ } else {
+ /* new pixel is the same as imIn */
+ lineOut8[x] = lineIn8[x];
+ }
+ }
+ } else {
+ lineIn = (pixel *)imIn->image32[y];
+ lineOut = (pixel *)imOut->image32[y];
+ for (x = 0; x < imIn->xsize; x++) {
+ /* compare in/out pixels, apply sharpening */
+ diff = lineIn[x][0] - lineOut[x][0];
+ lineOut[x][0] = abs(diff) > threshold
+ ? clip8(lineIn[x][0] + diff * percent / 100)
+ : lineIn[x][0];
+
+ diff = lineIn[x][1] - lineOut[x][1];
+ lineOut[x][1] = abs(diff) > threshold
+ ? clip8(lineIn[x][1] + diff * percent / 100)
+ : lineIn[x][1];
+
+ diff = lineIn[x][2] - lineOut[x][2];
+ lineOut[x][2] = abs(diff) > threshold
+ ? clip8(lineIn[x][2] + diff * percent / 100)
+ : lineIn[x][2];
+
+ diff = lineIn[x][3] - lineOut[x][3];
+ lineOut[x][3] = abs(diff) > threshold
+ ? clip8(lineIn[x][3] + diff * percent / 100)
+ : lineIn[x][3];
+ }
+ }
+ }
+
+ ImagingSectionLeave(&cookie);
+
+ return imOut;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/XbmDecode.c b/contrib/python/Pillow/py3/libImaging/XbmDecode.c
new file mode 100644
index 00000000000..d6690de3d28
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/XbmDecode.c
@@ -0,0 +1,78 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for XBM hex image data
+ *
+ * history:
+ * 96-04-13 fl Created
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#define HEX(v) \
+ ((v >= '0' && v <= '9') ? v - '0' \
+ : (v >= 'a' && v <= 'f') ? v - 'a' + 10 \
+ : (v >= 'A' && v <= 'F') ? v - 'A' + 10 \
+ : 0)
+
+int
+ImagingXbmDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ enum { BYTE = 1, SKIP };
+
+ UINT8 *ptr;
+
+ if (!state->state) {
+ state->state = SKIP;
+ }
+
+ ptr = buf;
+
+ for (;;) {
+ if (state->state == SKIP) {
+ /* Skip forward until next 'x' */
+
+ while (bytes > 0) {
+ if (*ptr == 'x') {
+ break;
+ }
+ ptr++;
+ bytes--;
+ }
+
+ if (bytes == 0) {
+ return ptr - buf;
+ }
+
+ state->state = BYTE;
+ }
+
+ if (bytes < 3) {
+ return ptr - buf;
+ }
+
+ state->buffer[state->x] = (HEX(ptr[1]) << 4) + HEX(ptr[2]);
+
+ if (++state->x >= state->bytes) {
+ /* Got a full line, unpack it */
+ state->shuffle((UINT8 *)im->image[state->y], state->buffer, state->xsize);
+
+ state->x = 0;
+
+ if (++state->y >= state->ysize) {
+ /* End of file (errcode = 0) */
+ return -1;
+ }
+ }
+
+ ptr += 3;
+ bytes -= 3;
+
+ state->state = SKIP;
+ }
+}
diff --git a/contrib/python/Pillow/py3/libImaging/XbmEncode.c b/contrib/python/Pillow/py3/libImaging/XbmEncode.c
new file mode 100644
index 00000000000..eec4c0d8462
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/XbmEncode.c
@@ -0,0 +1,96 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * encoder for Xbm data
+ *
+ * history:
+ * 96-11-01 fl created
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+int
+ImagingXbmEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
+ const char *hex = "0123456789abcdef";
+
+ UINT8 *ptr = buf;
+ int i, n;
+
+ if (!state->state) {
+ /* 8 pixels are stored in no more than 6 bytes */
+ state->bytes = 6 * (state->xsize + 7) / 8;
+
+ state->state = 1;
+ }
+
+ if (bytes < state->bytes) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return 0;
+ }
+
+ ptr = buf;
+
+ while (bytes >= state->bytes) {
+ state->shuffle(
+ state->buffer,
+ (UINT8 *)im->image[state->y + state->yoff] + state->xoff * im->pixelsize,
+ state->xsize);
+
+ if (state->y < state->ysize - 1) {
+ /* any line but the last */
+ for (n = 0; n < state->xsize; n += 8) {
+ i = state->buffer[n / 8];
+
+ *ptr++ = '0';
+ *ptr++ = 'x';
+ *ptr++ = hex[(i >> 4) & 15];
+ *ptr++ = hex[i & 15];
+ *ptr++ = ',';
+ bytes -= 5;
+
+ if (++state->count >= 79 / 5) {
+ *ptr++ = '\n';
+ bytes--;
+ state->count = 0;
+ }
+ }
+
+ state->y++;
+
+ } else {
+ /* last line */
+ for (n = 0; n < state->xsize; n += 8) {
+ i = state->buffer[n / 8];
+
+ *ptr++ = '0';
+ *ptr++ = 'x';
+ *ptr++ = hex[(i >> 4) & 15];
+ *ptr++ = hex[i & 15];
+
+ if (n < state->xsize - 8) {
+ *ptr++ = ',';
+ if (++state->count >= 79 / 5) {
+ *ptr++ = '\n';
+ bytes--;
+ state->count = 0;
+ }
+ } else {
+ *ptr++ = '\n';
+ }
+
+ bytes -= 5;
+ }
+
+ state->errcode = IMAGING_CODEC_END;
+ break;
+ }
+ }
+
+ return ptr - buf;
+}
diff --git a/contrib/python/Pillow/py3/libImaging/ZipCodecs.h b/contrib/python/Pillow/py3/libImaging/ZipCodecs.h
new file mode 100644
index 00000000000..50218b6c69a
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/ZipCodecs.h
@@ -0,0 +1,58 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * declarations for the ZIP codecs
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ */
+
+#include "zlib.h"
+
+/* modes */
+#define ZIP_PNG 0 /* continuous, filtered image data */
+#define ZIP_PNG_PALETTE 1 /* non-continuous data, disable filtering */
+#define ZIP_TIFF_PREDICTOR 2 /* TIFF, with predictor */
+#define ZIP_TIFF 3 /* TIFF, without predictor */
+
+typedef struct {
+ /* CONFIGURATION */
+
+ /* Codec mode */
+ int mode;
+
+ /* Optimize (max compression) SLOW!!! */
+ int optimize;
+
+ /* 0 no compression, 9 best compression, -1 default compression */
+ int compress_level;
+ /* compression strategy Z_XXX */
+ int compress_type;
+
+ /* Predefined dictionary (experimental) */
+ char *dictionary;
+ int dictionary_size;
+
+ /* PRIVATE CONTEXT (set by decoder/encoder) */
+
+ z_stream z_stream; /* (de)compression stream */
+
+ UINT8 *previous; /* previous line (allocated) */
+
+ int last_output; /* # bytes last output by inflate */
+
+ /* Compressor specific stuff */
+ UINT8 *prior; /* filter storage (allocated) */
+ UINT8 *up;
+ UINT8 *average;
+ UINT8 *paeth;
+
+ UINT8 *output; /* output data */
+
+ int prefix; /* size of filter prefix (0 for TIFF data) */
+
+ int interlaced; /* is the image interlaced? (PNG) */
+
+ int pass; /* current pass of the interlaced image (PNG) */
+
+} ZIPSTATE;
diff --git a/contrib/python/Pillow/py3/libImaging/ZipDecode.c b/contrib/python/Pillow/py3/libImaging/ZipDecode.c
new file mode 100644
index 00000000000..8749678341e
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/ZipDecode.c
@@ -0,0 +1,299 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * decoder for ZIP (deflated) image data.
+ *
+ * history:
+ * 1996-12-14 fl Created (for PNG)
+ * 1997-01-15 fl Prepared to read TIFF/ZIP
+ * 2001-11-19 fl PNG incomplete read patch (from Bernhard Herzog)
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997-2001.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#ifdef HAVE_LIBZ
+
+#include "ZipCodecs.h"
+
+static const int OFFSET[] = {7, 3, 3, 1, 1, 0, 0};
+static const int STARTING_COL[] = {0, 4, 0, 2, 0, 1, 0};
+static const int STARTING_ROW[] = {0, 0, 4, 0, 2, 0, 1};
+static const int COL_INCREMENT[] = {8, 8, 4, 4, 2, 2, 1};
+static const int ROW_INCREMENT[] = {8, 8, 8, 4, 4, 2, 2};
+
+/* Get the length in bytes of a scanline in the pass specified,
+ * for interlaced images */
+static int
+get_row_len(ImagingCodecState state, int pass) {
+ int row_len = (state->xsize + OFFSET[pass]) / COL_INCREMENT[pass];
+ return ((row_len * state->bits) + 7) / 8;
+}
+
+/* -------------------------------------------------------------------- */
+/* Decoder */
+/* -------------------------------------------------------------------- */
+
+int
+ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
+ ZIPSTATE *context = (ZIPSTATE *)state->context;
+ int err;
+ int n;
+ UINT8 *ptr;
+ int i, bpp;
+ int row_len;
+
+ if (!state->state) {
+ /* Initialization */
+ if (context->mode == ZIP_PNG || context->mode == ZIP_PNG_PALETTE) {
+ context->prefix = 1; /* PNG */
+ }
+
+ /* overflow check for malloc */
+ if (state->bytes > INT_MAX - 1) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+ /* Expand standard buffer to make room for the (optional) filter
+ prefix, and allocate a buffer to hold the previous line */
+ free(state->buffer);
+ /* malloc check ok, overflow checked above */
+ state->buffer = (UINT8 *)malloc(state->bytes + 1);
+ context->previous = (UINT8 *)malloc(state->bytes + 1);
+ if (!state->buffer || !context->previous) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+
+ context->last_output = 0;
+
+ /* Initialize to black */
+ memset(context->previous, 0, state->bytes + 1);
+
+ /* Setup decompression context */
+ context->z_stream.zalloc = (alloc_func)NULL;
+ context->z_stream.zfree = (free_func)NULL;
+ context->z_stream.opaque = (voidpf)NULL;
+
+ err = inflateInit(&context->z_stream);
+ if (err < 0) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ free(context->previous);
+ context->previous = NULL;
+ return -1;
+ }
+
+ if (context->interlaced) {
+ context->pass = 0;
+ state->y = STARTING_ROW[context->pass];
+ }
+
+ /* Ready to decode */
+ state->state = 1;
+ }
+
+ if (context->interlaced) {
+ row_len = get_row_len(state, context->pass);
+ } else {
+ row_len = state->bytes;
+ }
+
+ /* Setup the source buffer */
+ context->z_stream.next_in = buf;
+ context->z_stream.avail_in = bytes;
+
+ /* Decompress what we've got this far */
+ while (context->z_stream.avail_in > 0) {
+ context->z_stream.next_out = state->buffer + context->last_output;
+ context->z_stream.avail_out = row_len + context->prefix - context->last_output;
+
+ err = inflate(&context->z_stream, Z_NO_FLUSH);
+
+ if (err < 0) {
+ /* Something went wrong inside the compression library */
+ if (err == Z_DATA_ERROR) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ } else if (err == Z_MEM_ERROR) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ } else {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ }
+ free(context->previous);
+ context->previous = NULL;
+ inflateEnd(&context->z_stream);
+ return -1;
+ }
+
+ n = row_len + context->prefix - context->z_stream.avail_out;
+
+ if (n < row_len + context->prefix) {
+ context->last_output = n;
+ break; /* need more input data */
+ }
+
+ /* Apply predictor */
+ switch (context->mode) {
+ case ZIP_PNG:
+ switch (state->buffer[0]) {
+ case 0:
+ break;
+ case 1:
+ /* prior */
+ bpp = (state->bits + 7) / 8;
+ for (i = bpp + 1; i <= row_len; i++) {
+ state->buffer[i] += state->buffer[i - bpp];
+ }
+ break;
+ case 2:
+ /* up */
+ for (i = 1; i <= row_len; i++) {
+ state->buffer[i] += context->previous[i];
+ }
+ break;
+ case 3:
+ /* average */
+ bpp = (state->bits + 7) / 8;
+ for (i = 1; i <= bpp; i++) {
+ state->buffer[i] += context->previous[i] / 2;
+ }
+ for (; i <= row_len; i++) {
+ state->buffer[i] +=
+ (state->buffer[i - bpp] + context->previous[i]) / 2;
+ }
+ break;
+ case 4:
+ /* paeth filtering */
+ bpp = (state->bits + 7) / 8;
+ for (i = 1; i <= bpp; i++) {
+ state->buffer[i] += context->previous[i];
+ }
+ for (; i <= row_len; i++) {
+ int a, b, c;
+ int pa, pb, pc;
+
+ /* fetch pixels */
+ a = state->buffer[i - bpp];
+ b = context->previous[i];
+ c = context->previous[i - bpp];
+
+ /* distances to surrounding pixels */
+ pa = abs(b - c);
+ pb = abs(a - c);
+ pc = abs(a + b - 2 * c);
+
+ /* pick predictor with the shortest distance */
+ state->buffer[i] += (pa <= pb && pa <= pc) ? a
+ : (pb <= pc) ? b
+ : c;
+ }
+ break;
+ default:
+ state->errcode = IMAGING_CODEC_UNKNOWN;
+ free(context->previous);
+ context->previous = NULL;
+ inflateEnd(&context->z_stream);
+ return -1;
+ }
+ break;
+ case ZIP_TIFF_PREDICTOR:
+ bpp = (state->bits + 7) / 8;
+ for (i = bpp + 1; i <= row_len; i++) {
+ state->buffer[i] += state->buffer[i - bpp];
+ }
+ break;
+ }
+
+ /* Stuff data into the image */
+ if (context->interlaced) {
+ int col = STARTING_COL[context->pass];
+ if (state->bits >= 8) {
+ /* Stuff pixels in their correct location, one by one */
+ for (i = 0; i < row_len; i += ((state->bits + 7) / 8)) {
+ state->shuffle(
+ (UINT8 *)im->image[state->y] + col * im->pixelsize,
+ state->buffer + context->prefix + i,
+ 1);
+ col += COL_INCREMENT[context->pass];
+ }
+ } else {
+ /* Handle case with more than a pixel in each byte */
+ int row_bits = ((state->xsize + OFFSET[context->pass]) /
+ COL_INCREMENT[context->pass]) *
+ state->bits;
+ for (i = 0; i < row_bits; i += state->bits) {
+ UINT8 byte = *(state->buffer + context->prefix + (i / 8));
+ byte <<= (i % 8);
+ state->shuffle(
+ (UINT8 *)im->image[state->y] + col * im->pixelsize, &byte, 1);
+ col += COL_INCREMENT[context->pass];
+ }
+ }
+ /* Find next valid scanline */
+ state->y += ROW_INCREMENT[context->pass];
+ while (state->y >= state->ysize || row_len <= 0) {
+ context->pass++;
+ if (context->pass == 7) {
+ /* Force exit below */
+ state->y = state->ysize;
+ break;
+ }
+ state->y = STARTING_ROW[context->pass];
+ row_len = get_row_len(state, context->pass);
+ /* Since we're moving to the "first" line, the previous line
+ * should be black to make filters work correctly */
+ memset(state->buffer, 0, state->bytes + 1);
+ }
+ } else {
+ state->shuffle(
+ (UINT8 *)im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->buffer + context->prefix,
+ state->xsize);
+ state->y++;
+ }
+
+ /* all inflate output has been consumed */
+ context->last_output = 0;
+
+ if (state->y >= state->ysize || err == Z_STREAM_END) {
+ /* The image and the data should end simultaneously */
+ /* if (state->y < state->ysize || err != Z_STREAM_END)
+ state->errcode = IMAGING_CODEC_BROKEN; */
+
+ free(context->previous);
+ context->previous = NULL;
+ inflateEnd(&context->z_stream);
+ return -1; /* end of file (errcode=0) */
+ }
+
+ /* Swap buffer pointers */
+ ptr = state->buffer;
+ state->buffer = context->previous;
+ context->previous = ptr;
+ }
+
+ return bytes; /* consumed all of it */
+}
+
+int
+ImagingZipDecodeCleanup(ImagingCodecState state) {
+ /* called to free the decompression engine when the decode terminates
+ due to a corrupt or truncated image
+ */
+ ZIPSTATE *context = (ZIPSTATE *)state->context;
+
+ /* Clean up */
+ if (context->previous) {
+ inflateEnd(&context->z_stream);
+ free(context->previous);
+ context->previous = NULL;
+ }
+ return -1;
+}
+
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/ZipEncode.c b/contrib/python/Pillow/py3/libImaging/ZipEncode.c
new file mode 100644
index 00000000000..edbce36822c
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/ZipEncode.c
@@ -0,0 +1,367 @@
+/*
+ * The Python Imaging Library.
+ * $Id$
+ *
+ * coder for ZIP (deflated) image data
+ *
+ * History:
+ * 96-12-29 fl created
+ * 96-12-30 fl adaptive filter selection, encoder tuning
+ *
+ * Copyright (c) Fredrik Lundh 1996.
+ * Copyright (c) Secret Labs AB 1997.
+ *
+ * See the README file for information on usage and redistribution.
+ */
+
+#include "Imaging.h"
+
+#ifdef HAVE_LIBZ
+
+#include "ZipCodecs.h"
+
+int
+ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
+ ZIPSTATE *context = (ZIPSTATE *)state->context;
+ int err;
+ int compress_level, compress_type;
+ UINT8 *ptr;
+ int i, bpp, s, sum;
+ ImagingSectionCookie cookie;
+
+ if (!state->state) {
+ /* Initialization */
+
+ /* Valid modes are ZIP_PNG, ZIP_PNG_PALETTE, and ZIP_TIFF */
+
+ /* overflow check for malloc */
+ if (state->bytes > INT_MAX - 1) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+
+ /* Expand standard buffer to make room for the filter selector,
+ and allocate filter buffers */
+ free(state->buffer);
+ /* malloc check ok, overflow checked above */
+ state->buffer = (UINT8 *)malloc(state->bytes + 1);
+ context->previous = (UINT8 *)malloc(state->bytes + 1);
+ context->prior = (UINT8 *)malloc(state->bytes + 1);
+ context->up = (UINT8 *)malloc(state->bytes + 1);
+ context->average = (UINT8 *)malloc(state->bytes + 1);
+ context->paeth = (UINT8 *)malloc(state->bytes + 1);
+ if (!state->buffer || !context->previous || !context->prior || !context->up ||
+ !context->average || !context->paeth) {
+ free(context->paeth);
+ free(context->average);
+ free(context->up);
+ free(context->prior);
+ free(context->previous);
+ state->errcode = IMAGING_CODEC_MEMORY;
+ return -1;
+ }
+
+ /* Initialise filter buffers */
+ state->buffer[0] = 0;
+ context->prior[0] = 1;
+ context->up[0] = 2;
+ context->average[0] = 3;
+ context->paeth[0] = 4;
+
+ /* Initialise previous buffer to black */
+ memset(context->previous, 0, state->bytes + 1);
+
+ /* Setup compression context */
+ context->z_stream.zalloc = (alloc_func)0;
+ context->z_stream.zfree = (free_func)0;
+ context->z_stream.opaque = (voidpf)0;
+ context->z_stream.next_in = 0;
+ context->z_stream.avail_in = 0;
+
+ compress_level =
+ (context->optimize) ? Z_BEST_COMPRESSION : context->compress_level;
+
+ if (context->compress_type == -1) {
+ compress_type =
+ (context->mode == ZIP_PNG) ? Z_FILTERED : Z_DEFAULT_STRATEGY;
+ } else {
+ compress_type = context->compress_type;
+ }
+
+ err = deflateInit2(
+ &context->z_stream,
+ /* compression level */
+ compress_level,
+ /* compression method */
+ Z_DEFLATED,
+ /* compression memory resources */
+ 15,
+ 9,
+ /* compression strategy (image data are filtered)*/
+ compress_type);
+ if (err < 0) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+
+ if (context->dictionary && context->dictionary_size > 0) {
+ err = deflateSetDictionary(
+ &context->z_stream,
+ (unsigned char *)context->dictionary,
+ context->dictionary_size);
+ if (err < 0) {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ return -1;
+ }
+ }
+
+ /* Ready to decode */
+ state->state = 1;
+ }
+
+ /* Setup the destination buffer */
+ context->z_stream.next_out = buf;
+ context->z_stream.avail_out = bytes;
+ if (context->z_stream.next_in && context->z_stream.avail_in > 0) {
+ /* We have some data from previous round, deflate it first */
+ err = deflate(&context->z_stream, Z_NO_FLUSH);
+
+ if (err < 0) {
+ /* Something went wrong inside the compression library */
+ if (err == Z_DATA_ERROR) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ } else if (err == Z_MEM_ERROR) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ } else {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ }
+ free(context->paeth);
+ free(context->average);
+ free(context->up);
+ free(context->prior);
+ free(context->previous);
+ deflateEnd(&context->z_stream);
+ return -1;
+ }
+ }
+
+ ImagingSectionEnter(&cookie);
+ for (;;) {
+ switch (state->state) {
+ case 1:
+
+ /* Compress image data */
+ while (context->z_stream.avail_out > 0) {
+ if (state->y >= state->ysize) {
+ /* End of image; now flush compressor buffers */
+ state->state = 2;
+ break;
+ }
+
+ /* Stuff image data into the compressor */
+ state->shuffle(
+ state->buffer + 1,
+ (UINT8 *)im->image[state->y + state->yoff] +
+ state->xoff * im->pixelsize,
+ state->xsize);
+
+ state->y++;
+
+ context->output = state->buffer;
+
+ if (context->mode == ZIP_PNG) {
+ /* Filter the image data. For each line, select
+ the filter that gives the least total distance
+ from zero for the filtered data (taken from
+ LIBPNG) */
+
+ bpp = (state->bits + 7) / 8;
+
+ /* 0. No filter */
+ for (i = 1, sum = 0; i <= state->bytes; i++) {
+ UINT8 v = state->buffer[i];
+ sum += (v < 128) ? v : 256 - v;
+ }
+
+ /* 2. Up. We'll test this first to save time when
+ an image line is identical to the one above. */
+ if (sum > 0) {
+ for (i = 1, s = 0; i <= state->bytes; i++) {
+ UINT8 v = state->buffer[i] - context->previous[i];
+ context->up[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ if (s < sum) {
+ context->output = context->up;
+ sum = s; /* 0 if line was duplicated */
+ }
+ }
+
+ /* 1. Prior */
+ if (sum > 0) {
+ for (i = 1, s = 0; i <= bpp; i++) {
+ UINT8 v = state->buffer[i];
+ context->prior[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ for (; i <= state->bytes; i++) {
+ UINT8 v = state->buffer[i] - state->buffer[i - bpp];
+ context->prior[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ if (s < sum) {
+ context->output = context->prior;
+ sum = s; /* 0 if line is solid */
+ }
+ }
+
+ /* 3. Average (not very common in real-life images,
+ so its only used with the optimize option) */
+ if (context->optimize && sum > 0) {
+ for (i = 1, s = 0; i <= bpp; i++) {
+ UINT8 v = state->buffer[i] - context->previous[i] / 2;
+ context->average[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ for (; i <= state->bytes; i++) {
+ UINT8 v =
+ state->buffer[i] -
+ (state->buffer[i - bpp] + context->previous[i]) / 2;
+ context->average[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ if (s < sum) {
+ context->output = context->average;
+ sum = s;
+ }
+ }
+
+ /* 4. Paeth */
+ if (sum > 0) {
+ for (i = 1, s = 0; i <= bpp; i++) {
+ UINT8 v = state->buffer[i] - context->previous[i];
+ context->paeth[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ for (; i <= state->bytes; i++) {
+ UINT8 v;
+ int a, b, c;
+ int pa, pb, pc;
+
+ /* fetch pixels */
+ a = state->buffer[i - bpp];
+ b = context->previous[i];
+ c = context->previous[i - bpp];
+
+ /* distances to surrounding pixels */
+ pa = abs(b - c);
+ pb = abs(a - c);
+ pc = abs(a + b - 2 * c);
+
+ /* pick predictor with the shortest distance */
+ v = state->buffer[i] - ((pa <= pb && pa <= pc) ? a
+ : (pb <= pc) ? b
+ : c);
+ context->paeth[i] = v;
+ s += (v < 128) ? v : 256 - v;
+ }
+ if (s < sum) {
+ context->output = context->paeth;
+ sum = s;
+ }
+ }
+ }
+
+ /* Compress this line */
+ context->z_stream.next_in = context->output;
+ context->z_stream.avail_in = state->bytes + 1;
+
+ err = deflate(&context->z_stream, Z_NO_FLUSH);
+
+ if (err < 0) {
+ /* Something went wrong inside the compression library */
+ if (err == Z_DATA_ERROR) {
+ state->errcode = IMAGING_CODEC_BROKEN;
+ } else if (err == Z_MEM_ERROR) {
+ state->errcode = IMAGING_CODEC_MEMORY;
+ } else {
+ state->errcode = IMAGING_CODEC_CONFIG;
+ }
+ free(context->paeth);
+ free(context->average);
+ free(context->up);
+ free(context->prior);
+ free(context->previous);
+ deflateEnd(&context->z_stream);
+ ImagingSectionLeave(&cookie);
+ return -1;
+ }
+
+ /* Swap buffer pointers */
+ ptr = state->buffer;
+ state->buffer = context->previous;
+ context->previous = ptr;
+ }
+
+ if (context->z_stream.avail_out == 0) {
+ break; /* Buffer full */
+ }
+
+ case 2:
+
+ /* End of image data; flush compressor buffers */
+
+ while (context->z_stream.avail_out > 0) {
+ err = deflate(&context->z_stream, Z_FINISH);
+
+ if (err == Z_STREAM_END) {
+ free(context->paeth);
+ free(context->average);
+ free(context->up);
+ free(context->prior);
+ free(context->previous);
+
+ deflateEnd(&context->z_stream);
+
+ state->errcode = IMAGING_CODEC_END;
+
+ break;
+ }
+
+ if (context->z_stream.avail_out == 0) {
+ break; /* Buffer full */
+ }
+ }
+ }
+ ImagingSectionLeave(&cookie);
+ return bytes - context->z_stream.avail_out;
+ }
+
+ /* Should never ever arrive here... */
+ state->errcode = IMAGING_CODEC_CONFIG;
+ ImagingSectionLeave(&cookie);
+ return -1;
+}
+
+/* -------------------------------------------------------------------- */
+/* Cleanup */
+/* -------------------------------------------------------------------- */
+
+int
+ImagingZipEncodeCleanup(ImagingCodecState state) {
+ ZIPSTATE *context = (ZIPSTATE *)state->context;
+
+ if (context->dictionary) {
+ free(context->dictionary);
+ context->dictionary = NULL;
+ }
+
+ return -1;
+}
+
+const char *
+ImagingZipVersion(void) {
+ return zlibVersion();
+}
+
+#endif
diff --git a/contrib/python/Pillow/py3/libImaging/codec_fd.c b/contrib/python/Pillow/py3/libImaging/codec_fd.c
new file mode 100644
index 00000000000..5261681107b
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/codec_fd.c
@@ -0,0 +1,69 @@
+#include "Python.h"
+#include "Imaging.h"
+
+Py_ssize_t
+_imaging_read_pyFd(PyObject *fd, char *dest, Py_ssize_t bytes) {
+ /* dest should be a buffer bytes long, returns length of read
+ -1 on error */
+
+ PyObject *result;
+ char *buffer;
+ Py_ssize_t length;
+ int bytes_result;
+
+ result = PyObject_CallMethod(fd, "read", "n", bytes);
+
+ bytes_result = PyBytes_AsStringAndSize(result, &buffer, &length);
+ if (bytes_result == -1) {
+ goto err;
+ }
+
+ if (length > bytes) {
+ goto err;
+ }
+
+ memcpy(dest, buffer, length);
+
+ Py_DECREF(result);
+ return length;
+
+err:
+ Py_DECREF(result);
+ return -1;
+}
+
+Py_ssize_t
+_imaging_write_pyFd(PyObject *fd, char *src, Py_ssize_t bytes) {
+ PyObject *result;
+ PyObject *byteObj;
+
+ byteObj = PyBytes_FromStringAndSize(src, bytes);
+ result = PyObject_CallMethod(fd, "write", "O", byteObj);
+
+ Py_DECREF(byteObj);
+ Py_DECREF(result);
+
+ return bytes;
+}
+
+int
+_imaging_seek_pyFd(PyObject *fd, Py_ssize_t offset, int whence) {
+ PyObject *result;
+
+ result = PyObject_CallMethod(fd, "seek", "ni", offset, whence);
+
+ Py_DECREF(result);
+ return 0;
+}
+
+Py_ssize_t
+_imaging_tell_pyFd(PyObject *fd) {
+ PyObject *result;
+ Py_ssize_t location;
+
+ result = PyObject_CallMethod(fd, "tell", NULL);
+ location = PyLong_AsSsize_t(result);
+
+ Py_DECREF(result);
+ return location;
+}