Merge pull request #423 from wiredfool/trns-png

Support for PNG tRNS header when converting from RGB->RGBA
This commit is contained in:
Alex Clark ☺ 2013-12-28 05:56:03 -08:00
commit d48f301d57
7 changed files with 314 additions and 210 deletions

View File

@ -724,16 +724,10 @@ 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 in ("L", "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:

BIN
Tests/images/rgb_trns.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -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 876 transparent pixels
assert_equal(im.split()[3].getcolors()[0][0], 876)
def test_save_p_transparent_palette():
in_file = "Tests/images/pil123p.png"
im = Image.open(in_file)
@ -171,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)

View File

@ -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;
@ -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,
@ -794,11 +794,26 @@ _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 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*
_copy(ImagingObject* self, PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
return NULL;
return PyImagingNew(ImagingCopy(self->image));
}
@ -809,9 +824,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 +840,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 +851,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 +867,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 +922,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 +1081,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 +1102,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 +1113,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));
}
@ -1379,7 +1394,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 */
@ -1402,22 +1417,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);
@ -1464,21 +1479,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; i<length; i++) {
self->image->palette->palette[i*4+3] = (UINT8) values[i];
self->image->palette->palette[i*4+3] = (UINT8) values[i];
}
Py_INCREF(Py_None);
@ -1494,13 +1509,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))
@ -1519,7 +1534,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));
}
@ -1534,13 +1549,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);
}
@ -1554,7 +1569,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;
@ -1842,8 +1857,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]);
@ -1858,7 +1873,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)
@ -1922,9 +1937,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);
@ -1947,7 +1962,7 @@ _getband(ImagingObject* self, PyObject* args)
int band;
if (!PyArg_ParseTuple(args, "i", &band))
return NULL;
return NULL;
return PyImagingNew(ImagingGetBand(self->image, band));
}
@ -1959,7 +1974,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;
@ -1974,12 +1989,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;
@ -2001,7 +2016,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));
}
@ -2012,7 +2027,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));
}
@ -2023,7 +2038,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));
}
@ -2034,7 +2049,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));
}
@ -2045,7 +2060,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));
}
@ -2061,8 +2076,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));
@ -2079,8 +2094,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));
@ -2092,7 +2107,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));
}
@ -2103,7 +2118,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));
}
@ -2114,7 +2129,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));
}
@ -2125,7 +2140,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));
}
@ -2136,7 +2151,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));
}
@ -2159,18 +2174,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;
@ -2302,7 +2317,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);
@ -2349,7 +2364,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)
@ -2369,17 +2384,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(
@ -2404,7 +2418,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)
@ -2424,23 +2438,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);
@ -2457,11 +2471,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;
@ -2477,11 +2491,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;
@ -2526,10 +2540,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;
@ -2544,11 +2558,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];
@ -2579,7 +2593,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) {
@ -2605,7 +2619,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)
@ -2626,33 +2640,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);
@ -2671,23 +2684,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);
@ -2734,7 +2747,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);
@ -2778,8 +2791,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? */
@ -2824,7 +2837,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));
}
@ -2835,7 +2848,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));
}
@ -2858,7 +2871,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);
@ -2874,19 +2887,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;
}
@ -2907,7 +2920,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;
@ -2934,6 +2947,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

View File

@ -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,

View File

@ -312,7 +312,33 @@ 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, 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;
for (i=0; i < xsize; i++ ,tmp++) {
if (tmp[0]==trns) {
tmp[0]=repl;
}
}
}
/* ---------------- */
/* CMYK conversions */
@ -1162,6 +1188,60 @@ 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(imIn->mode, "L") == 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
if (strcmp(imIn->mode, "RGB") == 0) {
convert = rgb2rgba;
} else {
convert = l2rgb;
g = b = r;
}
imOut = ImagingNew2(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)
{

View File

@ -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);