From 91b08b7daa9b8bbdb951a16ff3f73c1e39879a37 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sat, 12 Aug 2017 19:08:07 +0300 Subject: [PATCH 1/5] noop core.merge --- PIL/Image.py | 8 +++----- _imaging.c | 24 ++++++++++++++++++++++++ libImaging/Bands.c | 39 +++++++++++++++++++++++++++++++++++++++ libImaging/Imaging.h | 1 + 4 files changed, 67 insertions(+), 5 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index 49c9f6ab2..5fdf7e99b 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -2612,11 +2612,9 @@ def merge(mode, bands): raise ValueError("mode mismatch") if im.size != bands[0].size: raise ValueError("size mismatch") - im = core.new(mode, bands[0].size) - for i in range(getmodebands(mode)): - bands[i].load() - im.putband(bands[i].im, i) - return bands[0]._new(im) + for band in bands: + band.load() + return bands[0]._new(core.merge(mode, *[b.im for b in bands])) # -------------------------------------------------------------------- diff --git a/_imaging.c b/_imaging.c index 7b3380b40..1dc803fc9 100644 --- a/_imaging.c +++ b/_imaging.c @@ -1905,6 +1905,29 @@ _putband(ImagingObject* self, PyObject* args) return Py_None; } +static PyObject* +_merge(PyObject* self, PyObject* args) +{ + char* mode; + ImagingObject *band0 = NULL; + ImagingObject *band1 = NULL; + ImagingObject *band2 = NULL; + ImagingObject *band3 = NULL; + Imaging bands[4] = {NULL, NULL, NULL, NULL}; + + if (!PyArg_ParseTuple(args, "sO!|O!O!O!", &mode, + &Imaging_Type, &band0, &Imaging_Type, &band1, + &Imaging_Type, &band2, &Imaging_Type, &band3)) + return NULL; + + if (band0) bands[0] = band0->image; + if (band1) bands[1] = band1->image; + if (band2) bands[2] = band2->image; + if (band3) bands[3] = band3->image; + + return PyImagingNew(ImagingMerge(mode, bands)); +} + /* -------------------------------------------------------------------- */ #ifdef WITH_IMAGECHOPS @@ -3316,6 +3339,7 @@ static PyMethodDef functions[] = { {"blend", (PyCFunction)_blend, 1}, {"fill", (PyCFunction)_fill, 1}, {"new", (PyCFunction)_new, 1}, + {"merge", (PyCFunction)_merge, 1}, {"getcount", (PyCFunction)_getcount, 1}, diff --git a/libImaging/Bands.c b/libImaging/Bands.c index d7424ab25..9dac17b68 100644 --- a/libImaging/Bands.c +++ b/libImaging/Bands.c @@ -127,3 +127,42 @@ ImagingFillBand(Imaging imOut, int band, int color) return imOut; } + +Imaging +ImagingMerge(const char* mode, Imaging bands[4]) +{ + int i; + int bandsCount = 0; + Imaging imOut; + Imaging firstBand; + + firstBand = bands[0]; + if ( ! firstBand) { + return (Imaging) ImagingError_ValueError("At least one band required"); + } + + for (i = 0; i < 4; ++i) { + if ( ! bands[i]) { + break; + } + if (bands[i]->bands != 1 || bands[i]->type != IMAGING_TYPE_UINT8) { + return (Imaging) ImagingError_ModeError(); + } + if (bands[i]->xsize != firstBand->xsize + || bands[i]->ysize != firstBand->ysize) { + return (Imaging) ImagingError_Mismatch(); + } + } + bandsCount = i; + + imOut = ImagingNew(mode, firstBand->xsize, firstBand->ysize); + if ( ! imOut) + return NULL; + + if (imOut->bands != bandsCount) { + ImagingDelete(imOut); + return (Imaging) ImagingError_ValueError("wrong number of bands"); + } + + return imOut; +} diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index 99fff7f67..f4ff3c345 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -267,6 +267,7 @@ extern Imaging ImagingFlipTopBottom(Imaging imOut, Imaging imIn); extern Imaging ImagingGaussianBlur(Imaging imOut, Imaging imIn, float radius, int passes); extern Imaging ImagingGetBand(Imaging im, int band); +extern Imaging ImagingMerge(const char* mode, Imaging bands[4]); extern int ImagingGetBBox(Imaging im, int bbox[4]); typedef struct { int x, y; INT32 count; INT32 pixel; } ImagingColorItem; extern ImagingColorItem* ImagingGetColors(Imaging im, int maxcolors, From a2681a069074bbf381f0728298fcd8a5e9367638 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sat, 12 Aug 2017 19:17:21 +0300 Subject: [PATCH 2/5] naive implementation --- libImaging/Bands.c | 48 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/libImaging/Bands.c b/libImaging/Bands.c index 9dac17b68..32823d76d 100644 --- a/libImaging/Bands.c +++ b/libImaging/Bands.c @@ -131,14 +131,14 @@ ImagingFillBand(Imaging imOut, int band, int color) Imaging ImagingMerge(const char* mode, Imaging bands[4]) { - int i; + int i, x, y; int bandsCount = 0; Imaging imOut; Imaging firstBand; firstBand = bands[0]; if ( ! firstBand) { - return (Imaging) ImagingError_ValueError("At least one band required"); + return (Imaging) ImagingError_ValueError("wrong number of bands"); } for (i = 0; i < 4; ++i) { @@ -164,5 +164,49 @@ ImagingMerge(const char* mode, Imaging bands[4]) 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]; + UINT8* out = (UINT8*) imOut->image[y]; + for (x = 0; x < imOut->xsize; x++) { + out[0] = *in0; + out[3] = *in1; + out += 4; + } + } + } 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]; + UINT8* out = (UINT8*) imOut->image[y]; + for (x = 0; x < imOut->xsize; x++) { + out[0] = *in0; + out[1] = *in1; + out[2] = *in2; + out += 4; + } + } + } 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]; + UINT8* out = (UINT8*) imOut->image[y]; + for (x = 0; x < imOut->xsize; x++) { + out[0] = *in0; + out[1] = *in1; + out[2] = *in2; + out[3] = *in3; + out += 4; + } + } + } + return imOut; } From b454f773bde7a98d4b0140ac7049ddfb827e0bd1 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sat, 12 Aug 2017 19:36:56 +0300 Subject: [PATCH 3/5] make things faster --- libImaging/Bands.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/libImaging/Bands.c b/libImaging/Bands.c index 32823d76d..9cebd3f5c 100644 --- a/libImaging/Bands.c +++ b/libImaging/Bands.c @@ -22,6 +22,17 @@ #define CLIP(x) ((x) <= 0 ? 0 : (x) < 256 ? (x) : 255) +#ifdef WORDS_BIGENDIAN + #define MAKE_UINT32(u0, u1, u2, u3) (u3 | (u2<<8) | (u1<<16) | (u0<<24)) + #define MAKE_UINT32_3(u0, u1, u2) ((u2<<8) | (u1<<16) | (u0<<24)) + #define MAKE_UINT32_2(u0, u3) (u3 | (u0<<24)) +#else + #define MAKE_UINT32(u0, u1, u2, u3) (u0 | (u1<<8) | (u2<<16) | (u3<<24)) + #define MAKE_UINT32_3(u0, u1, u2) (u0 | (u1<<8) | (u2<<16)) + #define MAKE_UINT32_2(u0, u3) (u0 | (u3<<24)) +#endif + + Imaging ImagingGetBand(Imaging imIn, int band) { @@ -145,7 +156,7 @@ ImagingMerge(const char* mode, Imaging bands[4]) if ( ! bands[i]) { break; } - if (bands[i]->bands != 1 || bands[i]->type != IMAGING_TYPE_UINT8) { + if (bands[i]->bands != 1) { return (Imaging) ImagingError_ModeError(); } if (bands[i]->xsize != firstBand->xsize @@ -171,11 +182,9 @@ ImagingMerge(const char* mode, Imaging bands[4]) for (y = 0; y < imOut->ysize; y++) { UINT8* in0 = bands[0]->image8[y]; UINT8* in1 = bands[1]->image8[y]; - UINT8* out = (UINT8*) imOut->image[y]; + UINT32* out = (UINT32*) imOut->image32[y]; for (x = 0; x < imOut->xsize; x++) { - out[0] = *in0; - out[3] = *in1; - out += 4; + out[x] = MAKE_UINT32_2(in0[x], in1[x]); } } } else if (imOut->bands == 3) { @@ -183,12 +192,9 @@ ImagingMerge(const char* mode, Imaging bands[4]) UINT8* in0 = bands[0]->image8[y]; UINT8* in1 = bands[1]->image8[y]; UINT8* in2 = bands[2]->image8[y]; - UINT8* out = (UINT8*) imOut->image[y]; + UINT32* out = (UINT32*) imOut->image32[y]; for (x = 0; x < imOut->xsize; x++) { - out[0] = *in0; - out[1] = *in1; - out[2] = *in2; - out += 4; + out[x] = MAKE_UINT32_3(in0[x], in1[x], in2[x]); } } } else if (imOut->bands == 4) { @@ -197,13 +203,9 @@ ImagingMerge(const char* mode, Imaging bands[4]) UINT8* in1 = bands[1]->image8[y]; UINT8* in2 = bands[2]->image8[y]; UINT8* in3 = bands[3]->image8[y]; - UINT8* out = (UINT8*) imOut->image[y]; + UINT32* out = (UINT32*) imOut->image32[y]; for (x = 0; x < imOut->xsize; x++) { - out[0] = *in0; - out[1] = *in1; - out[2] = *in2; - out[3] = *in3; - out += 4; + out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], in3[x]); } } } From 7c3c3273eb8884c6cc63a2ee776a3601ea9003c7 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sat, 12 Aug 2017 19:41:18 +0300 Subject: [PATCH 4/5] compiler makes this for me --- libImaging/Bands.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libImaging/Bands.c b/libImaging/Bands.c index 9cebd3f5c..8bde5efe8 100644 --- a/libImaging/Bands.c +++ b/libImaging/Bands.c @@ -24,12 +24,8 @@ #ifdef WORDS_BIGENDIAN #define MAKE_UINT32(u0, u1, u2, u3) (u3 | (u2<<8) | (u1<<16) | (u0<<24)) - #define MAKE_UINT32_3(u0, u1, u2) ((u2<<8) | (u1<<16) | (u0<<24)) - #define MAKE_UINT32_2(u0, u3) (u3 | (u0<<24)) #else #define MAKE_UINT32(u0, u1, u2, u3) (u0 | (u1<<8) | (u2<<16) | (u3<<24)) - #define MAKE_UINT32_3(u0, u1, u2) (u0 | (u1<<8) | (u2<<16)) - #define MAKE_UINT32_2(u0, u3) (u0 | (u3<<24)) #endif @@ -184,7 +180,7 @@ ImagingMerge(const char* mode, Imaging bands[4]) UINT8* in1 = bands[1]->image8[y]; UINT32* out = (UINT32*) imOut->image32[y]; for (x = 0; x < imOut->xsize; x++) { - out[x] = MAKE_UINT32_2(in0[x], in1[x]); + out[x] = MAKE_UINT32(in0[x], 0, 0, in1[x]); } } } else if (imOut->bands == 3) { @@ -194,7 +190,7 @@ ImagingMerge(const char* mode, Imaging bands[4]) UINT8* in2 = bands[2]->image8[y]; UINT32* out = (UINT32*) imOut->image32[y]; for (x = 0; x < imOut->xsize; x++) { - out[x] = MAKE_UINT32_3(in0[x], in1[x], in2[x]); + out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], 0); } } } else if (imOut->bands == 4) { From 4af4256ac3b467fa8d1c9fa847ac6dd0c877a7d9 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 17 Aug 2017 12:14:19 +0300 Subject: [PATCH 5/5] Use ImagingNewDirty --- libImaging/Bands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libImaging/Bands.c b/libImaging/Bands.c index 1c1a2ed80..758734b52 100644 --- a/libImaging/Bands.c +++ b/libImaging/Bands.c @@ -262,7 +262,7 @@ ImagingMerge(const char* mode, Imaging bands[4]) } bandsCount = i; - imOut = ImagingNew(mode, firstBand->xsize, firstBand->ysize); + imOut = ImagingNewDirty(mode, firstBand->xsize, firstBand->ysize); if ( ! imOut) return NULL;