mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-02-04 21:50:54 +03:00
Merge branch 'pcx' of https://github.com/wiredfool/Pillow into wiredfool-pcx
This commit is contained in:
commit
c1d44980b8
|
@ -8,6 +8,8 @@ Changelog (Pillow)
|
|||
[wiredfool]
|
||||
|
||||
- Skip CFFI test earlier if it's not installed
|
||||
|
||||
- Fixed opening and saving odd sized .pcx files, fixes #523
|
||||
[wiredfool]
|
||||
|
||||
- Fixed saving mode P image as a PNG with transparency = palette color 0
|
||||
|
|
|
@ -55,12 +55,18 @@ class PcxImageFile(ImageFile.ImageFile):
|
|||
bbox = i16(s,4), i16(s,6), i16(s,8)+1, i16(s,10)+1
|
||||
if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]:
|
||||
raise SyntaxError("bad PCX image size")
|
||||
if Image.DEBUG:
|
||||
print ("BBox: %s %s %s %s" % bbox)
|
||||
|
||||
|
||||
# format
|
||||
version = i8(s[1])
|
||||
bits = i8(s[3])
|
||||
planes = i8(s[65])
|
||||
stride = i16(s,66)
|
||||
if Image.DEBUG:
|
||||
print ("PCX version %s, bits %s, planes %s, stride %s" %
|
||||
(version, bits, planes, stride))
|
||||
|
||||
self.info["dpi"] = i16(s,12), i16(s,14)
|
||||
|
||||
|
@ -98,6 +104,8 @@ class PcxImageFile(ImageFile.ImageFile):
|
|||
self.size = bbox[2]-bbox[0], bbox[3]-bbox[1]
|
||||
|
||||
bbox = (0, 0) + self.size
|
||||
if Image.DEBUG:
|
||||
print ("size: %sx%s" % self.size)
|
||||
|
||||
self.tile = [("pcx", bbox, self.fp.tell(), (rawmode, planes * stride))]
|
||||
|
||||
|
@ -126,6 +134,16 @@ def _save(im, fp, filename, check=0):
|
|||
|
||||
# bytes per plane
|
||||
stride = (im.size[0] * bits + 7) // 8
|
||||
# stride should be even
|
||||
stride = stride + (stride % 2)
|
||||
# Stride needs to be kept in sync with the PcxEncode.c version.
|
||||
# Ideally it should be passed in in the state, but the bytes value
|
||||
# gets overwritten.
|
||||
|
||||
|
||||
if Image.DEBUG:
|
||||
print ("PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d" % (
|
||||
im.size[0], bits, stride))
|
||||
|
||||
# under windows, we could determine the current screen size with
|
||||
# "Image.core.display_mode()[1]", but I think that's overkill...
|
||||
|
|
|
@ -2,29 +2,30 @@ from tester import *
|
|||
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def _roundtrip(im):
|
||||
f = tempfile("temp.pcx")
|
||||
im.save(f)
|
||||
im2 = Image.open(f)
|
||||
|
||||
assert_equal(im2.mode, im.mode)
|
||||
assert_equal(im2.size, im.size)
|
||||
assert_equal(im2.format, "PCX")
|
||||
assert_image_equal(im2, im)
|
||||
|
||||
def test_sanity():
|
||||
for mode in ('1', 'L', 'P', 'RGB'):
|
||||
_roundtrip(lena(mode))
|
||||
|
||||
file = tempfile("temp.pcx")
|
||||
def test_odd():
|
||||
# see issue #523, odd sized images should have a stride that's even.
|
||||
# not that imagemagick or gimp write pcx that way.
|
||||
# we were not handling properly.
|
||||
for mode in ('1', 'L', 'P', 'RGB'):
|
||||
# larger, odd sized images are better here to ensure that
|
||||
# we handle interrupted scan lines properly.
|
||||
_roundtrip(lena(mode).resize((511,511)))
|
||||
|
||||
lena("1").save(file)
|
||||
|
||||
im = Image.open(file)
|
||||
im.load()
|
||||
assert_equal(im.mode, "1")
|
||||
assert_equal(im.size, (128, 128))
|
||||
assert_equal(im.format, "PCX")
|
||||
|
||||
lena("1").save(file)
|
||||
im = Image.open(file)
|
||||
|
||||
lena("L").save(file)
|
||||
im = Image.open(file)
|
||||
|
||||
lena("P").save(file)
|
||||
im = Image.open(file)
|
||||
|
||||
lena("RGB").save(file)
|
||||
im = Image.open(file)
|
||||
|
||||
def test_pil184():
|
||||
# Check reading of files where xmin/xmax is not zero.
|
||||
|
|
11
encode.c
11
encode.c
|
@ -358,15 +358,19 @@ PyImaging_PcxEncoderNew(PyObject* self, PyObject* args)
|
|||
char *mode;
|
||||
char *rawmode;
|
||||
int bits = 8;
|
||||
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &bits))
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss|ii", &mode, &rawmode, &bits)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
encoder = PyImaging_EncoderNew(0);
|
||||
if (encoder == NULL)
|
||||
if (encoder == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (get_packer(encoder, mode, rawmode) < 0)
|
||||
if (get_packer(encoder, mode, rawmode) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
encoder->encode = ImagingPcxEncode;
|
||||
|
||||
|
@ -793,3 +797,4 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -57,7 +57,16 @@ ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8* buf, int 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,
|
||||
|
|
|
@ -26,23 +26,41 @@ 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->bytes = (state->xsize*state->bits + 7) / 8;
|
||||
state->state = FETCH;
|
||||
|
||||
}
|
||||
|
||||
for (;;)
|
||||
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:
|
||||
|
@ -68,17 +86,22 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
|||
/* 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 */
|
||||
|
||||
while (state->x < state->bytes) {
|
||||
while (state->x < planes * bytes_per_line) {
|
||||
/* 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;
|
||||
|
@ -93,23 +116,23 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
|||
this = state->buffer[state->x];
|
||||
|
||||
if (this == state->LAST) {
|
||||
|
||||
/* extend the current run */
|
||||
state->x++;
|
||||
state->count++;
|
||||
|
||||
} else {
|
||||
|
||||
/* start a new run */
|
||||
if (state->count == 1 && (state->LAST < 0xc0)) {
|
||||
if (bytes < 1)
|
||||
if (bytes < 1) {
|
||||
return ptr - buf;
|
||||
}
|
||||
*ptr++ = state->LAST;
|
||||
bytes--;
|
||||
} else {
|
||||
if (state->count > 0) {
|
||||
if (bytes < 2)
|
||||
if (bytes < 2) {
|
||||
return ptr - buf;
|
||||
}
|
||||
*ptr++ = 0xc0 | state->count;
|
||||
*ptr++ = state->LAST;
|
||||
bytes -= 2;
|
||||
|
@ -126,23 +149,40 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
|||
|
||||
/* end of line; flush the current run */
|
||||
if (state->count == 1 && (state->LAST < 0xc0)) {
|
||||
if (bytes < 1)
|
||||
if (bytes < 1 + padding) {
|
||||
return ptr - buf;
|
||||
}
|
||||
*ptr++ = state->LAST;
|
||||
bytes--;
|
||||
} else {
|
||||
if (state->count > 0) {
|
||||
if (bytes < 2)
|
||||
if (bytes < 2 + padding) {
|
||||
return ptr - buf;
|
||||
}
|
||||
*ptr++ = 0xc0 | state->count;
|
||||
*ptr++ = state->LAST;
|
||||
bytes -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes < padding) {
|
||||
return ptr - buf;
|
||||
}
|
||||
/* add the padding */
|
||||
for (i=0;i<padding;i++){
|
||||
*ptr++=0;
|
||||
bytes--;
|
||||
}
|
||||
/* reset for the next color plane. */
|
||||
if (state->x < planes * bytes_per_line) {
|
||||
state->count = 1;
|
||||
state->LAST = state->buffer[state->x];
|
||||
state->x++;
|
||||
}
|
||||
}
|
||||
/* read next line */
|
||||
state->state = FETCH;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user