mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 01:47:47 +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