mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 17:36:18 +03:00
Merge pull request #2041 from uploadcare/pcx-encoding
PCX encoding fixes
This commit is contained in:
commit
0a8385f5e0
|
@ -1,6 +1,6 @@
|
||||||
from helper import unittest, PillowTestCase, hopper
|
from helper import unittest, PillowTestCase, hopper
|
||||||
|
|
||||||
from PIL import Image, PcxImagePlugin
|
from PIL import Image, ImageFile, PcxImagePlugin
|
||||||
|
|
||||||
|
|
||||||
class TestFilePcx(PillowTestCase):
|
class TestFilePcx(PillowTestCase):
|
||||||
|
@ -46,6 +46,84 @@ class TestFilePcx(PillowTestCase):
|
||||||
# Make sure all pixels are either 0 or 255.
|
# Make sure all pixels are either 0 or 255.
|
||||||
self.assertEqual(im.histogram()[0] + im.histogram()[255], 447*144)
|
self.assertEqual(im.histogram()[0] + im.histogram()[255], 447*144)
|
||||||
|
|
||||||
|
def test_1px_width(self):
|
||||||
|
im = Image.new('L', (1, 256))
|
||||||
|
px = im.load()
|
||||||
|
for y in range(256):
|
||||||
|
px[0, y] = y
|
||||||
|
self._roundtrip(im)
|
||||||
|
|
||||||
|
def test_large_count(self):
|
||||||
|
im = Image.new('L', (256, 1))
|
||||||
|
px = im.load()
|
||||||
|
for x in range(256):
|
||||||
|
px[x, 0] = x // 67 * 67
|
||||||
|
self._roundtrip(im)
|
||||||
|
|
||||||
|
def _test_buffer_overflow(self, im, size=1024):
|
||||||
|
_last = ImageFile.MAXBLOCK
|
||||||
|
ImageFile.MAXBLOCK = size
|
||||||
|
try:
|
||||||
|
self._roundtrip(im)
|
||||||
|
finally:
|
||||||
|
ImageFile.MAXBLOCK = _last
|
||||||
|
|
||||||
|
def test_break_in_count_overflow(self):
|
||||||
|
im = Image.new('L', (256, 5))
|
||||||
|
px = im.load()
|
||||||
|
for y in range(4):
|
||||||
|
for x in range(256):
|
||||||
|
px[x, y] = x % 128
|
||||||
|
self._test_buffer_overflow(im)
|
||||||
|
|
||||||
|
def test_break_one_in_loop(self):
|
||||||
|
im = Image.new('L', (256, 5))
|
||||||
|
px = im.load()
|
||||||
|
for y in range(5):
|
||||||
|
for x in range(256):
|
||||||
|
px[x, y] = x % 128
|
||||||
|
self._test_buffer_overflow(im)
|
||||||
|
|
||||||
|
def test_break_many_in_loop(self):
|
||||||
|
im = Image.new('L', (256, 5))
|
||||||
|
px = im.load()
|
||||||
|
for y in range(4):
|
||||||
|
for x in range(256):
|
||||||
|
px[x, y] = x % 128
|
||||||
|
for x in range(8):
|
||||||
|
px[x, 4] = 16
|
||||||
|
self._test_buffer_overflow(im)
|
||||||
|
|
||||||
|
def test_break_one_at_end(self):
|
||||||
|
im = Image.new('L', (256, 5))
|
||||||
|
px = im.load()
|
||||||
|
for y in range(5):
|
||||||
|
for x in range(256):
|
||||||
|
px[x, y] = x % 128
|
||||||
|
px[0, 3] = 128 + 64
|
||||||
|
self._test_buffer_overflow(im)
|
||||||
|
|
||||||
|
def test_break_many_at_end(self):
|
||||||
|
im = Image.new('L', (256, 5))
|
||||||
|
px = im.load()
|
||||||
|
for y in range(5):
|
||||||
|
for x in range(256):
|
||||||
|
px[x, y] = x % 128
|
||||||
|
for x in range(4):
|
||||||
|
px[x * 2, 3] = 128 + 64
|
||||||
|
px[x + 256 - 4, 3] = 0
|
||||||
|
self._test_buffer_overflow(im)
|
||||||
|
|
||||||
|
def test_break_padding(self):
|
||||||
|
im = Image.new('L', (257, 5))
|
||||||
|
px = im.load()
|
||||||
|
for y in range(5):
|
||||||
|
for x in range(257):
|
||||||
|
px[x, y] = x % 128
|
||||||
|
for x in range(5):
|
||||||
|
px[x, 3] = 0
|
||||||
|
self._test_buffer_overflow(im)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -75,7 +75,7 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
(UINT8*) im->image[state->y + state->yoff] +
|
(UINT8*) im->image[state->y + state->yoff] +
|
||||||
state->xoff * im->pixelsize, state->xsize);
|
state->xoff * im->pixelsize, state->xsize);
|
||||||
|
|
||||||
state->y++;
|
state->y += 1;
|
||||||
|
|
||||||
state->count = 1;
|
state->count = 1;
|
||||||
state->LAST = state->buffer[0];
|
state->LAST = state->buffer[0];
|
||||||
|
@ -91,7 +91,7 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
/* when we arrive here, "count" contains the number of
|
/* when we arrive here, "count" contains the number of
|
||||||
bytes having the value of "LAST" that we've already
|
bytes having the value of "LAST" that we've already
|
||||||
seen */
|
seen */
|
||||||
while (state->x < planes * bytes_per_line) {
|
do {
|
||||||
/* If we're encoding an odd width file, and we've
|
/* If we're encoding an odd width file, and we've
|
||||||
got more than one plane, we need to pad each
|
got more than one plane, we need to pad each
|
||||||
color row with padding bytes at the end. Since
|
color row with padding bytes at the end. Since
|
||||||
|
@ -103,22 +103,23 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
|
|
||||||
if (state->count == 63) {
|
if (state->count == 63) {
|
||||||
/* this run is full; flush it */
|
/* this run is full; flush it */
|
||||||
if (bytes < 2)
|
if (bytes < 2) {
|
||||||
return ptr - buf;
|
return ptr - buf;
|
||||||
*ptr++ = 0xff;
|
}
|
||||||
*ptr++ = state->LAST;
|
ptr[0] = 0xff;
|
||||||
|
ptr[1] = state->LAST;
|
||||||
|
ptr += 2;
|
||||||
bytes -= 2;
|
bytes -= 2;
|
||||||
|
|
||||||
state->count = 0;
|
state->count = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this = state->buffer[state->x];
|
this = state->buffer[state->x];
|
||||||
|
|
||||||
if (this == state->LAST) {
|
if (this == state->LAST) {
|
||||||
/* extend the current run */
|
/* extend the current run */
|
||||||
state->x++;
|
state->x += 1;
|
||||||
state->count++;
|
state->count += 1;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* start a new run */
|
/* start a new run */
|
||||||
|
@ -126,15 +127,17 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
if (bytes < 1) {
|
if (bytes < 1) {
|
||||||
return ptr - buf;
|
return ptr - buf;
|
||||||
}
|
}
|
||||||
*ptr++ = state->LAST;
|
ptr[0] = state->LAST;
|
||||||
bytes--;
|
ptr += 1;
|
||||||
|
bytes -= 1;
|
||||||
} else {
|
} else {
|
||||||
if (state->count > 0) {
|
if (state->count > 0) {
|
||||||
if (bytes < 2) {
|
if (bytes < 2) {
|
||||||
return ptr - buf;
|
return ptr - buf;
|
||||||
}
|
}
|
||||||
*ptr++ = 0xc0 | state->count;
|
ptr[0] = 0xc0 | state->count;
|
||||||
*ptr++ = state->LAST;
|
ptr[1] = state->LAST;
|
||||||
|
ptr += 2;
|
||||||
bytes -= 2;
|
bytes -= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,8 +145,7 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
state->LAST = this;
|
state->LAST = this;
|
||||||
state->count = 1;
|
state->count = 1;
|
||||||
|
|
||||||
state->x++;
|
state->x += 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,33 +154,34 @@ ImagingPcxEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
||||||
if (bytes < 1 + padding) {
|
if (bytes < 1 + padding) {
|
||||||
return ptr - buf;
|
return ptr - buf;
|
||||||
}
|
}
|
||||||
*ptr++ = state->LAST;
|
ptr[0] = state->LAST;
|
||||||
bytes--;
|
ptr += 1;
|
||||||
|
bytes -= 1;
|
||||||
} else {
|
} else {
|
||||||
if (state->count > 0) {
|
if (state->count > 0) {
|
||||||
if (bytes < 2 + padding) {
|
if (bytes < 2 + padding) {
|
||||||
return ptr - buf;
|
return ptr - buf;
|
||||||
}
|
}
|
||||||
*ptr++ = 0xc0 | state->count;
|
ptr[0] = 0xc0 | state->count;
|
||||||
*ptr++ = state->LAST;
|
ptr[1] = state->LAST;
|
||||||
|
ptr += 2;
|
||||||
bytes -= 2;
|
bytes -= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bytes < padding) {
|
|
||||||
return ptr - buf;
|
|
||||||
}
|
|
||||||
/* add the padding */
|
/* add the padding */
|
||||||
for (i=0;i<padding;i++){
|
for (i = 0; i < padding; i++) {
|
||||||
*ptr++=0;
|
ptr[0] = 0;
|
||||||
bytes--;
|
ptr += 1;
|
||||||
|
bytes -= 1;
|
||||||
}
|
}
|
||||||
/* reset for the next color plane. */
|
/* reset for the next color plane. */
|
||||||
if (state->x < planes * bytes_per_line) {
|
if (state->x < planes * bytes_per_line) {
|
||||||
state->count = 1;
|
state->count = 1;
|
||||||
state->LAST = state->buffer[state->x];
|
state->LAST = state->buffer[state->x];
|
||||||
state->x++;
|
state->x += 1;
|
||||||
}
|
}
|
||||||
}
|
} while (state->x < planes * bytes_per_line);
|
||||||
|
|
||||||
/* read next line */
|
/* read next line */
|
||||||
state->state = FETCH;
|
state->state = FETCH;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user