From d030b4f48a7ec3cee2538769cea9f96042e480d5 Mon Sep 17 00:00:00 2001 From: nikmolnar Date: Fri, 22 Nov 2013 16:04:51 -0800 Subject: [PATCH 1/7] Added a test for issue #421 --- Tests/images/rgb_trns.png | Bin 0 -> 1595 bytes Tests/test_file_png.py | 11 +++++++++++ 2 files changed, 11 insertions(+) create mode 100644 Tests/images/rgb_trns.png diff --git a/Tests/images/rgb_trns.png b/Tests/images/rgb_trns.png new file mode 100644 index 0000000000000000000000000000000000000000..dee80acdcfe1cfb46d52a4fb1070d18aa5237216 GIT binary patch literal 1595 zcmV-B2E_S^P)00006bW%=J00030 z05tK6$H@Qy1@K8kK~#90&DvXz+DI6N;kVq?4cOQ~)14tvC(2|Ev##0P>|!>Mxfv-^ zqNt-j0501cGPvf#HW;5dhF=y!-1zbDa$$dEp(&{c00z*7!4>8T2W*3GNSAms(S1Wi zzgR+>TG(g{C2(N^3z)(jUXxEB0&u|v;9mefZ|~V-2*4fK1G-~6a0`8CK@V(jpanMA zvR>b&Sl>fiDScmyR)IdCHDPgpehBR{Jvc=N(4_Yny{U!6;+h3#)fb(CJ@kDo9JDOf zk70I9y`3CD^xYO)*FdelZ(xOaeZKc&j2Ynx^bXvt^+O!vlJyq7YW)k{^V}ptA zA=xYRR#ScH$Gr{=fdW(Ku zFNHJ0A=%P;!`ExQHPdpf*Mm@W57K*Ff9EGV>V4XIJvfg^`z!Pv7pWbDjqYyi2WYcO zKZV);`Vp8py$!7YY1%lh>2d>R6P0u#mGfA(NAE$yFNA9*XY59_LhDoKL+8KnX#o0AYi2Q zTK^az8KBLLUiS#C$4red!-{iQ_A$rkeS}E?=j~^`t`rnsq4McUp)~;1NVx+g;{|f z7n$z;h3J8d-k;$p+=!mifATPP(ofHJ1kLn-EYojCQCsu_dV1I87D6?b#T@{CM?{88yIfxwNUs3?>jjd@g?>5|6dzPH4I4mi-cPR_vo0dgvWE!3l!yMo{( zdgEsxn@6y<0rFE2>v54Pv8H0cBkC*r1N<`tb9{X#Prc;L#MzGu-sO8lLUV53Kqo%91}Z|jF}6ZbyW zgC}eC;5=^L5!vX=0%T^fJ{<#&f-1eWjQ6*thXHh!(Ne2+5P3Z)S*xd9Ult$-xe#+t zJvDmp47iQ-&>Ph0@kCl52guW!06G0oTcN+L(}T+BVJt1$e*9ih>swZzdcSKX@x;*A zX?EwAvic|leT^4ClFcaB z+i5*2UiM+id!?gwhokG?K(9*gf395w4%)vyd(GCY2(ZR-hc^qv0fGG!IQh{ zqu$HtN^Km$X5x^vzB{KK{j#%u48BpKx6}G}6P?$`@%LeRXO4M*9(-A%*J=HCUliyM z=>7dFzD?Mx_v2)jKCSowO7x0%ZlYJ<9jaf4ITiZw#x<5+BmK=-FVtoT4WlnR>KjI| tC($pJz!T_yn)cqs3NEJi%V<)c{|{@E6cjrEE#?3K002ovPDHLkV1f;FAPxWk literal 0 HcmV?d00001 diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index 5ae726ad8..98f2cec6d 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -150,6 +150,17 @@ def test_load_transparent_p(): # image has 124 uniqe qlpha values assert_equal(len(im.split()[3].getcolors()), 124) +def test_load_transparent_rgb(): + file = "Tests/images/rgb_trns.png" + im = Image.open(file) + + assert_image(im, "RGB", (64, 64)) + im = im.convert("RGBA") + assert_image(im, "RGBA", (64, 64)) + + # image has 867 transparent pixels + assert_equal(im.split()[3].getcolors()[0][0], 867) + def test_save_p_transparent_palette(): in_file = "Tests/images/pil123p.png" im = Image.open(in_file) From c6cfd02f8f5b11f18821360a421b4e7e13c013fb Mon Sep 17 00:00:00 2001 From: wiredfool Date: Mon, 25 Nov 2013 16:25:06 -0800 Subject: [PATCH 2/7] more consistent 4space indent --- _imaging.c | 390 ++++++++++++++++++++++++++--------------------------- 1 file changed, 194 insertions(+), 196 deletions(-) diff --git a/_imaging.c b/_imaging.c index e792ebfa5..8a7761055 100644 --- a/_imaging.c +++ b/_imaging.c @@ -168,12 +168,12 @@ PyImagingNew(Imaging imOut) ImagingObject* imagep; if (!imOut) - return NULL; + return NULL; imagep = PyObject_New(ImagingObject, &Imaging_Type); if (imagep == NULL) { - ImagingDelete(imOut); - return NULL; + ImagingDelete(imOut); + return NULL; } #ifdef VERBOSE @@ -195,7 +195,7 @@ _dealloc(ImagingObject* imagep) #endif if (imagep->access) - ImagingAccessDelete(imagep->image, imagep->access); + ImagingAccessDelete(imagep->image, imagep->access); ImagingDelete(imagep->image); PyObject_Del(imagep); } @@ -205,8 +205,8 @@ _dealloc(ImagingObject* imagep) Imaging PyImaging_AsImaging(PyObject *op) { if (!PyImaging_Check(op)) { - PyErr_BadInternalCall(); - return NULL; + PyErr_BadInternalCall(); + return NULL; } return ((ImagingObject *)op)->image; @@ -369,14 +369,14 @@ getlist(PyObject* arg, int* length, const char* wrong_length, int type) void* list; if (!PySequence_Check(arg)) { - PyErr_SetString(PyExc_TypeError, must_be_sequence); - return NULL; + PyErr_SetString(PyExc_TypeError, must_be_sequence); + return NULL; } n = PyObject_Length(arg); if (length && wrong_length && n != *length) { - PyErr_SetString(PyExc_ValueError, wrong_length); - return NULL; + PyErr_SetString(PyExc_ValueError, wrong_length); + return NULL; } list = malloc(n * (type & 0xff)); @@ -469,33 +469,33 @@ getpixel(Imaging im, ImagingAccess access, int x, int y) } pixel; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) { - PyErr_SetString(PyExc_IndexError, outside_image); - return NULL; + PyErr_SetString(PyExc_IndexError, outside_image); + return NULL; } access->get_pixel(im, x, y, &pixel); switch (im->type) { case IMAGING_TYPE_UINT8: - switch (im->bands) { - case 1: - return PyInt_FromLong(pixel.b[0]); - case 2: - return Py_BuildValue("BB", pixel.b[0], pixel.b[1]); - case 3: - return Py_BuildValue("BBB", pixel.b[0], pixel.b[1], pixel.b[2]); - case 4: - return Py_BuildValue("BBBB", pixel.b[0], pixel.b[1], pixel.b[2], pixel.b[3]); - } - break; + switch (im->bands) { + case 1: + return PyInt_FromLong(pixel.b[0]); + case 2: + return Py_BuildValue("BB", pixel.b[0], pixel.b[1]); + case 3: + return Py_BuildValue("BBB", pixel.b[0], pixel.b[1], pixel.b[2]); + case 4: + return Py_BuildValue("BBBB", pixel.b[0], pixel.b[1], pixel.b[2], pixel.b[3]); + } + break; case IMAGING_TYPE_INT32: - return PyInt_FromLong(pixel.i); + return PyInt_FromLong(pixel.i); case IMAGING_TYPE_FLOAT32: - return PyFloat_FromDouble(pixel.f); + return PyFloat_FromDouble(pixel.f); case IMAGING_TYPE_SPECIAL: - if (strncmp(im->mode, "I;16", 4) == 0) - return PyInt_FromLong(pixel.h); - break; + if (strncmp(im->mode, "I;16", 4) == 0) + return PyInt_FromLong(pixel.h); + break; } /* unknown type */ @@ -603,7 +603,7 @@ _fill(PyObject* self, PyObject* args) color = NULL; if (!PyArg_ParseTuple(args, "s|(ii)O", &mode, &xsize, &ysize, &color)) - return NULL; + return NULL; im = ImagingNew(mode, xsize, ysize); if (!im) @@ -629,7 +629,7 @@ _new(PyObject* self, PyObject* args) int xsize, ysize; if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize)) - return NULL; + return NULL; return PyImagingNew(ImagingNew(mode, xsize, ysize)); } @@ -641,7 +641,7 @@ _new_array(PyObject* self, PyObject* args) int xsize, ysize; if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize)) - return NULL; + return NULL; return PyImagingNew(ImagingNewArray(mode, xsize, ysize)); } @@ -653,7 +653,7 @@ _new_block(PyObject* self, PyObject* args) int xsize, ysize; if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize)) - return NULL; + return NULL; return PyImagingNew(ImagingNewBlock(mode, xsize, ysize)); } @@ -662,7 +662,7 @@ static PyObject* _getcount(PyObject* self, PyObject* args) { if (!PyArg_ParseTuple(args, ":getcount")) - return NULL; + return NULL; return PyInt_FromLong(ImagingNewCount); } @@ -673,7 +673,7 @@ _linear_gradient(PyObject* self, PyObject* args) char* mode; if (!PyArg_ParseTuple(args, "s", &mode)) - return NULL; + return NULL; return PyImagingNew(ImagingFillLinearGradient(mode)); } @@ -684,7 +684,7 @@ _radial_gradient(PyObject* self, PyObject* args) char* mode; if (!PyArg_ParseTuple(args, "s", &mode)) - return NULL; + return NULL; return PyImagingNew(ImagingFillRadialGradient(mode)); } @@ -695,7 +695,7 @@ _open_ppm(PyObject* self, PyObject* args) char* filename; if (!PyArg_ParseTuple(args, "s", &filename)) - return NULL; + return NULL; return PyImagingNew(ImagingOpenPPM(filename)); } @@ -709,7 +709,7 @@ _alpha_composite(ImagingObject* self, PyObject* args) if (!PyArg_ParseTuple(args, "O!O!", &Imaging_Type, &imagep1, &Imaging_Type, &imagep2)) - return NULL; + return NULL; return PyImagingNew(ImagingAlphaComposite(imagep1->image, imagep2->image)); } @@ -723,10 +723,10 @@ _blend(ImagingObject* self, PyObject* args) alpha = 0.5; if (!PyArg_ParseTuple(args, "O!O!|d", - &Imaging_Type, &imagep1, - &Imaging_Type, &imagep2, - &alpha)) - return NULL; + &Imaging_Type, &imagep1, + &Imaging_Type, &imagep2, + &alpha)) + return NULL; return PyImagingNew(ImagingBlend(imagep1->image, imagep2->image, (float) alpha)); @@ -744,17 +744,17 @@ _convert(ImagingObject* self, PyObject* args) ImagingObject *paletteimage = NULL; if (!PyArg_ParseTuple(args, "s|iO", &mode, &dither, &paletteimage)) - return NULL; + return NULL; if (paletteimage != NULL) { - if (!PyImaging_Check(paletteimage)) { - PyObject_Print((PyObject *)paletteimage, stderr, 0); - PyErr_SetString(PyExc_ValueError, "palette argument must be image with mode 'P'"); - return NULL; - } - if (paletteimage->image->palette == NULL) { - PyErr_SetString(PyExc_ValueError, "null palette"); - return NULL; - } + if (!PyImaging_Check(paletteimage)) { + PyObject_Print((PyObject *)paletteimage, stderr, 0); + PyErr_SetString(PyExc_ValueError, "palette argument must be image with mode 'P'"); + return NULL; + } + if (paletteimage->image->palette == NULL) { + PyErr_SetString(PyExc_ValueError, "null palette"); + return NULL; + } } return PyImagingNew(ImagingConvert(self->image, mode, paletteimage ? paletteimage->image->palette : NULL, dither)); @@ -766,9 +766,9 @@ _convert2(ImagingObject* self, PyObject* args) ImagingObject* imagep1; ImagingObject* imagep2; if (!PyArg_ParseTuple(args, "O!O!", - &Imaging_Type, &imagep1, - &Imaging_Type, &imagep2)) - return NULL; + &Imaging_Type, &imagep1, + &Imaging_Type, &imagep2)) + return NULL; if (!ImagingConvert2(imagep1->image, imagep2->image)) return NULL; @@ -798,7 +798,7 @@ static PyObject* _copy(ImagingObject* self, PyObject* args) { if (!PyArg_ParseTuple(args, "")) - return NULL; + return NULL; return PyImagingNew(ImagingCopy(self->image)); } @@ -809,9 +809,9 @@ _copy2(ImagingObject* self, PyObject* args) ImagingObject* imagep1; ImagingObject* imagep2; if (!PyArg_ParseTuple(args, "O!O!", - &Imaging_Type, &imagep1, - &Imaging_Type, &imagep2)) - return NULL; + &Imaging_Type, &imagep1, + &Imaging_Type, &imagep2)) + return NULL; if (!ImagingCopy2(imagep1->image, imagep2->image)) return NULL; @@ -825,7 +825,7 @@ _crop(ImagingObject* self, PyObject* args) { int x0, y0, x1, y1; if (!PyArg_ParseTuple(args, "(iiii)", &x0, &y0, &x1, &y1)) - return NULL; + return NULL; return PyImagingNew(ImagingCrop(self->image, x0, y0, x1, y1)); } @@ -836,7 +836,7 @@ _expand(ImagingObject* self, PyObject* args) int x, y; int mode = 0; if (!PyArg_ParseTuple(args, "ii|i", &x, &y, &mode)) - return NULL; + return NULL; return PyImagingNew(ImagingExpand(self->image, x, y, mode)); } @@ -852,7 +852,7 @@ _filter(ImagingObject* self, PyObject* args) float divisor, offset; PyObject* kernel = NULL; if (!PyArg_ParseTuple(args, "(ii)ffO", &xsize, &ysize, - &divisor, &offset, &kernel)) + &divisor, &offset, &kernel)) return NULL; /* get user-defined kernel */ @@ -907,25 +907,25 @@ _getpalette(ImagingObject* self, PyObject* args) char* mode = "RGB"; char* rawmode = "RGB"; if (!PyArg_ParseTuple(args, "|ss", &mode, &rawmode)) - return NULL; + return NULL; if (!self->image->palette) { - PyErr_SetString(PyExc_ValueError, no_palette); - return NULL; + PyErr_SetString(PyExc_ValueError, no_palette); + return NULL; } pack = ImagingFindPacker(mode, rawmode, &bits); if (!pack) { - PyErr_SetString(PyExc_ValueError, wrong_raw_mode); - return NULL; + PyErr_SetString(PyExc_ValueError, wrong_raw_mode); + return NULL; } palette = PyBytes_FromStringAndSize(NULL, palettesize * bits / 8); if (!palette) - return NULL; + return NULL; pack((UINT8*) PyBytes_AsString(palette), - self->image->palette->palette, palettesize); + self->image->palette->palette, palettesize); return palette; } @@ -1066,14 +1066,14 @@ _histogram(ImagingObject* self, PyObject* args) /* Build an integer list containing the histogram */ list = PyList_New(h->bands * 256); for (i = 0; i < h->bands * 256; i++) { - PyObject* item; - item = PyInt_FromLong(h->histogram[i]); - if (item == NULL) { - Py_DECREF(list); - list = NULL; - break; - } - PyList_SetItem(list, i, item); + PyObject* item; + item = PyInt_FromLong(h->histogram[i]); + if (item == NULL) { + Py_DECREF(list); + list = NULL; + break; + } + PyList_SetItem(list, i, item); } ImagingHistogramDelete(h); @@ -1087,7 +1087,7 @@ _modefilter(ImagingObject* self, PyObject* args) { int size; if (!PyArg_ParseTuple(args, "i", &size)) - return NULL; + return NULL; return PyImagingNew(ImagingModeFilter(self->image, size)); } @@ -1098,7 +1098,7 @@ _offset(ImagingObject* self, PyObject* args) { int xoffset, yoffset; if (!PyArg_ParseTuple(args, "ii", &xoffset, &yoffset)) - return NULL; + return NULL; return PyImagingNew(ImagingOffset(self->image, xoffset, yoffset)); } @@ -1378,7 +1378,7 @@ _quantize(ImagingObject* self, PyObject* args) int method = 0; int kmeans = 0; if (!PyArg_ParseTuple(args, "|iii", &colours, &method, &kmeans)) - return NULL; + return NULL; if (!self->image->xsize || !self->image->ysize) { /* no content; return an empty image */ @@ -1401,22 +1401,22 @@ _putpalette(ImagingObject* self, PyObject* args) UINT8* palette; int palettesize; if (!PyArg_ParseTuple(args, "s"PY_ARG_BYTES_LENGTH, &rawmode, &palette, &palettesize)) - return NULL; + return NULL; if (strcmp(self->image->mode, "L") != 0 && strcmp(self->image->mode, "P")) { - PyErr_SetString(PyExc_ValueError, wrong_mode); - return NULL; + PyErr_SetString(PyExc_ValueError, wrong_mode); + return NULL; } unpack = ImagingFindUnpacker("RGB", rawmode, &bits); if (!unpack) { - PyErr_SetString(PyExc_ValueError, wrong_raw_mode); - return NULL; + PyErr_SetString(PyExc_ValueError, wrong_raw_mode); + return NULL; } if ( palettesize * 8 / bits > 256) { - PyErr_SetString(PyExc_ValueError, wrong_palette_size); - return NULL; + PyErr_SetString(PyExc_ValueError, wrong_palette_size); + return NULL; } ImagingPaletteDelete(self->image->palette); @@ -1463,21 +1463,21 @@ _putpalettealphas(ImagingObject* self, PyObject* args) UINT8 *values; int length; if (!PyArg_ParseTuple(args, "s#", &values, &length)) - return NULL; + return NULL; if (!self->image->palette) { - PyErr_SetString(PyExc_ValueError, no_palette); - return NULL; + PyErr_SetString(PyExc_ValueError, no_palette); + return NULL; } if (length > 256) { - PyErr_SetString(PyExc_ValueError, outside_palette); - return NULL; + PyErr_SetString(PyExc_ValueError, outside_palette); + return NULL; } strcpy(self->image->palette->mode, "RGBA"); for (i=0; iimage->palette->palette[i*4+3] = (UINT8) values[i]; + self->image->palette->palette[i*4+3] = (UINT8) values[i]; } Py_INCREF(Py_None); @@ -1493,13 +1493,13 @@ _putpixel(ImagingObject* self, PyObject* args) int x, y; PyObject* color; if (!PyArg_ParseTuple(args, "(ii)O", &x, &y, &color)) - return NULL; + return NULL; im = self->image; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) { - PyErr_SetString(PyExc_IndexError, outside_image); - return NULL; + PyErr_SetString(PyExc_IndexError, outside_image); + return NULL; } if (!getink(color, im, ink)) @@ -1518,7 +1518,7 @@ _rankfilter(ImagingObject* self, PyObject* args) { int size, rank; if (!PyArg_ParseTuple(args, "ii", &size, &rank)) - return NULL; + return NULL; return PyImagingNew(ImagingRankFilter(self->image, size, rank)); } @@ -1533,13 +1533,13 @@ _resize(ImagingObject* self, PyObject* args) int xsize, ysize; int filter = IMAGING_TRANSFORM_NEAREST; if (!PyArg_ParseTuple(args, "(ii)|i", &xsize, &ysize, &filter)) - return NULL; + return NULL; imIn = self->image; imOut = ImagingNew(imIn->mode, xsize, ysize); if (imOut) - (void) ImagingResize(imOut, imIn, filter); + (void) ImagingResize(imOut, imIn, filter); return PyImagingNew(imOut); } @@ -1553,7 +1553,7 @@ _rotate(ImagingObject* self, PyObject* args) double theta; int filter = IMAGING_TRANSFORM_NEAREST; if (!PyArg_ParseTuple(args, "d|i", &theta, &filter)) - return NULL; + return NULL; imIn = self->image; @@ -1841,8 +1841,8 @@ _getbbox(ImagingObject* self, PyObject* args) { int bbox[4]; if (!ImagingGetBBox(self->image, bbox)) { - Py_INCREF(Py_None); - return Py_None; + Py_INCREF(Py_None); + return Py_None; } return Py_BuildValue("iiii", bbox[0], bbox[1], bbox[2], bbox[3]); @@ -1857,7 +1857,7 @@ _getcolors(ImagingObject* self, PyObject* args) int maxcolors = 256; if (!PyArg_ParseTuple(args, "i:getcolors", &maxcolors)) - return NULL; + return NULL; items = ImagingGetColors(self->image, maxcolors, &colors); if (!items) @@ -1921,9 +1921,9 @@ _getprojection(ImagingObject* self, PyObject* args) yprofile = malloc(self->image->ysize); if (xprofile == NULL || yprofile == NULL) { - free(xprofile); - free(yprofile); - return PyErr_NoMemory(); + free(xprofile); + free(yprofile); + return PyErr_NoMemory(); } ImagingGetProjection(self->image, (unsigned char *)xprofile, (unsigned char *)yprofile); @@ -1946,7 +1946,7 @@ _getband(ImagingObject* self, PyObject* args) int band; if (!PyArg_ParseTuple(args, "i", &band)) - return NULL; + return NULL; return PyImagingNew(ImagingGetBand(self->image, band)); } @@ -1958,7 +1958,7 @@ _fillband(ImagingObject* self, PyObject* args) int color; if (!PyArg_ParseTuple(args, "ii", &band, &color)) - return NULL; + return NULL; if (!ImagingFillBand(self->image, band, color)) return NULL; @@ -1973,12 +1973,12 @@ _putband(ImagingObject* self, PyObject* args) ImagingObject* imagep; int band; if (!PyArg_ParseTuple(args, "O!i", - &Imaging_Type, &imagep, - &band)) - return NULL; + &Imaging_Type, &imagep, + &band)) + return NULL; if (!ImagingPutBand(self->image, imagep->image, band)) - return NULL; + return NULL; Py_INCREF(Py_None); return Py_None; @@ -2000,7 +2000,7 @@ _chop_lighter(ImagingObject* self, PyObject* args) ImagingObject* imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) - return NULL; + return NULL; return PyImagingNew(ImagingChopLighter(self->image, imagep->image)); } @@ -2011,7 +2011,7 @@ _chop_darker(ImagingObject* self, PyObject* args) ImagingObject* imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) - return NULL; + return NULL; return PyImagingNew(ImagingChopDarker(self->image, imagep->image)); } @@ -2022,7 +2022,7 @@ _chop_difference(ImagingObject* self, PyObject* args) ImagingObject* imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) - return NULL; + return NULL; return PyImagingNew(ImagingChopDifference(self->image, imagep->image)); } @@ -2033,7 +2033,7 @@ _chop_multiply(ImagingObject* self, PyObject* args) ImagingObject* imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) - return NULL; + return NULL; return PyImagingNew(ImagingChopMultiply(self->image, imagep->image)); } @@ -2044,7 +2044,7 @@ _chop_screen(ImagingObject* self, PyObject* args) ImagingObject* imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) - return NULL; + return NULL; return PyImagingNew(ImagingChopScreen(self->image, imagep->image)); } @@ -2060,8 +2060,8 @@ _chop_add(ImagingObject* self, PyObject* args) offset = 0; if (!PyArg_ParseTuple(args, "O!|fi", &Imaging_Type, &imagep, - &scale, &offset)) - return NULL; + &scale, &offset)) + return NULL; return PyImagingNew(ImagingChopAdd(self->image, imagep->image, scale, offset)); @@ -2078,8 +2078,8 @@ _chop_subtract(ImagingObject* self, PyObject* args) offset = 0; if (!PyArg_ParseTuple(args, "O!|fi", &Imaging_Type, &imagep, - &scale, &offset)) - return NULL; + &scale, &offset)) + return NULL; return PyImagingNew(ImagingChopSubtract(self->image, imagep->image, scale, offset)); @@ -2091,7 +2091,7 @@ _chop_and(ImagingObject* self, PyObject* args) ImagingObject* imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) - return NULL; + return NULL; return PyImagingNew(ImagingChopAnd(self->image, imagep->image)); } @@ -2102,7 +2102,7 @@ _chop_or(ImagingObject* self, PyObject* args) ImagingObject* imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) - return NULL; + return NULL; return PyImagingNew(ImagingChopOr(self->image, imagep->image)); } @@ -2113,7 +2113,7 @@ _chop_xor(ImagingObject* self, PyObject* args) ImagingObject* imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) - return NULL; + return NULL; return PyImagingNew(ImagingChopXor(self->image, imagep->image)); } @@ -2124,7 +2124,7 @@ _chop_add_modulo(ImagingObject* self, PyObject* args) ImagingObject* imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) - return NULL; + return NULL; return PyImagingNew(ImagingChopAddModulo(self->image, imagep->image)); } @@ -2135,7 +2135,7 @@ _chop_subtract_modulo(ImagingObject* self, PyObject* args) ImagingObject* imagep; if (!PyArg_ParseTuple(args, "O!", &Imaging_Type, &imagep)) - return NULL; + return NULL; return PyImagingNew(ImagingChopSubtractModulo(self->image, imagep->image)); } @@ -2158,18 +2158,18 @@ _font_new(PyObject* self_, PyObject* args) unsigned char* glyphdata; int glyphdata_length; if (!PyArg_ParseTuple(args, "O!"PY_ARG_BYTES_LENGTH, - &Imaging_Type, &imagep, - &glyphdata, &glyphdata_length)) + &Imaging_Type, &imagep, + &glyphdata, &glyphdata_length)) return NULL; if (glyphdata_length != 256 * 20) { - PyErr_SetString(PyExc_ValueError, wrong_length); - return NULL; + PyErr_SetString(PyExc_ValueError, wrong_length); + return NULL; } self = PyObject_New(ImagingFontObject, &ImagingFont_Type); if (self == NULL) - return NULL; + return NULL; /* glyph bitmap */ self->bitmap = imagep->image; @@ -2301,7 +2301,7 @@ _draw_new(PyObject* self_, PyObject* args) self = PyObject_New(ImagingDrawObject, &ImagingDraw_Type); if (self == NULL) - return NULL; + return NULL; /* keep a reference to the image object */ Py_INCREF(imagep); @@ -2348,7 +2348,7 @@ _draw_arc(ImagingDrawObject* self, PyObject* args) if (!PyArg_ParseTuple(args, "(iiii)iii|i", &x0, &y0, &x1, &y1, &start, &end, &ink)) - return NULL; + return NULL; if (ImagingDrawArc(self->image->image, x0, y0, x1, y1, start, end, &ink, op) < 0) @@ -2368,17 +2368,16 @@ _draw_bitmap(ImagingDrawObject* self, PyObject* args) ImagingObject* bitmap; int ink; if (!PyArg_ParseTuple(args, "OO!i", &data, &Imaging_Type, &bitmap, &ink)) - return NULL; + return NULL; n = PyPath_Flatten(data, &xy); if (n < 0) - return NULL; + return NULL; if (n != 1) { - PyErr_SetString( - PyExc_TypeError, - "coordinate list must contain exactly 1 coordinate" - ); - return NULL; + PyErr_SetString(PyExc_TypeError, + "coordinate list must contain exactly 1 coordinate" + ); + return NULL; } n = ImagingDrawBitmap( @@ -2403,7 +2402,7 @@ _draw_chord(ImagingDrawObject* self, PyObject* args) int start, end; if (!PyArg_ParseTuple(args, "(iiii)iiii", &x0, &y0, &x1, &y1, &start, &end, &ink, &fill)) - return NULL; + return NULL; if (ImagingDrawChord(self->image->image, x0, y0, x1, y1, start, end, &ink, fill, self->blend) < 0) @@ -2423,23 +2422,23 @@ _draw_ellipse(ImagingDrawObject* self, PyObject* args) int ink; int fill = 0; if (!PyArg_ParseTuple(args, "Oi|i", &data, &ink, &fill)) - return NULL; + return NULL; n = PyPath_Flatten(data, &xy); if (n < 0) - return NULL; + return NULL; if (n != 2) { - PyErr_SetString( - PyExc_TypeError, - "coordinate list must contain exactly 2 coordinates" - ); - return NULL; + PyErr_SetString(PyExc_TypeError, + "coordinate list must contain exactly 2 coordinates" + ); + return NULL; } - n = ImagingDrawEllipse( - self->image->image, (int) xy[0], (int) xy[1], (int) xy[2], (int) xy[3], - &ink, fill, self->blend - ); + n = ImagingDrawEllipse(self->image->image, + (int) xy[0], (int) xy[1], + (int) xy[2], (int) xy[3], + &ink, fill, self->blend + ); free(xy); @@ -2456,11 +2455,11 @@ _draw_line(ImagingDrawObject* self, PyObject* args) int x0, y0, x1, y1; int ink; if (!PyArg_ParseTuple(args, "(ii)(ii)i", &x0, &y0, &x1, &y1, &ink)) - return NULL; + return NULL; if (ImagingDrawLine(self->image->image, x0, y0, x1, y1, &ink, self->blend) < 0) - return NULL; + return NULL; Py_INCREF(Py_None); return Py_None; @@ -2476,11 +2475,11 @@ _draw_lines(ImagingDrawObject* self, PyObject* args) int ink; int width = 0; if (!PyArg_ParseTuple(args, "Oi|i", &data, &ink, &width)) - return NULL; + return NULL; n = PyPath_Flatten(data, &xy); if (n < 0) - return NULL; + return NULL; if (width <= 1) { double *p = NULL; @@ -2525,10 +2524,10 @@ _draw_point(ImagingDrawObject* self, PyObject* args) int x, y; int ink; if (!PyArg_ParseTuple(args, "(ii)i", &x, &y, &ink)) - return NULL; + return NULL; if (ImagingDrawPoint(self->image->image, x, y, &ink, self->blend) < 0) - return NULL; + return NULL; Py_INCREF(Py_None); return Py_None; @@ -2543,11 +2542,11 @@ _draw_points(ImagingDrawObject* self, PyObject* args) PyObject *data; int ink; if (!PyArg_ParseTuple(args, "Oi", &data, &ink)) - return NULL; + return NULL; n = PyPath_Flatten(data, &xy); if (n < 0) - return NULL; + return NULL; for (i = 0; i < n; i++) { double *p = &xy[i+i]; @@ -2578,7 +2577,7 @@ _draw_outline(ImagingDrawObject* self, PyObject* args) int ink; int fill = 0; if (!PyArg_ParseTuple(args, "Oi|i", &outline_, &ink, &fill)) - return NULL; + return NULL; outline = PyOutline_AsOutline(outline_); if (!outline) { @@ -2604,7 +2603,7 @@ _draw_pieslice(ImagingDrawObject* self, PyObject* args) int start, end; if (!PyArg_ParseTuple(args, "(iiii)iiii", &x0, &y0, &x1, &y1, &start, &end, &ink, &fill)) - return NULL; + return NULL; if (ImagingDrawPieslice(self->image->image, x0, y0, x1, y1, start, end, &ink, fill, self->blend) < 0) @@ -2625,33 +2624,32 @@ _draw_polygon(ImagingDrawObject* self, PyObject* args) int ink; int fill = 0; if (!PyArg_ParseTuple(args, "Oi|i", &data, &ink, &fill)) - return NULL; + return NULL; n = PyPath_Flatten(data, &xy); if (n < 0) - return NULL; + return NULL; if (n < 2) { - PyErr_SetString( - PyExc_TypeError, - "coordinate list must contain at least 2 coordinates" - ); - return NULL; + PyErr_SetString(PyExc_TypeError, + "coordinate list must contain at least 2 coordinates" + ); + return NULL; } /* Copy list of vertices to array */ ixy = (int*) malloc(n * 2 * sizeof(int)); for (i = 0; i < n; i++) { - ixy[i+i] = (int) xy[i+i]; - ixy[i+i+1] = (int) xy[i+i+1]; + ixy[i+i] = (int) xy[i+i]; + ixy[i+i+1] = (int) xy[i+i+1]; } free(xy); if (ImagingDrawPolygon(self->image->image, n, ixy, &ink, fill, self->blend) < 0) { - free(ixy); - return NULL; + free(ixy); + return NULL; } free(ixy); @@ -2670,23 +2668,23 @@ _draw_rectangle(ImagingDrawObject* self, PyObject* args) int ink; int fill = 0; if (!PyArg_ParseTuple(args, "Oi|i", &data, &ink, &fill)) - return NULL; + return NULL; n = PyPath_Flatten(data, &xy); if (n < 0) - return NULL; + return NULL; if (n != 2) { - PyErr_SetString( - PyExc_TypeError, - "coordinate list must contain exactly 2 coordinates" - ); - return NULL; + PyErr_SetString(PyExc_TypeError, + "coordinate list must contain exactly 2 coordinates" + ); + return NULL; } - n = ImagingDrawRectangle( - self->image->image, (int) xy[0], (int) xy[1], - (int) xy[2], (int) xy[3], &ink, fill, self->blend - ); + n = ImagingDrawRectangle(self->image->image, + (int) xy[0], (int) xy[1], + (int) xy[2], (int) xy[3], + &ink, fill, self->blend + ); free(xy); @@ -2733,7 +2731,7 @@ pixel_access_new(ImagingObject* imagep, PyObject* args) self = PyObject_New(PixelAccessObject, &PixelAccess_Type); if (self == NULL) - return NULL; + return NULL; /* keep a reference to the image object */ Py_INCREF(imagep); @@ -2777,8 +2775,8 @@ pixel_access_setitem(PixelAccessObject *self, PyObject *xy, PyObject *color) return -1; if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) { - PyErr_SetString(PyExc_IndexError, outside_image); - return -1; + PyErr_SetString(PyExc_IndexError, outside_image); + return -1; } if (!color) /* FIXME: raise exception? */ @@ -2823,7 +2821,7 @@ _effect_noise(ImagingObject* self, PyObject* args) int xsize, ysize; float sigma = 128; if (!PyArg_ParseTuple(args, "(ii)|f", &xsize, &ysize, &sigma)) - return NULL; + return NULL; return PyImagingNew(ImagingEffectNoise(xsize, ysize, sigma)); } @@ -2834,7 +2832,7 @@ _effect_spread(ImagingObject* self, PyObject* args) int dist; if (!PyArg_ParseTuple(args, "i", &dist)) - return NULL; + return NULL; return PyImagingNew(ImagingEffectSpread(self->image, dist)); } @@ -2857,7 +2855,7 @@ _crc32(PyObject* self, PyObject* args) if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH"|(ii)", &buffer, &bytes, &hi, &lo)) - return NULL; + return NULL; crc = ((UINT32) (hi & 0xFFFF) << 16) + (lo & 0xFFFF); @@ -2873,19 +2871,19 @@ _getcodecstatus(PyObject* self, PyObject* args) char* msg; if (!PyArg_ParseTuple(args, "i", &status)) - return NULL; + return NULL; switch (status) { case IMAGING_CODEC_OVERRUN: - msg = "buffer overrun"; break; + msg = "buffer overrun"; break; case IMAGING_CODEC_BROKEN: - msg = "broken data stream"; break; + msg = "broken data stream"; break; case IMAGING_CODEC_UNKNOWN: - msg = "unrecognized data stream contents"; break; + msg = "unrecognized data stream contents"; break; case IMAGING_CODEC_CONFIG: - msg = "codec configuration error"; break; + msg = "codec configuration error"; break; case IMAGING_CODEC_MEMORY: - msg = "out of memory"; break; + msg = "out of memory"; break; default: Py_RETURN_NONE; } @@ -2906,7 +2904,7 @@ _save_ppm(ImagingObject* self, PyObject* args) char* filename; if (!PyArg_ParseTuple(args, "s", &filename)) - return NULL; + return NULL; if (!ImagingSavePPM(self->image, filename)) return NULL; From e60b871b928c7ad8e7740f34b95d461881766859 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 26 Nov 2013 12:21:50 -0800 Subject: [PATCH 3/7] whitespace --- _imaging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_imaging.c b/_imaging.c index 8a7761055..37dab7839 100644 --- a/_imaging.c +++ b/_imaging.c @@ -783,7 +783,7 @@ _convert_matrix(ImagingObject* self, PyObject* args) char* mode; float m[12]; if (!PyArg_ParseTuple(args, "s(ffff)", &mode, m+0, m+1, m+2, m+3)) { - PyErr_Clear(); + PyErr_Clear(); if (!PyArg_ParseTuple(args, "s(ffffffffffff)", &mode, m+0, m+1, m+2, m+3, m+4, m+5, m+6, m+7, From e12528fb625ffbfb51268ccc4abd3cc12bf3862f Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 26 Nov 2013 12:22:09 -0800 Subject: [PATCH 4/7] dyslexic typo --- Tests/test_file_png.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index 98f2cec6d..81113a8fb 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -158,8 +158,8 @@ def test_load_transparent_rgb(): im = im.convert("RGBA") assert_image(im, "RGBA", (64, 64)) - # image has 867 transparent pixels - assert_equal(im.split()[3].getcolors()[0][0], 867) + # image has 876 transparent pixels + assert_equal(im.split()[3].getcolors()[0][0], 876) def test_save_p_transparent_palette(): in_file = "Tests/images/pil123p.png" From c546c5a4c01b0c6f1443e525d23a9266b02bb731 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 26 Nov 2013 12:24:19 -0800 Subject: [PATCH 5/7] Added conversion for RGB+Transparency to RGBA that adds an alpha mask corresponding to the transparency value, fixes #421 --- PIL/Image.py | 4 +++ _imaging.c | 13 ++++++++ libImaging/Convert.c | 72 ++++++++++++++++++++++++++++++++++++++++++++ libImaging/Imaging.h | 1 + 4 files changed, 90 insertions(+) diff --git a/PIL/Image.py b/PIL/Image.py index ec5ff548d..2e5efeb28 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -731,6 +731,10 @@ class Image: self.palette.dirty = 1 self.load() + # Use transparent conversion to promote from transparent color to an alpha channel. + if self.mode == "RGB" and mode == "RGBA" and "transparency" in self.info: + return self._new(self.im.convert_transparent(mode, self.info['transparency'])) + try: im = self.im.convert(mode, dither) except ValueError: diff --git a/_imaging.c b/_imaging.c index 37dab7839..ce6584788 100644 --- a/_imaging.c +++ b/_imaging.c @@ -794,6 +794,18 @@ _convert_matrix(ImagingObject* self, PyObject* args) return PyImagingNew(ImagingConvertMatrix(self->image, mode, m)); } +static PyObject* +_convert_transparent(ImagingObject* self, PyObject* args) +{ + char* mode; + int r,g,b; + if (!PyArg_ParseTuple(args, "s(iii)", &mode, &r, &g, &b)) { + return NULL; + } + + return PyImagingNew(ImagingConvertTransparent(self->image, mode, r, g, b)); +} + static PyObject* _copy(ImagingObject* self, PyObject* args) { @@ -2931,6 +2943,7 @@ static struct PyMethodDef methods[] = { {"convert", (PyCFunction)_convert, 1}, {"convert2", (PyCFunction)_convert2, 1}, {"convert_matrix", (PyCFunction)_convert_matrix, 1}, + {"convert_transparent", (PyCFunction)_convert_transparent, 1}, {"copy", (PyCFunction)_copy, 1}, {"copy2", (PyCFunction)_copy2, 1}, #ifdef WITH_CRACKCODE diff --git a/libImaging/Convert.c b/libImaging/Convert.c index 2caf219ea..cedff2d04 100644 --- a/libImaging/Convert.c +++ b/libImaging/Convert.c @@ -312,7 +312,36 @@ rgba2rgbA(UINT8* out, const UINT8* in, int xsize) } } +/* + * 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, const UINT8* in, 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 + UINT32* tmp = (UINT32 *)out; + int i; + + rgb2rgba(out, in, xsize); + + for (i=0; i < xsize; i++ ,tmp++) { + if (tmp[0]==trns) { + tmp[0]=repl; + } + } +} + + /* ---------------- */ /* CMYK conversions */ @@ -1162,6 +1191,49 @@ 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; + Imaging imOut = NULL; + int y; + + if (!imIn){ + return (Imaging) ImagingError_ModeError(); + } + + if (!(strcmp(imIn->mode, "RGB") == 0 && strcmp(mode, "RGBA") == 0)) +#ifdef notdef + { + return (Imaging) ImagingError_ValueError("conversion not supported"); + } +#else + { + static char buf[256]; + /* FIXME: may overflow if mode is too large */ + sprintf(buf, "conversion from %s to %s not supported in convert_transparent", imIn->mode, mode); + return (Imaging) ImagingError_ValueError(buf); + } +#endif + + + imOut = ImagingNew2(mode, imOut, imIn); + if (!imOut){ + return NULL; + } + + ImagingSectionEnter(&cookie); + for (y = 0; y < imIn->ysize; y++) + rgbT2rgba((UINT8*) imOut->image[y], (UINT8*) imIn->image[y], + imIn->xsize, r, g, b); + ImagingSectionLeave(&cookie); + + return imOut; + +} + Imaging ImagingConvertInPlace(Imaging imIn, const char* mode) { diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index c139aed88..b45dcbe23 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -248,6 +248,7 @@ 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, int mode); extern Imaging ImagingFill(Imaging im, const void* ink); From 0356741a293e9f03e635bf58a0eb0049ce120c1a Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 26 Nov 2013 13:04:10 -0800 Subject: [PATCH 6/7] Now using the rgbT2rgba conversion for L+transparency to RGBA, dropping the palette hack --- PIL/Image.py | 12 +----------- Tests/test_file_png.py | 4 ++++ _imaging.c | 11 +++++++---- libImaging/Convert.c | 24 ++++++++++++++++-------- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index 2e5efeb28..a75b3c065 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -721,18 +721,8 @@ class Image: if dither is None: dither = FLOYDSTEINBERG - # fake a P-mode image, otherwise the transparency will get lost as there is - # currently no other way to convert transparency into an RGBA image - if self.mode == "L" and mode == "RGBA" and "transparency" in self.info: - from PIL import ImagePalette - self.mode = "P" - bytePalette = bytes(bytearray([i//3 for i in range(768)])) - self.palette = ImagePalette.raw("RGB", bytePalette) - self.palette.dirty = 1 - self.load() - # Use transparent conversion to promote from transparent color to an alpha channel. - if self.mode == "RGB" and mode == "RGBA" and "transparency" in self.info: + if self.mode in ("L", "RGB") and mode == "RGBA" and "transparency" in self.info: return self._new(self.im.convert_transparent(mode, self.info['transparency'])) try: diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index 81113a8fb..3f61f39bd 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -182,6 +182,10 @@ def test_save_l_transparency(): file = tempfile("temp.png") assert_no_exception(lambda: im.save(file)) + # There are 559 transparent pixels. + im = im.convert('RGBA') + assert_equal(im.split()[3].getcolors()[0][0], 559) + def test_save_rgb_single_transparency(): in_file = "Tests/images/caption_6_33_22.png" im = Image.open(in_file) diff --git a/_imaging.c b/_imaging.c index ce6584788..489a5017c 100644 --- a/_imaging.c +++ b/_imaging.c @@ -799,11 +799,14 @@ _convert_transparent(ImagingObject* self, PyObject* args) { char* mode; int r,g,b; - if (!PyArg_ParseTuple(args, "s(iii)", &mode, &r, &g, &b)) { - return NULL; + if (PyArg_ParseTuple(args, "s(iii)", &mode, &r, &g, &b)) { + return PyImagingNew(ImagingConvertTransparent(self->image, mode, r, g, b)); } - - return PyImagingNew(ImagingConvertTransparent(self->image, mode, r, g, b)); + PyErr_Clear(); + if (PyArg_ParseTuple(args, "si", &mode, &r)) { + return PyImagingNew(ImagingConvertTransparent(self->image, mode, r, 0, 0)); + } + return NULL; } static PyObject* diff --git a/libImaging/Convert.c b/libImaging/Convert.c index cedff2d04..631263b31 100644 --- a/libImaging/Convert.c +++ b/libImaging/Convert.c @@ -319,7 +319,7 @@ rgba2rgbA(UINT8* out, const UINT8* in, int xsize) */ static void -rgbT2rgba(UINT8* out, const UINT8* in, int xsize, int r, int g, int b) +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; @@ -332,15 +332,12 @@ rgbT2rgba(UINT8* out, const UINT8* in, int xsize, int r, int g, int b) UINT32* tmp = (UINT32 *)out; int i; - rgb2rgba(out, in, xsize); - for (i=0; i < xsize; i++ ,tmp++) { if (tmp[0]==trns) { tmp[0]=repl; } } } - /* ---------------- */ @@ -1197,6 +1194,7 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, int r, int g, int b) { ImagingSectionCookie cookie; + ImagingShuffler convert; Imaging imOut = NULL; int y; @@ -1204,7 +1202,9 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, return (Imaging) ImagingError_ModeError(); } - if (!(strcmp(imIn->mode, "RGB") == 0 && strcmp(mode, "RGBA") == 0)) + if (!((strcmp(imIn->mode, "RGB") == 0 || + strcmp(imIn->mode, "L") == 0) + && strcmp(mode, "RGBA") == 0)) #ifdef notdef { return (Imaging) ImagingError_ValueError("conversion not supported"); @@ -1218,6 +1218,12 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, } #endif + if (strcmp(imIn->mode, "RGB") == 0) { + convert = rgb2rgba; + } else { + convert = l2rgb; + g = b = r; + } imOut = ImagingNew2(mode, imOut, imIn); if (!imOut){ @@ -1225,9 +1231,11 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, } ImagingSectionEnter(&cookie); - for (y = 0; y < imIn->ysize; y++) - rgbT2rgba((UINT8*) imOut->image[y], (UINT8*) imIn->image[y], - imIn->xsize, r, g, b); + 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; From e06600d17677a15aaa8413c298c2dd73294442c7 Mon Sep 17 00:00:00 2001 From: wiredfool Date: Tue, 26 Nov 2013 14:51:07 -0800 Subject: [PATCH 7/7] Docs: saving RGB+transparency works --- docs/handbook/image-file-formats.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index d0595711e..5f47f647a 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -187,9 +187,9 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options: possible. This includes extra processing in order to find optimal encoder settings. -**transparency** - For ``P`` and ``L`` images, this option controls what color image to mark as - transparent. +**transparency** + For ``P``, ``L``, and ``RGB`` images, this option controls what + color image to mark as transparent. **bits (experimental)** For ``P`` images, this option controls how many bits to store. If omitted,