mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 09:57:43 +03:00 
			
		
		
		
	Line too long
This commit is contained in:
		
							parent
							
								
									ce5d0e72b2
								
							
						
					
					
						commit
						c2189235af
					
				| 
						 | 
					@ -153,7 +153,8 @@ class PillowTestCase(unittest.TestCase):
 | 
				
			||||||
                    pass
 | 
					                    pass
 | 
				
			||||||
            raise e
 | 
					            raise e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def assert_image_similar_tofile(self, a, filename, epsilon, msg=None, mode=None):
 | 
					    def assert_image_similar_tofile(self, a, filename, epsilon, msg=None,
 | 
				
			||||||
 | 
					                                    mode=None):
 | 
				
			||||||
        with Image.open(filename) as img:
 | 
					        with Image.open(filename) as img:
 | 
				
			||||||
            if mode:
 | 
					            if mode:
 | 
				
			||||||
                img = img.convert(mode)
 | 
					                img = img.convert(mode)
 | 
				
			||||||
| 
						 | 
					@ -246,7 +247,8 @@ class PillowLeakTestCase(PillowTestCase):
 | 
				
			||||||
        mem = getrusage(RUSAGE_SELF).ru_maxrss
 | 
					        mem = getrusage(RUSAGE_SELF).ru_maxrss
 | 
				
			||||||
        if sys.platform == 'darwin':
 | 
					        if sys.platform == 'darwin':
 | 
				
			||||||
            # man 2 getrusage:
 | 
					            # man 2 getrusage:
 | 
				
			||||||
            #     ru_maxrss    the maximum resident set size utilized (in bytes).
 | 
					            #     ru_maxrss
 | 
				
			||||||
 | 
					            # This is the maximum resident set size utilized (in bytes).
 | 
				
			||||||
            return mem / 1024  # Kb
 | 
					            return mem / 1024  # Kb
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            # linux
 | 
					            # linux
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -410,7 +410,8 @@ class TestGenerateColorLut3D(PillowTestCase):
 | 
				
			||||||
        self.assertEqual(lut.name, "Color 3D LUT")
 | 
					        self.assertEqual(lut.name, "Color 3D LUT")
 | 
				
			||||||
        self.assertEqual(lut.table[:24], [
 | 
					        self.assertEqual(lut.table[:24], [
 | 
				
			||||||
            0.0, 0.0, 0.0, 0.0,  0.0, 0.25, 0.0, 0.125,  0.0, 0.5, 0.0, 0.25,
 | 
					            0.0, 0.0, 0.0, 0.0,  0.0, 0.25, 0.0, 0.125,  0.0, 0.5, 0.0, 0.25,
 | 
				
			||||||
            0.0, 0.75, 0.0, 0.375,  0.0, 1.0, 0.0, 0.5,  0.0, 0.0, 0.25, 0.125])
 | 
					            0.0, 0.75, 0.0, 0.375,  0.0, 1.0, 0.0, 0.5,  0.0, 0.0, 0.25, 0.125
 | 
				
			||||||
 | 
					        ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_apply(self):
 | 
					    def test_apply(self):
 | 
				
			||||||
        lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b))
 | 
					        lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -402,7 +402,8 @@ class TestFileGif(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_comment(self):
 | 
					    def test_comment(self):
 | 
				
			||||||
        im = Image.open(TEST_GIF)
 | 
					        im = Image.open(TEST_GIF)
 | 
				
			||||||
        self.assertEqual(im.info['comment'], b"File written by Adobe Photoshop\xa8 4.0")
 | 
					        self.assertEqual(im.info['comment'],
 | 
				
			||||||
 | 
					                         b"File written by Adobe Photoshop\xa8 4.0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        out = self.tempfile('temp.gif')
 | 
					        out = self.tempfile('temp.gif')
 | 
				
			||||||
        im = Image.new('L', (100, 100), '#000')
 | 
					        im = Image.new('L', (100, 100), '#000')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,7 +126,8 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
            im.tile[0][:3], ('tiff_adobe_deflate', (0, 0, 278, 374), 0))
 | 
					            im.tile[0][:3], ('tiff_adobe_deflate', (0, 0, 278, 374), 0))
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assert_image_equal_tofile(im, 'Tests/images/tiff_adobe_deflate.png')
 | 
					        self.assert_image_equal_tofile(im,
 | 
				
			||||||
 | 
					                                       'Tests/images/tiff_adobe_deflate.png')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_write_metadata(self):
 | 
					    def test_write_metadata(self):
 | 
				
			||||||
        """ Test metadata writing through libtiff """
 | 
					        """ Test metadata writing through libtiff """
 | 
				
			||||||
| 
						 | 
					@ -217,7 +218,8 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
            if info.length == 0:
 | 
					            if info.length == 0:
 | 
				
			||||||
                new_ifd[tag] = tuple(values[info.type] for _ in range(3))
 | 
					                new_ifd[tag] = tuple(values[info.type] for _ in range(3))
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                new_ifd[tag] = tuple(values[info.type] for _ in range(info.length))
 | 
					                new_ifd[tag] = tuple(values[info.type]
 | 
				
			||||||
 | 
					                                     for _ in range(info.length))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Extra samples really doesn't make sense in this application.
 | 
					        # Extra samples really doesn't make sense in this application.
 | 
				
			||||||
        del(new_ifd[338])
 | 
					        del(new_ifd[338])
 | 
				
			||||||
| 
						 | 
					@ -578,10 +580,14 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(im.mode, "RGBA")
 | 
					        self.assertEqual(im.mode, "RGBA")
 | 
				
			||||||
        self.assertEqual(im.size, (100, 40))
 | 
					        self.assertEqual(im.size, (100, 40))
 | 
				
			||||||
        self.assertEqual(im.tile, [('tiff_lzw', (0, 0, 100, 40), 0, ('RGBa;16N', 'tiff_lzw', False))])
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            im.tile,
 | 
				
			||||||
 | 
					            [('tiff_lzw', (0, 0, 100, 40), 0, ('RGBa;16N', 'tiff_lzw', False))]
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png")
 | 
					        self.assert_image_equal_tofile(
 | 
				
			||||||
 | 
					            im, "Tests/images/tiff_16bit_RGBa_target.png")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_gimp_tiff(self):
 | 
					    def test_gimp_tiff(self):
 | 
				
			||||||
        # Read TIFF JPEG images from GIMP [@PIL168]
 | 
					        # Read TIFF JPEG images from GIMP [@PIL168]
 | 
				
			||||||
| 
						 | 
					@ -607,7 +613,8 @@ class TestFileLibTiff(LibTiffTestCase):
 | 
				
			||||||
        im = Image.open("Tests/images/copyleft.tiff")
 | 
					        im = Image.open("Tests/images/copyleft.tiff")
 | 
				
			||||||
        self.assertEqual(im.mode, 'RGB')
 | 
					        self.assertEqual(im.mode, 'RGB')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assert_image_equal_tofile(im, "Tests/images/copyleft.png", mode='RGB')
 | 
					        self.assert_image_equal_tofile(im, "Tests/images/copyleft.png",
 | 
				
			||||||
 | 
					                                       mode='RGB')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_lzw(self):
 | 
					    def test_lzw(self):
 | 
				
			||||||
        im = Image.open("Tests/images/hopper_lzw.tif")
 | 
					        im = Image.open("Tests/images/hopper_lzw.tif")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,8 @@ class TestFilePdf(PillowTestCase):
 | 
				
			||||||
        self.assertTrue(os.path.isfile(outfile))
 | 
					        self.assertTrue(os.path.isfile(outfile))
 | 
				
			||||||
        self.assertGreater(os.path.getsize(outfile), 0)
 | 
					        self.assertGreater(os.path.getsize(outfile), 0)
 | 
				
			||||||
        with PdfParser.PdfParser(outfile) as pdf:
 | 
					        with PdfParser.PdfParser(outfile) as pdf:
 | 
				
			||||||
            if kwargs.get("append_images", False) or kwargs.get("append", False):
 | 
					            if kwargs.get("append_images", False) or \
 | 
				
			||||||
 | 
					               kwargs.get("append", False):
 | 
				
			||||||
                self.assertGreater(len(pdf.pages), 1)
 | 
					                self.assertGreater(len(pdf.pages), 1)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                self.assertGreater(len(pdf.pages), 0)
 | 
					                self.assertGreater(len(pdf.pages), 0)
 | 
				
			||||||
| 
						 | 
					@ -116,7 +117,9 @@ class TestFilePdf(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_pdf_open(self):
 | 
					    def test_pdf_open(self):
 | 
				
			||||||
        # fail on a buffer full of null bytes
 | 
					        # fail on a buffer full of null bytes
 | 
				
			||||||
        self.assertRaises(PdfParser.PdfFormatError, PdfParser.PdfParser, buf=bytearray(65536))
 | 
					        self.assertRaises(
 | 
				
			||||||
 | 
					            PdfParser.PdfFormatError,
 | 
				
			||||||
 | 
					            PdfParser.PdfParser, buf=bytearray(65536))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # make an empty PDF object
 | 
					        # make an empty PDF object
 | 
				
			||||||
        with PdfParser.PdfParser() as empty_pdf:
 | 
					        with PdfParser.PdfParser() as empty_pdf:
 | 
				
			||||||
| 
						 | 
					@ -153,7 +156,10 @@ class TestFilePdf(PillowTestCase):
 | 
				
			||||||
        im = hopper("RGB")
 | 
					        im = hopper("RGB")
 | 
				
			||||||
        temp_dir = tempfile.mkdtemp()
 | 
					        temp_dir = tempfile.mkdtemp()
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self.assertRaises(IOError, im.save, os.path.join(temp_dir, "nonexistent.pdf"), append=True)
 | 
					            self.assertRaises(IOError,
 | 
				
			||||||
 | 
					                              im.save,
 | 
				
			||||||
 | 
					                              os.path.join(temp_dir, "nonexistent.pdf"),
 | 
				
			||||||
 | 
					                              append=True)
 | 
				
			||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
            os.rmdir(temp_dir)
 | 
					            os.rmdir(temp_dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -204,7 +210,8 @@ class TestFilePdf(PillowTestCase):
 | 
				
			||||||
        # append two images
 | 
					        # append two images
 | 
				
			||||||
        mode_CMYK = hopper("CMYK")
 | 
					        mode_CMYK = hopper("CMYK")
 | 
				
			||||||
        mode_P = hopper("P")
 | 
					        mode_P = hopper("P")
 | 
				
			||||||
        mode_CMYK.save(pdf_filename, append=True, save_all=True, append_images=[mode_P])
 | 
					        mode_CMYK.save(pdf_filename,
 | 
				
			||||||
 | 
					                       append=True, save_all=True, append_images=[mode_P])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # open the PDF again, check pages and info again
 | 
					        # open the PDF again, check pages and info again
 | 
				
			||||||
        with PdfParser.PdfParser(pdf_filename) as pdf:
 | 
					        with PdfParser.PdfParser(pdf_filename) as pdf:
 | 
				
			||||||
| 
						 | 
					@ -219,7 +226,9 @@ class TestFilePdf(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_pdf_info(self):
 | 
					    def test_pdf_info(self):
 | 
				
			||||||
        # make a PDF file
 | 
					        # make a PDF file
 | 
				
			||||||
        pdf_filename = self.helper_save_as_pdf("RGB", title="title", author="author", subject="subject", keywords="keywords", creator="creator", producer="producer")
 | 
					        pdf_filename = self.helper_save_as_pdf(
 | 
				
			||||||
 | 
					            "RGB", title="title", author="author", subject="subject",
 | 
				
			||||||
 | 
					            keywords="keywords", creator="creator", producer="producer")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # open it, check pages and info
 | 
					        # open it, check pages and info
 | 
				
			||||||
        with PdfParser.PdfParser(pdf_filename) as pdf:
 | 
					        with PdfParser.PdfParser(pdf_filename) as pdf:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -355,7 +355,8 @@ class TestFilePng(PillowTestCase):
 | 
				
			||||||
        broken_crc_chunk_data = chunk_data[:-1] + b'q'  # break CRC
 | 
					        broken_crc_chunk_data = chunk_data[:-1] + b'q'  # break CRC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        image_data = HEAD + broken_crc_chunk_data + TAIL
 | 
					        image_data = HEAD + broken_crc_chunk_data + TAIL
 | 
				
			||||||
        self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile, BytesIO(image_data))
 | 
					        self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile,
 | 
				
			||||||
 | 
					                          BytesIO(image_data))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ImageFile.LOAD_TRUNCATED_IMAGES = True
 | 
					        ImageFile.LOAD_TRUNCATED_IMAGES = True
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
| 
						 | 
					@ -371,7 +372,8 @@ class TestFilePng(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ImageFile.LOAD_TRUNCATED_IMAGES = True
 | 
					        ImageFile.LOAD_TRUNCATED_IMAGES = True
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile, BytesIO(image_data))
 | 
					            self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile,
 | 
				
			||||||
 | 
					                              BytesIO(image_data))
 | 
				
			||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
            ImageFile.LOAD_TRUNCATED_IMAGES = False
 | 
					            ImageFile.LOAD_TRUNCATED_IMAGES = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -444,7 +444,8 @@ class TestFileTiff(PillowTestCase):
 | 
				
			||||||
            for im in ims:
 | 
					            for im in ims:
 | 
				
			||||||
                yield im
 | 
					                yield im
 | 
				
			||||||
        mp = io.BytesIO()
 | 
					        mp = io.BytesIO()
 | 
				
			||||||
        im.save(mp, format="TIFF", save_all=True, append_images=imGenerator(ims))
 | 
					        im.save(mp, format="TIFF", save_all=True,
 | 
				
			||||||
 | 
					                append_images=imGenerator(ims))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mp.seek(0, os.SEEK_SET)
 | 
					        mp.seek(0, os.SEEK_SET)
 | 
				
			||||||
        reread = Image.open(mp)
 | 
					        reread = Image.open(mp)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,7 +16,8 @@ class TestTTypeFontLeak(PillowLeakTestCase):
 | 
				
			||||||
        self._test_leak(lambda: draw.text((0, 0), "some text "*1024,  # ~10k
 | 
					        self._test_leak(lambda: draw.text((0, 0), "some text "*1024,  # ~10k
 | 
				
			||||||
                                          font=font, fill="black"))
 | 
					                                          font=font, fill="black"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipIf(not features.check('freetype2'), "Test requires freetype2")
 | 
					    @unittest.skipIf(not features.check('freetype2'),
 | 
				
			||||||
 | 
					                     "Test requires freetype2")
 | 
				
			||||||
    def test_leak(self):
 | 
					    def test_leak(self):
 | 
				
			||||||
        ttype = ImageFont.truetype('Tests/fonts/FreeMono.ttf', 20)
 | 
					        ttype = ImageFont.truetype('Tests/fonts/FreeMono.ttf', 20)
 | 
				
			||||||
        self._test_font(ttype)
 | 
					        self._test_font(ttype)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -294,7 +294,8 @@ int main(int argc, char* argv[])
 | 
				
			||||||
        compiler = ccompiler.new_compiler()
 | 
					        compiler = ccompiler.new_compiler()
 | 
				
			||||||
        compiler.add_include_dir(sysconfig.get_python_inc())
 | 
					        compiler.add_include_dir(sysconfig.get_python_inc())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        libdir = sysconfig.get_config_var('LIBDIR') or sysconfig.get_python_inc().replace('include', 'libs')
 | 
					        libdir = (sysconfig.get_config_var('LIBDIR') or
 | 
				
			||||||
 | 
					                  sysconfig.get_python_inc().replace('include', 'libs'))
 | 
				
			||||||
        print(libdir)
 | 
					        print(libdir)
 | 
				
			||||||
        compiler.add_library_dir(libdir)
 | 
					        compiler.add_library_dir(libdir)
 | 
				
			||||||
        objects = compiler.compile(['embed_pil.c'])
 | 
					        objects = compiler.compile(['embed_pil.c'])
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,9 +15,11 @@ class TestImageArray(PillowTestCase):
 | 
				
			||||||
        self.assertEqual(test("L"), (3, (100, 128), '|u1', 12800))
 | 
					        self.assertEqual(test("L"), (3, (100, 128), '|u1', 12800))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # FIXME: wrong?
 | 
					        # FIXME: wrong?
 | 
				
			||||||
        self.assertEqual(test("I"), (3, (100, 128), Image._ENDIAN + 'i4', 51200))
 | 
					        self.assertEqual(test("I"), (3, (100, 128),
 | 
				
			||||||
 | 
					                         Image._ENDIAN + 'i4', 51200))
 | 
				
			||||||
        # FIXME: wrong?
 | 
					        # FIXME: wrong?
 | 
				
			||||||
        self.assertEqual(test("F"), (3, (100, 128), Image._ENDIAN + 'f4', 51200))
 | 
					        self.assertEqual(test("F"), (3, (100, 128),
 | 
				
			||||||
 | 
					                         Image._ENDIAN + 'f4', 51200))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(test("LA"), (3, (100, 128, 2), '|u1', 25600))
 | 
					        self.assertEqual(test("LA"), (3, (100, 128, 2), '|u1', 25600))
 | 
				
			||||||
        self.assertEqual(test("RGB"), (3, (100, 128, 3), '|u1', 38400))
 | 
					        self.assertEqual(test("RGB"), (3, (100, 128, 3), '|u1', 38400))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -193,7 +193,8 @@ class TestImageConvert(PillowTestCase):
 | 
				
			||||||
            if converted_im.mode == 'RGB':
 | 
					            if converted_im.mode == 'RGB':
 | 
				
			||||||
                self.assert_image_similar(converted_im, target, 3)
 | 
					                self.assert_image_similar(converted_im, target, 3)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                self.assert_image_similar(converted_im, target.getchannel(0), 1)
 | 
					                self.assert_image_similar(converted_im,
 | 
				
			||||||
 | 
					                                          target.getchannel(0), 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        matrix_convert('RGB')
 | 
					        matrix_convert('RGB')
 | 
				
			||||||
        matrix_convert('L')
 | 
					        matrix_convert('L')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -288,10 +288,14 @@ class CoreResampleAlphaCorrectTest(PillowTestCase):
 | 
				
			||||||
    def test_dirty_pixels_rgba(self):
 | 
					    def test_dirty_pixels_rgba(self):
 | 
				
			||||||
        case = self.make_dirty_case('RGBA', (255, 255, 0, 128), (0, 0, 255, 0))
 | 
					        case = self.make_dirty_case('RGBA', (255, 255, 0, 128), (0, 0, 255, 0))
 | 
				
			||||||
        self.run_dirty_case(case.resize((20, 20), Image.BOX), (255, 255, 0))
 | 
					        self.run_dirty_case(case.resize((20, 20), Image.BOX), (255, 255, 0))
 | 
				
			||||||
        self.run_dirty_case(case.resize((20, 20), Image.BILINEAR), (255, 255, 0))
 | 
					        self.run_dirty_case(case.resize((20, 20), Image.BILINEAR),
 | 
				
			||||||
        self.run_dirty_case(case.resize((20, 20), Image.HAMMING), (255, 255, 0))
 | 
					                            (255, 255, 0))
 | 
				
			||||||
        self.run_dirty_case(case.resize((20, 20), Image.BICUBIC), (255, 255, 0))
 | 
					        self.run_dirty_case(case.resize((20, 20), Image.HAMMING),
 | 
				
			||||||
        self.run_dirty_case(case.resize((20, 20), Image.LANCZOS), (255, 255, 0))
 | 
					                            (255, 255, 0))
 | 
				
			||||||
 | 
					        self.run_dirty_case(case.resize((20, 20), Image.BICUBIC),
 | 
				
			||||||
 | 
					                            (255, 255, 0))
 | 
				
			||||||
 | 
					        self.run_dirty_case(case.resize((20, 20), Image.LANCZOS),
 | 
				
			||||||
 | 
					                            (255, 255, 0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_dirty_pixels_la(self):
 | 
					    def test_dirty_pixels_la(self):
 | 
				
			||||||
        case = self.make_dirty_case('LA', (255, 128), (0, 0))
 | 
					        case = self.make_dirty_case('LA', (255, 128), (0, 0))
 | 
				
			||||||
| 
						 | 
					@ -367,23 +371,28 @@ class CoreResampleCoefficientsTest(PillowTestCase):
 | 
				
			||||||
        im = Image.new('RGBA', (1280, 1280), (0x20, 0x40, 0x60, 0xff))
 | 
					        im = Image.new('RGBA', (1280, 1280), (0x20, 0x40, 0x60, 0xff))
 | 
				
			||||||
        histogram = im.resize((256, 256), Image.BICUBIC).histogram()
 | 
					        histogram = im.resize((256, 256), Image.BICUBIC).histogram()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(histogram[0x100 * 0 + 0x20], 0x10000)  # first channel
 | 
					        # first channel
 | 
				
			||||||
        self.assertEqual(histogram[0x100 * 1 + 0x40], 0x10000)  # second channel
 | 
					        self.assertEqual(histogram[0x100 * 0 + 0x20], 0x10000)
 | 
				
			||||||
        self.assertEqual(histogram[0x100 * 2 + 0x60], 0x10000)  # third channel
 | 
					        # second channel
 | 
				
			||||||
        self.assertEqual(histogram[0x100 * 3 + 0xff], 0x10000)  # fourth channel
 | 
					        self.assertEqual(histogram[0x100 * 1 + 0x40], 0x10000)
 | 
				
			||||||
 | 
					        # third channel
 | 
				
			||||||
 | 
					        self.assertEqual(histogram[0x100 * 2 + 0x60], 0x10000)
 | 
				
			||||||
 | 
					        # fourth channel
 | 
				
			||||||
 | 
					        self.assertEqual(histogram[0x100 * 3 + 0xff], 0x10000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CoreResampleBoxTest(PillowTestCase):
 | 
					class CoreResampleBoxTest(PillowTestCase):
 | 
				
			||||||
    def test_wrong_arguments(self):
 | 
					    def test_wrong_arguments(self):
 | 
				
			||||||
        im = hopper()
 | 
					        im = hopper()
 | 
				
			||||||
        for resample in (Image.NEAREST, Image.BOX, Image.BILINEAR, Image.HAMMING,
 | 
					        for resample in (Image.NEAREST, Image.BOX, Image.BILINEAR,
 | 
				
			||||||
                Image.BICUBIC, Image.LANCZOS):
 | 
					                         Image.HAMMING, Image.BICUBIC, Image.LANCZOS):
 | 
				
			||||||
            im.resize((32, 32), resample, (0, 0, im.width, im.height))
 | 
					            im.resize((32, 32), resample, (0, 0, im.width, im.height))
 | 
				
			||||||
            im.resize((32, 32), resample, (20, 20, im.width, im.height))
 | 
					            im.resize((32, 32), resample, (20, 20, im.width, im.height))
 | 
				
			||||||
            im.resize((32, 32), resample, (20, 20, 20, 100))
 | 
					            im.resize((32, 32), resample, (20, 20, 20, 100))
 | 
				
			||||||
            im.resize((32, 32), resample, (20, 20, 100, 20))
 | 
					            im.resize((32, 32), resample, (20, 20, 100, 20))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            with self.assertRaisesRegex(TypeError, "must be sequence of length 4"):
 | 
					            with self.assertRaisesRegex(TypeError,
 | 
				
			||||||
 | 
					                                        "must be sequence of length 4"):
 | 
				
			||||||
                im.resize((32, 32), resample, (im.width, im.height))
 | 
					                im.resize((32, 32), resample, (im.width, im.height))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            with self.assertRaisesRegex(ValueError, "can't be negative"):
 | 
					            with self.assertRaisesRegex(ValueError, "can't be negative"):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -95,7 +95,8 @@ class TestImageRotate(PillowTestCase):
 | 
				
			||||||
        im = hopper()
 | 
					        im = hopper()
 | 
				
			||||||
        self.rotate(im, im.mode, 45, center=(0, 0))
 | 
					        self.rotate(im, im.mode, 45, center=(0, 0))
 | 
				
			||||||
        self.rotate(im, im.mode, 45, translate=(im.size[0]/2, 0))
 | 
					        self.rotate(im, im.mode, 45, translate=(im.size[0]/2, 0))
 | 
				
			||||||
        self.rotate(im, im.mode, 45, center=(0, 0), translate=(im.size[0]/2, 0))
 | 
					        self.rotate(im, im.mode, 45, center=(0, 0),
 | 
				
			||||||
 | 
					                    translate=(im.size[0]/2, 0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_rotate_no_fill(self):
 | 
					    def test_rotate_no_fill(self):
 | 
				
			||||||
        im = Image.new('RGB', (100, 100), 'green')
 | 
					        im = Image.new('RGB', (100, 100), 'green')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,8 +43,9 @@ class TestToQImage(PillowQtTestCase, PillowTestCase):
 | 
				
			||||||
            if mode == '1':
 | 
					            if mode == '1':
 | 
				
			||||||
                # BW appears to not save correctly on QT4 and QT5
 | 
					                # BW appears to not save correctly on QT4 and QT5
 | 
				
			||||||
                # kicks out errors on console:
 | 
					                # kicks out errors on console:
 | 
				
			||||||
                # libpng warning: Invalid color type/bit depth combination in IHDR
 | 
					                #     libpng warning: Invalid color type/bit depth combination
 | 
				
			||||||
                # libpng error: Invalid IHDR data
 | 
					                #                     in IHDR
 | 
				
			||||||
 | 
					                #     libpng error: Invalid IHDR data
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Test saving the file
 | 
					            # Test saving the file
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -286,53 +286,104 @@ class TestImageCms(PillowTestCase):
 | 
				
			||||||
            self.assertEqual(truncate_tuple(tup1), truncate_tuple(tup2))
 | 
					            self.assertEqual(truncate_tuple(tup1), truncate_tuple(tup2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(p.attributes, 4294967296)
 | 
					        self.assertEqual(p.attributes, 4294967296)
 | 
				
			||||||
        assert_truncated_tuple_equal(p.blue_colorant, ((0.14306640625, 0.06060791015625, 0.7140960693359375), (0.1558847490315394, 0.06603820639433387, 0.06060791015625)))
 | 
					        assert_truncated_tuple_equal(
 | 
				
			||||||
        assert_truncated_tuple_equal(p.blue_primary, ((0.14306641366715667, 0.06060790921083026, 0.7140960805782015), (0.15588475410450106, 0.06603820408959558, 0.06060790921083026)))
 | 
					            p.blue_colorant,
 | 
				
			||||||
 | 
					            ((0.14306640625, 0.06060791015625, 0.7140960693359375),
 | 
				
			||||||
 | 
					             (0.1558847490315394, 0.06603820639433387, 0.06060791015625)))
 | 
				
			||||||
 | 
					        assert_truncated_tuple_equal(
 | 
				
			||||||
 | 
					            p.blue_primary,
 | 
				
			||||||
 | 
					            ((0.14306641366715667, 0.06060790921083026, 0.7140960805782015),
 | 
				
			||||||
 | 
					             (0.15588475410450106, 0.06603820408959558, 0.06060790921083026)))
 | 
				
			||||||
        assert_truncated_tuple_equal(p.chromatic_adaptation, (((1.04791259765625, 0.0229339599609375, -0.050201416015625), (0.02960205078125, 0.9904632568359375, -0.0170745849609375), (-0.009246826171875, 0.0150604248046875, 0.7517852783203125)), ((1.0267159024652783, 0.022470062342089134, 0.0229339599609375), (0.02951378324103937, 0.9875098886387147, 0.9904632568359375), (-0.012205438066465256, 0.01987915407854985, 0.0150604248046875))))
 | 
					        assert_truncated_tuple_equal(p.chromatic_adaptation, (((1.04791259765625, 0.0229339599609375, -0.050201416015625), (0.02960205078125, 0.9904632568359375, -0.0170745849609375), (-0.009246826171875, 0.0150604248046875, 0.7517852783203125)), ((1.0267159024652783, 0.022470062342089134, 0.0229339599609375), (0.02951378324103937, 0.9875098886387147, 0.9904632568359375), (-0.012205438066465256, 0.01987915407854985, 0.0150604248046875))))
 | 
				
			||||||
        self.assertIsNone(p.chromaticity)
 | 
					        self.assertIsNone(p.chromaticity)
 | 
				
			||||||
        self.assertEqual(p.clut, {0: (False, False, True), 1: (False, False, True), 2: (False, False, True), 3: (False, False, True)})
 | 
					        self.assertEqual(p.clut, {
 | 
				
			||||||
 | 
					            0: (False, False, True),
 | 
				
			||||||
 | 
					            1: (False, False, True),
 | 
				
			||||||
 | 
					            2: (False, False, True),
 | 
				
			||||||
 | 
					            3: (False, False, True)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
        self.assertEqual(p.color_space, 'RGB')
 | 
					        self.assertEqual(p.color_space, 'RGB')
 | 
				
			||||||
        self.assertIsNone(p.colorant_table)
 | 
					        self.assertIsNone(p.colorant_table)
 | 
				
			||||||
        self.assertIsNone(p.colorant_table_out)
 | 
					        self.assertIsNone(p.colorant_table_out)
 | 
				
			||||||
        self.assertIsNone(p.colorimetric_intent)
 | 
					        self.assertIsNone(p.colorimetric_intent)
 | 
				
			||||||
        self.assertEqual(p.connection_space, 'XYZ ')
 | 
					        self.assertEqual(p.connection_space, 'XYZ ')
 | 
				
			||||||
        self.assertEqual(p.copyright, 'Copyright International Color Consortium, 2009')
 | 
					        self.assertEqual(p.copyright,
 | 
				
			||||||
        self.assertEqual(p.creation_date, datetime.datetime(2009, 2, 27, 21, 36, 31))
 | 
					                         'Copyright International Color Consortium, 2009')
 | 
				
			||||||
 | 
					        self.assertEqual(p.creation_date,
 | 
				
			||||||
 | 
					                         datetime.datetime(2009, 2, 27, 21, 36, 31))
 | 
				
			||||||
        self.assertEqual(p.device_class, 'mntr')
 | 
					        self.assertEqual(p.device_class, 'mntr')
 | 
				
			||||||
        assert_truncated_tuple_equal(p.green_colorant, ((0.3851470947265625, 0.7168731689453125, 0.097076416015625), (0.32119769927720654, 0.5978443449048152, 0.7168731689453125)))
 | 
					        assert_truncated_tuple_equal(
 | 
				
			||||||
        assert_truncated_tuple_equal(p.green_primary, ((0.3851470888162112, 0.7168731974161346, 0.09707641738998518), (0.32119768793686687, 0.5978443567149709, 0.7168731974161346)))
 | 
					            p.green_colorant,
 | 
				
			||||||
 | 
					            ((0.3851470947265625, 0.7168731689453125, 0.097076416015625),
 | 
				
			||||||
 | 
					             (0.32119769927720654, 0.5978443449048152, 0.7168731689453125)))
 | 
				
			||||||
 | 
					        assert_truncated_tuple_equal(
 | 
				
			||||||
 | 
					            p.green_primary,
 | 
				
			||||||
 | 
					            ((0.3851470888162112, 0.7168731974161346, 0.09707641738998518),
 | 
				
			||||||
 | 
					             (0.32119768793686687, 0.5978443567149709, 0.7168731974161346)))
 | 
				
			||||||
        self.assertEqual(p.header_flags, 0)
 | 
					        self.assertEqual(p.header_flags, 0)
 | 
				
			||||||
        self.assertEqual(p.header_manufacturer, '\x00\x00\x00\x00')
 | 
					        self.assertEqual(p.header_manufacturer, '\x00\x00\x00\x00')
 | 
				
			||||||
        self.assertEqual(p.header_model, '\x00\x00\x00\x00')
 | 
					        self.assertEqual(p.header_model, '\x00\x00\x00\x00')
 | 
				
			||||||
        self.assertEqual(p.icc_measurement_condition, {'backing': (0.0, 0.0, 0.0), 'flare': 0.0, 'geo': 'unknown', 'observer': 1, 'illuminant_type': 'D65'})
 | 
					        self.assertEqual(p.icc_measurement_condition, {
 | 
				
			||||||
 | 
					            'backing': (0.0, 0.0, 0.0),
 | 
				
			||||||
 | 
					            'flare': 0.0,
 | 
				
			||||||
 | 
					            'geo': 'unknown',
 | 
				
			||||||
 | 
					            'observer': 1,
 | 
				
			||||||
 | 
					            'illuminant_type': 'D65'
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
        self.assertEqual(p.icc_version, 33554432)
 | 
					        self.assertEqual(p.icc_version, 33554432)
 | 
				
			||||||
        self.assertIsNone(p.icc_viewing_condition)
 | 
					        self.assertIsNone(p.icc_viewing_condition)
 | 
				
			||||||
        self.assertEqual(p.intent_supported, {0: (True, True, True), 1: (True, True, True), 2: (True, True, True), 3: (True, True, True)})
 | 
					        self.assertEqual(p.intent_supported, {
 | 
				
			||||||
 | 
					            0: (True, True, True),
 | 
				
			||||||
 | 
					            1: (True, True, True),
 | 
				
			||||||
 | 
					            2: (True, True, True),
 | 
				
			||||||
 | 
					            3: (True, True, True)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
        self.assertTrue(p.is_matrix_shaper)
 | 
					        self.assertTrue(p.is_matrix_shaper)
 | 
				
			||||||
        self.assertEqual(p.luminance, ((0.0, 80.0, 0.0), (0.0, 1.0, 80.0)))
 | 
					        self.assertEqual(p.luminance, ((0.0, 80.0, 0.0), (0.0, 1.0, 80.0)))
 | 
				
			||||||
        self.assertIsNone(p.manufacturer)
 | 
					        self.assertIsNone(p.manufacturer)
 | 
				
			||||||
        assert_truncated_tuple_equal(p.media_black_point, ((0.012054443359375, 0.0124969482421875, 0.01031494140625), (0.34573304157549234, 0.35842450765864337, 0.0124969482421875)))
 | 
					        assert_truncated_tuple_equal(
 | 
				
			||||||
        assert_truncated_tuple_equal(p.media_white_point, ((0.964202880859375, 1.0, 0.8249053955078125), (0.3457029219802284, 0.3585375327567059, 1.0)))
 | 
					            p.media_black_point,
 | 
				
			||||||
        assert_truncated_tuple_equal((p.media_white_point_temperature,), (5000.722328847392,))
 | 
					            ((0.012054443359375, 0.0124969482421875, 0.01031494140625),
 | 
				
			||||||
        self.assertEqual(p.model, 'IEC 61966-2-1 Default RGB Colour Space - sRGB')
 | 
					             (0.34573304157549234, 0.35842450765864337, 0.0124969482421875)))
 | 
				
			||||||
 | 
					        assert_truncated_tuple_equal(
 | 
				
			||||||
 | 
					            p.media_white_point,
 | 
				
			||||||
 | 
					            ((0.964202880859375, 1.0, 0.8249053955078125),
 | 
				
			||||||
 | 
					             (0.3457029219802284, 0.3585375327567059, 1.0)))
 | 
				
			||||||
 | 
					        assert_truncated_tuple_equal(
 | 
				
			||||||
 | 
					            (p.media_white_point_temperature,),
 | 
				
			||||||
 | 
					            (5000.722328847392,))
 | 
				
			||||||
 | 
					        self.assertEqual(p.model,
 | 
				
			||||||
 | 
					                         'IEC 61966-2-1 Default RGB Colour Space - sRGB')
 | 
				
			||||||
        self.assertEqual(p.pcs, 'XYZ')
 | 
					        self.assertEqual(p.pcs, 'XYZ')
 | 
				
			||||||
        self.assertIsNone(p.perceptual_rendering_intent_gamut)
 | 
					        self.assertIsNone(p.perceptual_rendering_intent_gamut)
 | 
				
			||||||
        self.assertEqual(p.product_copyright, 'Copyright International Color Consortium, 2009')
 | 
					        self.assertEqual(p.product_copyright,
 | 
				
			||||||
 | 
					                         'Copyright International Color Consortium, 2009')
 | 
				
			||||||
        self.assertEqual(p.product_desc, 'sRGB IEC61966-2-1 black scaled')
 | 
					        self.assertEqual(p.product_desc, 'sRGB IEC61966-2-1 black scaled')
 | 
				
			||||||
        self.assertEqual(p.product_description, 'sRGB IEC61966-2-1 black scaled')
 | 
					        self.assertEqual(p.product_description,
 | 
				
			||||||
 | 
					                         'sRGB IEC61966-2-1 black scaled')
 | 
				
			||||||
        self.assertEqual(p.product_manufacturer, '')
 | 
					        self.assertEqual(p.product_manufacturer, '')
 | 
				
			||||||
        self.assertEqual(p.product_model, 'IEC 61966-2-1 Default RGB Colour Space - sRGB')
 | 
					        self.assertEqual(
 | 
				
			||||||
        self.assertEqual(p.profile_description, 'sRGB IEC61966-2-1 black scaled')
 | 
					            p.product_model, 'IEC 61966-2-1 Default RGB Colour Space - sRGB')
 | 
				
			||||||
        self.assertEqual(p.profile_id, b')\xf8=\xde\xaf\xf2U\xaexB\xfa\xe4\xca\x839\r')
 | 
					        self.assertEqual(
 | 
				
			||||||
        assert_truncated_tuple_equal(p.red_colorant, ((0.436065673828125, 0.2224884033203125, 0.013916015625), (0.6484536316398539, 0.3308524880306778, 0.2224884033203125)))
 | 
					            p.profile_description, 'sRGB IEC61966-2-1 black scaled')
 | 
				
			||||||
        assert_truncated_tuple_equal(p.red_primary, ((0.43606566581047446, 0.22248840582960838, 0.013916015621759925), (0.6484536250319214, 0.3308524944738204, 0.22248840582960838)))
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            p.profile_id, b')\xf8=\xde\xaf\xf2U\xaexB\xfa\xe4\xca\x839\r')
 | 
				
			||||||
 | 
					        assert_truncated_tuple_equal(
 | 
				
			||||||
 | 
					            p.red_colorant,
 | 
				
			||||||
 | 
					            ((0.436065673828125, 0.2224884033203125, 0.013916015625),
 | 
				
			||||||
 | 
					             (0.6484536316398539, 0.3308524880306778, 0.2224884033203125)))
 | 
				
			||||||
 | 
					        assert_truncated_tuple_equal(
 | 
				
			||||||
 | 
					            p.red_primary,
 | 
				
			||||||
 | 
					            ((0.43606566581047446, 0.22248840582960838, 0.013916015621759925),
 | 
				
			||||||
 | 
					             (0.6484536250319214, 0.3308524944738204, 0.22248840582960838)))
 | 
				
			||||||
        self.assertEqual(p.rendering_intent, 0)
 | 
					        self.assertEqual(p.rendering_intent, 0)
 | 
				
			||||||
        self.assertIsNone(p.saturation_rendering_intent_gamut)
 | 
					        self.assertIsNone(p.saturation_rendering_intent_gamut)
 | 
				
			||||||
        self.assertIsNone(p.screening_description)
 | 
					        self.assertIsNone(p.screening_description)
 | 
				
			||||||
        self.assertIsNone(p.target)
 | 
					        self.assertIsNone(p.target)
 | 
				
			||||||
        self.assertEqual(p.technology, 'CRT ')
 | 
					        self.assertEqual(p.technology, 'CRT ')
 | 
				
			||||||
        self.assertEqual(p.version, 2.0)
 | 
					        self.assertEqual(p.version, 2.0)
 | 
				
			||||||
        self.assertEqual(p.viewing_condition, 'Reference Viewing Condition in IEC 61966-2-1')
 | 
					        self.assertEqual(p.viewing_condition,
 | 
				
			||||||
 | 
					                         'Reference Viewing Condition in IEC 61966-2-1')
 | 
				
			||||||
        self.assertEqual(p.xcolor_space, 'RGB ')
 | 
					        self.assertEqual(p.xcolor_space, 'RGB ')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_profile_typesafety(self):
 | 
					    def test_profile_typesafety(self):
 | 
				
			||||||
| 
						 | 
					@ -346,7 +397,8 @@ class TestImageCms(PillowTestCase):
 | 
				
			||||||
        with self.assertRaises(TypeError):
 | 
					        with self.assertRaises(TypeError):
 | 
				
			||||||
            ImageCms.ImageCmsProfile(1).tobytes()
 | 
					            ImageCms.ImageCmsProfile(1).tobytes()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def assert_aux_channel_preserved(self, mode, transform_in_place, preserved_channel):
 | 
					    def assert_aux_channel_preserved(self, mode,
 | 
				
			||||||
 | 
					                                     transform_in_place, preserved_channel):
 | 
				
			||||||
        def create_test_image():
 | 
					        def create_test_image():
 | 
				
			||||||
            # set up test image with something interesting in the tested aux
 | 
					            # set up test image with something interesting in the tested aux
 | 
				
			||||||
            # channel.
 | 
					            # channel.
 | 
				
			||||||
| 
						 | 
					@ -379,29 +431,35 @@ class TestImageCms(PillowTestCase):
 | 
				
			||||||
        # create some transform, it doesn't matter which one
 | 
					        # create some transform, it doesn't matter which one
 | 
				
			||||||
        source_profile = ImageCms.createProfile("sRGB")
 | 
					        source_profile = ImageCms.createProfile("sRGB")
 | 
				
			||||||
        destination_profile = ImageCms.createProfile("sRGB")
 | 
					        destination_profile = ImageCms.createProfile("sRGB")
 | 
				
			||||||
        t = ImageCms.buildTransform(source_profile, destination_profile, inMode=mode, outMode=mode)
 | 
					        t = ImageCms.buildTransform(
 | 
				
			||||||
 | 
					            source_profile, destination_profile, inMode=mode, outMode=mode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # apply transform
 | 
					        # apply transform
 | 
				
			||||||
        if transform_in_place:
 | 
					        if transform_in_place:
 | 
				
			||||||
            ImageCms.applyTransform(source_image, t, inPlace=True)
 | 
					            ImageCms.applyTransform(source_image, t, inPlace=True)
 | 
				
			||||||
            result_image = source_image
 | 
					            result_image = source_image
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            result_image = ImageCms.applyTransform(source_image, t, inPlace=False)
 | 
					            result_image = ImageCms.applyTransform(
 | 
				
			||||||
 | 
					                source_image, t, inPlace=False)
 | 
				
			||||||
        result_image_aux = result_image.getchannel(preserved_channel)
 | 
					        result_image_aux = result_image.getchannel(preserved_channel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assert_image_equal(source_image_aux, result_image_aux)
 | 
					        self.assert_image_equal(source_image_aux, result_image_aux)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_preserve_auxiliary_channels_rgba(self):
 | 
					    def test_preserve_auxiliary_channels_rgba(self):
 | 
				
			||||||
        self.assert_aux_channel_preserved(mode='RGBA', transform_in_place=False, preserved_channel='A')
 | 
					        self.assert_aux_channel_preserved(mode='RGBA',
 | 
				
			||||||
 | 
					            transform_in_place=False, preserved_channel='A')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_preserve_auxiliary_channels_rgba_in_place(self):
 | 
					    def test_preserve_auxiliary_channels_rgba_in_place(self):
 | 
				
			||||||
        self.assert_aux_channel_preserved(mode='RGBA', transform_in_place=True, preserved_channel='A')
 | 
					        self.assert_aux_channel_preserved(mode='RGBA',
 | 
				
			||||||
 | 
					            transform_in_place=True, preserved_channel='A')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_preserve_auxiliary_channels_rgbx(self):
 | 
					    def test_preserve_auxiliary_channels_rgbx(self):
 | 
				
			||||||
        self.assert_aux_channel_preserved(mode='RGBX', transform_in_place=False, preserved_channel='X')
 | 
					        self.assert_aux_channel_preserved(mode='RGBX',
 | 
				
			||||||
 | 
					            transform_in_place=False, preserved_channel='X')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_preserve_auxiliary_channels_rgbx_in_place(self):
 | 
					    def test_preserve_auxiliary_channels_rgbx_in_place(self):
 | 
				
			||||||
        self.assert_aux_channel_preserved(mode='RGBX', transform_in_place=True, preserved_channel='X')
 | 
					        self.assert_aux_channel_preserved(mode='RGBX',
 | 
				
			||||||
 | 
					            transform_in_place=True, preserved_channel='X')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_auxiliary_channels_isolated(self):
 | 
					    def test_auxiliary_channels_isolated(self):
 | 
				
			||||||
        # test data in aux channels does not affect non-aux channels
 | 
					        # test data in aux channels does not affect non-aux channels
 | 
				
			||||||
| 
						 | 
					@ -422,20 +480,29 @@ class TestImageCms(PillowTestCase):
 | 
				
			||||||
                    source_profile = ImageCms.createProfile(src_format[1])
 | 
					                    source_profile = ImageCms.createProfile(src_format[1])
 | 
				
			||||||
                    destination_profile = ImageCms.createProfile(dst_format[1])
 | 
					                    destination_profile = ImageCms.createProfile(dst_format[1])
 | 
				
			||||||
                    source_image = src_format[3]
 | 
					                    source_image = src_format[3]
 | 
				
			||||||
                    test_transform = ImageCms.buildTransform(source_profile, destination_profile, inMode=src_format[0], outMode=dst_format[0])
 | 
					                    test_transform = ImageCms.buildTransform(
 | 
				
			||||||
 | 
					                        source_profile, destination_profile,
 | 
				
			||||||
 | 
					                        inMode=src_format[0], outMode=dst_format[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    # test conversion from aux-ful source
 | 
					                    # test conversion from aux-ful source
 | 
				
			||||||
                    if transform_in_place:
 | 
					                    if transform_in_place:
 | 
				
			||||||
                        test_image = source_image.copy()
 | 
					                        test_image = source_image.copy()
 | 
				
			||||||
                        ImageCms.applyTransform(test_image, test_transform, inPlace=True)
 | 
					                        ImageCms.applyTransform(
 | 
				
			||||||
 | 
					                            test_image, test_transform, inPlace=True)
 | 
				
			||||||
                    else:
 | 
					                    else:
 | 
				
			||||||
                        test_image = ImageCms.applyTransform(source_image, test_transform, inPlace=False)
 | 
					                        test_image = ImageCms.applyTransform(
 | 
				
			||||||
 | 
					                            source_image, test_transform, inPlace=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    # reference conversion from aux-less source
 | 
					                    # reference conversion from aux-less source
 | 
				
			||||||
                    reference_transform = ImageCms.buildTransform(source_profile, destination_profile, inMode=src_format[2], outMode=dst_format[2])
 | 
					                    reference_transform = ImageCms.buildTransform(
 | 
				
			||||||
                    reference_image = ImageCms.applyTransform(source_image.convert(src_format[2]), reference_transform)
 | 
					                        source_profile, destination_profile,
 | 
				
			||||||
 | 
					                        inMode=src_format[2], outMode=dst_format[2])
 | 
				
			||||||
 | 
					                    reference_image = ImageCms.applyTransform(
 | 
				
			||||||
 | 
					                        source_image.convert(src_format[2]),
 | 
				
			||||||
 | 
					                        reference_transform)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    self.assert_image_equal(test_image.convert(dst_format[2]), reference_image)
 | 
					                    self.assert_image_equal(test_image.convert(dst_format[2]),
 | 
				
			||||||
 | 
					                                            reference_image)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,8 @@ class TestImageColor(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # case insensitivity
 | 
					        # case insensitivity
 | 
				
			||||||
        self.assertEqual(ImageColor.getrgb("#DEF"), ImageColor.getrgb("#def"))
 | 
					        self.assertEqual(ImageColor.getrgb("#DEF"), ImageColor.getrgb("#def"))
 | 
				
			||||||
        self.assertEqual(ImageColor.getrgb("#CDEF"), ImageColor.getrgb("#cdef"))
 | 
					        self.assertEqual(ImageColor.getrgb("#CDEF"),
 | 
				
			||||||
 | 
					                         ImageColor.getrgb("#cdef"))
 | 
				
			||||||
        self.assertEqual(ImageColor.getrgb("#DEFDEF"),
 | 
					        self.assertEqual(ImageColor.getrgb("#DEFDEF"),
 | 
				
			||||||
                         ImageColor.getrgb("#defdef"))
 | 
					                         ImageColor.getrgb("#defdef"))
 | 
				
			||||||
        self.assertEqual(ImageColor.getrgb("#CDEFCDEF"),
 | 
					        self.assertEqual(ImageColor.getrgb("#CDEFCDEF"),
 | 
				
			||||||
| 
						 | 
					@ -80,18 +81,23 @@ class TestImageColor(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual((255, 0, 0), ImageColor.getrgb("hsv(0,100%,100%)"))
 | 
					        self.assertEqual((255, 0, 0), ImageColor.getrgb("hsv(0,100%,100%)"))
 | 
				
			||||||
        self.assertEqual((255, 0, 0), ImageColor.getrgb("hsv(360,100%,100%)"))
 | 
					        self.assertEqual((255, 0, 0), ImageColor.getrgb("hsv(360,100%,100%)"))
 | 
				
			||||||
        self.assertEqual((0, 255, 255), ImageColor.getrgb("hsv(180,100%,100%)"))
 | 
					        self.assertEqual((0, 255, 255),
 | 
				
			||||||
 | 
					                         ImageColor.getrgb("hsv(180,100%,100%)"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # alternate format
 | 
					        # alternate format
 | 
				
			||||||
        self.assertEqual(ImageColor.getrgb("hsb(0,100%,50%)"),
 | 
					        self.assertEqual(ImageColor.getrgb("hsb(0,100%,50%)"),
 | 
				
			||||||
                         ImageColor.getrgb("hsv(0,100%,50%)"))
 | 
					                         ImageColor.getrgb("hsv(0,100%,50%)"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # floats
 | 
					        # floats
 | 
				
			||||||
        self.assertEqual((254, 3, 3), ImageColor.getrgb("hsl(0.1,99.2%,50.3%)"))
 | 
					        self.assertEqual((254, 3, 3),
 | 
				
			||||||
        self.assertEqual((255, 0, 0), ImageColor.getrgb("hsl(360.,100.0%,50%)"))
 | 
					                         ImageColor.getrgb("hsl(0.1,99.2%,50.3%)"))
 | 
				
			||||||
 | 
					        self.assertEqual((255, 0, 0),
 | 
				
			||||||
 | 
					                         ImageColor.getrgb("hsl(360.,100.0%,50%)"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual((253, 2, 2), ImageColor.getrgb("hsv(0.1,99.2%,99.3%)"))
 | 
					        self.assertEqual((253, 2, 2),
 | 
				
			||||||
        self.assertEqual((255, 0, 0), ImageColor.getrgb("hsv(360.,100.0%,100%)"))
 | 
					                         ImageColor.getrgb("hsv(0.1,99.2%,99.3%)"))
 | 
				
			||||||
 | 
					        self.assertEqual((255, 0, 0),
 | 
				
			||||||
 | 
					                         ImageColor.getrgb("hsv(360.,100.0%,100%)"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # case insensitivity
 | 
					        # case insensitivity
 | 
				
			||||||
        self.assertEqual(ImageColor.getrgb("RGB(255,0,0)"),
 | 
					        self.assertEqual(ImageColor.getrgb("RGB(255,0,0)"),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,8 +45,9 @@ class TestImageEnhance(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for op in ['Color', 'Brightness', 'Contrast', 'Sharpness']:
 | 
					        for op in ['Color', 'Brightness', 'Contrast', 'Sharpness']:
 | 
				
			||||||
            for amount in [0, 0.5, 1.0]:
 | 
					            for amount in [0, 0.5, 1.0]:
 | 
				
			||||||
                self._check_alpha(getattr(ImageEnhance, op)(original).enhance(amount),
 | 
					                self._check_alpha(
 | 
				
			||||||
                                  original, op, amount)
 | 
					                    getattr(ImageEnhance, op)(original).enhance(amount),
 | 
				
			||||||
 | 
					                    original, op, amount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -215,12 +215,16 @@ class TestPyDecoder(PillowTestCase):
 | 
				
			||||||
        buf = BytesIO(b'\x00'*255)
 | 
					        buf = BytesIO(b'\x00'*255)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        im = MockImageFile(buf)
 | 
					        im = MockImageFile(buf)
 | 
				
			||||||
        im.tile = [("MOCK", (xoff, yoff, xoff+xsize + 100, yoff+ysize), 32, None)]
 | 
					        im.tile = [
 | 
				
			||||||
 | 
					            ("MOCK", (xoff, yoff, xoff+xsize + 100, yoff+ysize), 32, None)
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
        d = self.get_decoder()
 | 
					        d = self.get_decoder()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertRaises(ValueError, im.load)
 | 
					        self.assertRaises(ValueError, im.load)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        im.tile = [("MOCK", (xoff, yoff, xoff+xsize, yoff+ysize + 100), 32, None)]
 | 
					        im.tile = [
 | 
				
			||||||
 | 
					            ("MOCK", (xoff, yoff, xoff+xsize, yoff+ysize + 100), 32, None)
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
        self.assertRaises(ValueError, im.load)
 | 
					        self.assertRaises(ValueError, im.load)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_no_format(self):
 | 
					    def test_no_format(self):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,8 +67,11 @@ class TestImageFont(PillowTestCase):
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        freetype_version = tuple(ImageFont.core.freetype2_version.split('.'))[:2]
 | 
					        freetype_version = tuple(
 | 
				
			||||||
        self.metrics = self.METRICS.get(freetype_version, self.METRICS['Default'])
 | 
					            ImageFont.core.freetype2_version.split('.')
 | 
				
			||||||
 | 
					        )[:2]
 | 
				
			||||||
 | 
					        self.metrics = self.METRICS.get(freetype_version,
 | 
				
			||||||
 | 
					                                        self.METRICS['Default'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_font(self):
 | 
					    def get_font(self):
 | 
				
			||||||
        return ImageFont.truetype(FONT_PATH, FONT_SIZE,
 | 
					        return ImageFont.truetype(FONT_PATH, FONT_SIZE,
 | 
				
			||||||
| 
						 | 
					@ -202,7 +205,8 @@ class TestImageFont(PillowTestCase):
 | 
				
			||||||
            target_img = Image.open(target)
 | 
					            target_img = Image.open(target)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Epsilon ~.5 fails with FreeType 2.7
 | 
					            # Epsilon ~.5 fails with FreeType 2.7
 | 
				
			||||||
            self.assert_image_similar(im, target_img, self.metrics['multiline'])
 | 
					            self.assert_image_similar(im, target_img,
 | 
				
			||||||
 | 
					                                      self.metrics['multiline'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_unknown_align(self):
 | 
					    def test_unknown_align(self):
 | 
				
			||||||
        im = Image.new(mode='RGB', size=(300, 100))
 | 
					        im = Image.new(mode='RGB', size=(300, 100))
 | 
				
			||||||
| 
						 | 
					@ -427,7 +431,8 @@ class TestImageFont(PillowTestCase):
 | 
				
			||||||
        # Make a copy of FreeTypeFont so we can patch the original
 | 
					        # Make a copy of FreeTypeFont so we can patch the original
 | 
				
			||||||
        free_type_font = copy.deepcopy(ImageFont.FreeTypeFont)
 | 
					        free_type_font = copy.deepcopy(ImageFont.FreeTypeFont)
 | 
				
			||||||
        with SimplePatcher(ImageFont, '_FreeTypeFont', free_type_font):
 | 
					        with SimplePatcher(ImageFont, '_FreeTypeFont', free_type_font):
 | 
				
			||||||
            def loadable_font(filepath, size, index, encoding, *args, **kwargs):
 | 
					            def loadable_font(filepath, size, index, encoding,
 | 
				
			||||||
 | 
					                              *args, **kwargs):
 | 
				
			||||||
                if filepath == path_to_fake:
 | 
					                if filepath == path_to_fake:
 | 
				
			||||||
                    return ImageFont._FreeTypeFont(FONT_PATH, size, index,
 | 
					                    return ImageFont._FreeTypeFont(FONT_PATH, size, index,
 | 
				
			||||||
                                                   encoding, *args, **kwargs)
 | 
					                                                   encoding, *args, **kwargs)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,7 +19,8 @@ class TestImageFontBitmap(PillowTestCase):
 | 
				
			||||||
            font='Tests/fonts/DejaVuSans-bitmap.ttf', size=24)
 | 
					            font='Tests/fonts/DejaVuSans-bitmap.ttf', size=24)
 | 
				
			||||||
        size_outline = font_outline.getsize(text)
 | 
					        size_outline = font_outline.getsize(text)
 | 
				
			||||||
        size_bitmap = font_bitmap.getsize(text)
 | 
					        size_bitmap = font_bitmap.getsize(text)
 | 
				
			||||||
        size_final = max(size_outline[0], size_bitmap[0]), max(size_outline[1], size_bitmap[1])
 | 
					        size_final = (max(size_outline[0], size_bitmap[0]),
 | 
				
			||||||
 | 
					                      max(size_outline[1], size_bitmap[1]))
 | 
				
			||||||
        im_bitmap = Image.new('RGB', size_final, (255, 255, 255))
 | 
					        im_bitmap = Image.new('RGB', size_final, (255, 255, 255))
 | 
				
			||||||
        im_outline = im_bitmap.copy()
 | 
					        im_outline = im_bitmap.copy()
 | 
				
			||||||
        draw_bitmap = ImageDraw.Draw(im_bitmap)
 | 
					        draw_bitmap = ImageDraw.Draw(im_bitmap)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,7 +30,8 @@ class TestImagecomplextext(PillowTestCase):
 | 
				
			||||||
        self.assert_image_similar(im, target_img, .5)
 | 
					        self.assert_image_similar(im, target_img, .5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_y_offset(self):
 | 
					    def test_y_offset(self):
 | 
				
			||||||
        ttf = ImageFont.truetype("Tests/fonts/NotoNastaliqUrdu-Regular.ttf", FONT_SIZE)
 | 
					        ttf = ImageFont.truetype("Tests/fonts/NotoNastaliqUrdu-Regular.ttf",
 | 
				
			||||||
 | 
					                                 FONT_SIZE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        im = Image.new(mode='RGB', size=(300, 100))
 | 
					        im = Image.new(mode='RGB', size=(300, 100))
 | 
				
			||||||
        draw = ImageDraw.Draw(im)
 | 
					        draw = ImageDraw.Draw(im)
 | 
				
			||||||
| 
						 | 
					@ -70,7 +71,8 @@ class TestImagecomplextext(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        im = Image.new(mode='RGB', size=(300, 100))
 | 
					        im = Image.new(mode='RGB', size=(300, 100))
 | 
				
			||||||
        draw = ImageDraw.Draw(im)
 | 
					        draw = ImageDraw.Draw(im)
 | 
				
			||||||
        draw.text((0, 0),  'سلطنة عمان Oman', font=ttf, fill=500, direction='ltr')
 | 
					        draw.text((0, 0),  'سلطنة عمان Oman',
 | 
				
			||||||
 | 
					                  font=ttf, fill=500, direction='ltr')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        target = 'Tests/images/test_direction_ltr.png'
 | 
					        target = 'Tests/images/test_direction_ltr.png'
 | 
				
			||||||
        target_img = Image.open(target)
 | 
					        target_img = Image.open(target)
 | 
				
			||||||
| 
						 | 
					@ -82,7 +84,8 @@ class TestImagecomplextext(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        im = Image.new(mode='RGB', size=(300, 100))
 | 
					        im = Image.new(mode='RGB', size=(300, 100))
 | 
				
			||||||
        draw = ImageDraw.Draw(im)
 | 
					        draw = ImageDraw.Draw(im)
 | 
				
			||||||
        draw.text((0, 0), 'Oman سلطنة عمان', font=ttf, fill=500, direction='rtl')
 | 
					        draw.text((0, 0), 'Oman سلطنة عمان',
 | 
				
			||||||
 | 
					                  font=ttf, fill=500, direction='rtl')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        target = 'Tests/images/test_direction_ltr.png'
 | 
					        target = 'Tests/images/test_direction_ltr.png'
 | 
				
			||||||
        target_img = Image.open(target)
 | 
					        target_img = Image.open(target)
 | 
				
			||||||
| 
						 | 
					@ -120,7 +123,8 @@ class TestImagecomplextext(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        im = Image.new(mode='RGB', size=(300, 100))
 | 
					        im = Image.new(mode='RGB', size=(300, 100))
 | 
				
			||||||
        draw = ImageDraw.Draw(im)
 | 
					        draw = ImageDraw.Draw(im)
 | 
				
			||||||
        draw.text((0, 0), 'اللغة العربية', font=ttf, fill=500, features=['-fina', '-init', '-medi'])
 | 
					        draw.text((0, 0), 'اللغة العربية', font=ttf, fill=500,
 | 
				
			||||||
 | 
					                  features=['-fina', '-init', '-medi'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        target = 'Tests/images/test_arabictext_features.png'
 | 
					        target = 'Tests/images/test_arabictext_features.png'
 | 
				
			||||||
        target_img = Image.open(target)
 | 
					        target_img = Image.open(target)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -265,8 +265,9 @@ class MorphTests(PillowTestCase):
 | 
				
			||||||
        # Act / Assert
 | 
					        # Act / Assert
 | 
				
			||||||
        with self.assertRaises(Exception) as e:
 | 
					        with self.assertRaises(Exception) as e:
 | 
				
			||||||
            lb.build_lut()
 | 
					            lb.build_lut()
 | 
				
			||||||
        self.assertEqual(str(e.exception),
 | 
					        self.assertEqual(
 | 
				
			||||||
                         'Syntax error in pattern "a pattern with a syntax error"')
 | 
					            str(e.exception),
 | 
				
			||||||
 | 
					            'Syntax error in pattern "a pattern with a syntax error"')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_load_invalid_mrl(self):
 | 
					    def test_load_invalid_mrl(self):
 | 
				
			||||||
        # Arrange
 | 
					        # Arrange
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,8 @@ class TestLibPack(PillowTestCase):
 | 
				
			||||||
        self.assert_pack("1", "1;R", b'\xaa', 0, X, 0, X, 0, X, 0, X)
 | 
					        self.assert_pack("1", "1;R", b'\xaa', 0, X, 0, X, 0, X, 0, X)
 | 
				
			||||||
        self.assert_pack("1", "1;IR", b'\xaa', X, 0, X, 0, X, 0, X, 0)
 | 
					        self.assert_pack("1", "1;IR", b'\xaa', X, 0, X, 0, X, 0, X, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assert_pack("1", "L", b'\xff\x00\x00\xff\x00\x00', X, 0, 0, X, 0, 0)
 | 
					        self.assert_pack(
 | 
				
			||||||
 | 
					            "1", "L", b'\xff\x00\x00\xff\x00\x00', X, 0, 0, X, 0, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_L(self):
 | 
					    def test_L(self):
 | 
				
			||||||
        self.assert_pack("L", "L", 1, 1, 2, 3, 4)
 | 
					        self.assert_pack("L", "L", 1, 1, 2, 3, 4)
 | 
				
			||||||
| 
						 | 
					@ -80,8 +81,10 @@ class TestLibPack(PillowTestCase):
 | 
				
			||||||
            "RGBA", "RGBA", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12))
 | 
					            "RGBA", "RGBA", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12))
 | 
				
			||||||
        self.assert_pack(
 | 
					        self.assert_pack(
 | 
				
			||||||
            "RGBA", "RGBA;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12))
 | 
					            "RGBA", "RGBA;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12))
 | 
				
			||||||
        self.assert_pack("RGBA", "RGB", 3, (1, 2, 3, 14), (4, 5, 6, 15), (7, 8, 9, 16))
 | 
					        self.assert_pack(
 | 
				
			||||||
        self.assert_pack("RGBA", "BGR", 3, (3, 2, 1, 14), (6, 5, 4, 15), (9, 8, 7, 16))
 | 
					            "RGBA", "RGB", 3, (1, 2, 3, 14), (4, 5, 6, 15), (7, 8, 9, 16))
 | 
				
			||||||
 | 
					        self.assert_pack(
 | 
				
			||||||
 | 
					            "RGBA", "BGR", 3, (3, 2, 1, 14), (6, 5, 4, 15), (9, 8, 7, 16))
 | 
				
			||||||
        self.assert_pack(
 | 
					        self.assert_pack(
 | 
				
			||||||
            "RGBA", "BGRA", 4,
 | 
					            "RGBA", "BGRA", 4,
 | 
				
			||||||
            (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12))
 | 
					            (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12))
 | 
				
			||||||
| 
						 | 
					@ -90,10 +93,14 @@ class TestLibPack(PillowTestCase):
 | 
				
			||||||
        self.assert_pack(
 | 
					        self.assert_pack(
 | 
				
			||||||
            "RGBA", "BGRa", 4,
 | 
					            "RGBA", "BGRa", 4,
 | 
				
			||||||
            (191, 127, 63, 4), (223, 191, 159, 8), (233, 212, 191, 12))
 | 
					            (191, 127, 63, 4), (223, 191, 159, 8), (233, 212, 191, 12))
 | 
				
			||||||
        self.assert_pack("RGBA", "R", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0))
 | 
					        self.assert_pack(
 | 
				
			||||||
        self.assert_pack("RGBA", "G", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9))
 | 
					            "RGBA", "R", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0))
 | 
				
			||||||
        self.assert_pack("RGBA", "B", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9))
 | 
					        self.assert_pack(
 | 
				
			||||||
        self.assert_pack("RGBA", "A", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3))
 | 
					            "RGBA", "G", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9))
 | 
				
			||||||
 | 
					        self.assert_pack(
 | 
				
			||||||
 | 
					            "RGBA", "B", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9))
 | 
				
			||||||
 | 
					        self.assert_pack(
 | 
				
			||||||
 | 
					            "RGBA", "A", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_RGBa(self):
 | 
					    def test_RGBa(self):
 | 
				
			||||||
        self.assert_pack(
 | 
					        self.assert_pack(
 | 
				
			||||||
| 
						 | 
					@ -104,10 +111,14 @@ class TestLibPack(PillowTestCase):
 | 
				
			||||||
            "RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9))
 | 
					            "RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_RGBX(self):
 | 
					    def test_RGBX(self):
 | 
				
			||||||
        self.assert_pack("RGBX", "RGBX", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12))
 | 
					        self.assert_pack(
 | 
				
			||||||
        self.assert_pack("RGBX", "RGBX;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12))
 | 
					            "RGBX", "RGBX", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12))
 | 
				
			||||||
        self.assert_pack("RGBX", "RGB", 3, (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X))
 | 
					        self.assert_pack(
 | 
				
			||||||
        self.assert_pack("RGBX", "BGR", 3, (3, 2, 1, X), (6, 5, 4, X), (9, 8, 7, X))
 | 
					            "RGBX", "RGBX;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12))
 | 
				
			||||||
 | 
					        self.assert_pack(
 | 
				
			||||||
 | 
					            "RGBX", "RGB", 3, (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X))
 | 
				
			||||||
 | 
					        self.assert_pack(
 | 
				
			||||||
 | 
					            "RGBX", "BGR", 3, (3, 2, 1, X), (6, 5, 4, X), (9, 8, 7, X))
 | 
				
			||||||
        self.assert_pack(
 | 
					        self.assert_pack(
 | 
				
			||||||
            "RGBX", "BGRX",
 | 
					            "RGBX", "BGRX",
 | 
				
			||||||
            b'\x01\x02\x03\x00\x05\x06\x07\x00\t\n\x0b\x00',
 | 
					            b'\x01\x02\x03\x00\x05\x06\x07\x00\t\n\x0b\x00',
 | 
				
			||||||
| 
						 | 
					@ -116,23 +127,30 @@ class TestLibPack(PillowTestCase):
 | 
				
			||||||
            "RGBX", "XBGR",
 | 
					            "RGBX", "XBGR",
 | 
				
			||||||
            b'\x00\x02\x03\x04\x00\x06\x07\x08\x00\n\x0b\x0c',
 | 
					            b'\x00\x02\x03\x04\x00\x06\x07\x08\x00\n\x0b\x0c',
 | 
				
			||||||
            (4, 3, 2, X), (8, 7, 6, X), (12, 11, 10, X))
 | 
					            (4, 3, 2, X), (8, 7, 6, X), (12, 11, 10, X))
 | 
				
			||||||
        self.assert_pack("RGBX", "R", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0))
 | 
					        self.assert_pack("RGBX", "R", 1,
 | 
				
			||||||
        self.assert_pack("RGBX", "G", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9))
 | 
					                         (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0))
 | 
				
			||||||
        self.assert_pack("RGBX", "B", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9))
 | 
					        self.assert_pack("RGBX", "G", 1,
 | 
				
			||||||
        self.assert_pack("RGBX", "X", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3))
 | 
					                         (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9))
 | 
				
			||||||
 | 
					        self.assert_pack("RGBX", "B", 1,
 | 
				
			||||||
 | 
					                         (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9))
 | 
				
			||||||
 | 
					        self.assert_pack("RGBX", "X", 1,
 | 
				
			||||||
 | 
					                         (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_CMYK(self):
 | 
					    def test_CMYK(self):
 | 
				
			||||||
        self.assert_pack("CMYK", "CMYK", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12))
 | 
					        self.assert_pack("CMYK", "CMYK", 4,
 | 
				
			||||||
 | 
					                         (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12))
 | 
				
			||||||
        self.assert_pack(
 | 
					        self.assert_pack(
 | 
				
			||||||
            "CMYK", "CMYK;I", 4,
 | 
					            "CMYK", "CMYK;I", 4,
 | 
				
			||||||
            (254, 253, 252, 251), (250, 249, 248, 247), (246, 245, 244, 243))
 | 
					            (254, 253, 252, 251), (250, 249, 248, 247), (246, 245, 244, 243))
 | 
				
			||||||
        self.assert_pack(
 | 
					        self.assert_pack(
 | 
				
			||||||
            "CMYK", "CMYK;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12))
 | 
					            "CMYK", "CMYK;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12))
 | 
				
			||||||
        self.assert_pack("CMYK", "K", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3))
 | 
					        self.assert_pack("CMYK", "K", 1,
 | 
				
			||||||
 | 
					                         (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_YCbCr(self):
 | 
					    def test_YCbCr(self):
 | 
				
			||||||
        self.assert_pack("YCbCr", "YCbCr", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9))
 | 
					        self.assert_pack("YCbCr", "YCbCr", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9))
 | 
				
			||||||
        self.assert_pack("YCbCr", "YCbCr;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9))
 | 
					        self.assert_pack("YCbCr", "YCbCr;L", 3,
 | 
				
			||||||
 | 
					                         (1, 4, 7), (2, 5, 8), (3, 6, 9))
 | 
				
			||||||
        self.assert_pack(
 | 
					        self.assert_pack(
 | 
				
			||||||
            "YCbCr", "YCbCrX",
 | 
					            "YCbCr", "YCbCrX",
 | 
				
			||||||
            b'\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff',
 | 
					            b'\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff',
 | 
				
			||||||
| 
						 | 
					@ -141,9 +159,12 @@ class TestLibPack(PillowTestCase):
 | 
				
			||||||
            "YCbCr", "YCbCrK",
 | 
					            "YCbCr", "YCbCrK",
 | 
				
			||||||
            b'\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff',
 | 
					            b'\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff',
 | 
				
			||||||
            (1, 2, 3), (5, 6, 7), (9, 10, 11))
 | 
					            (1, 2, 3), (5, 6, 7), (9, 10, 11))
 | 
				
			||||||
        self.assert_pack("YCbCr", "Y", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0))
 | 
					        self.assert_pack("YCbCr", "Y", 1,
 | 
				
			||||||
        self.assert_pack("YCbCr", "Cb", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9))
 | 
					                         (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0))
 | 
				
			||||||
        self.assert_pack("YCbCr", "Cr", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9))
 | 
					        self.assert_pack("YCbCr", "Cb", 1,
 | 
				
			||||||
 | 
					                         (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9))
 | 
				
			||||||
 | 
					        self.assert_pack("YCbCr", "Cr", 1,
 | 
				
			||||||
 | 
					                         (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_LAB(self):
 | 
					    def test_LAB(self):
 | 
				
			||||||
        self.assert_pack(
 | 
					        self.assert_pack(
 | 
				
			||||||
| 
						 | 
					@ -269,8 +290,10 @@ class TestLibUnpack(PillowTestCase):
 | 
				
			||||||
        self.assert_unpack("RGB", "RGBX", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11))
 | 
					        self.assert_unpack("RGB", "RGBX", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11))
 | 
				
			||||||
        self.assert_unpack("RGB", "RGBX;L", 4, (1, 4, 7), (2, 5, 8), (3, 6, 9))
 | 
					        self.assert_unpack("RGB", "RGBX;L", 4, (1, 4, 7), (2, 5, 8), (3, 6, 9))
 | 
				
			||||||
        self.assert_unpack("RGB", "BGRX", 4, (3, 2, 1), (7, 6, 5), (11, 10, 9))
 | 
					        self.assert_unpack("RGB", "BGRX", 4, (3, 2, 1), (7, 6, 5), (11, 10, 9))
 | 
				
			||||||
        self.assert_unpack("RGB", "XRGB", 4, (2, 3, 4), (6, 7, 8), (10, 11, 12))
 | 
					        self.assert_unpack(
 | 
				
			||||||
        self.assert_unpack("RGB", "XBGR", 4, (4, 3, 2), (8, 7, 6), (12, 11, 10))
 | 
					            "RGB", "XRGB", 4, (2, 3, 4), (6, 7, 8), (10, 11, 12))
 | 
				
			||||||
 | 
					        self.assert_unpack(
 | 
				
			||||||
 | 
					            "RGB", "XBGR", 4, (4, 3, 2), (8, 7, 6), (12, 11, 10))
 | 
				
			||||||
        self.assert_unpack(
 | 
					        self.assert_unpack(
 | 
				
			||||||
            "RGB", "YCC;P",
 | 
					            "RGB", "YCC;P",
 | 
				
			||||||
            b'D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12',  # random data
 | 
					            b'D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12',  # random data
 | 
				
			||||||
| 
						 | 
					@ -280,7 +303,8 @@ class TestLibUnpack(PillowTestCase):
 | 
				
			||||||
        self.assert_unpack("RGB", "B", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3))
 | 
					        self.assert_unpack("RGB", "B", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_RGBA(self):
 | 
					    def test_RGBA(self):
 | 
				
			||||||
        self.assert_unpack("RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6))
 | 
					        self.assert_unpack(
 | 
				
			||||||
 | 
					            "RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6))
 | 
				
			||||||
        self.assert_unpack(
 | 
					        self.assert_unpack(
 | 
				
			||||||
            "RGBA", "LA;16B", 4, (1, 1, 1, 3), (5, 5, 5, 7), (9, 9, 9, 11))
 | 
					            "RGBA", "LA;16B", 4, (1, 1, 1, 3), (5, 5, 5, 7), (9, 9, 9, 11))
 | 
				
			||||||
        self.assert_unpack(
 | 
					        self.assert_unpack(
 | 
				
			||||||
| 
						 | 
					@ -322,9 +346,12 @@ class TestLibUnpack(PillowTestCase):
 | 
				
			||||||
            "RGBA", "RGBA;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12))
 | 
					            "RGBA", "RGBA;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12))
 | 
				
			||||||
        self.assert_unpack("RGBA", "RGBA;15", 2, (8, 131, 0, 0), (24, 0, 8, 0))
 | 
					        self.assert_unpack("RGBA", "RGBA;15", 2, (8, 131, 0, 0), (24, 0, 8, 0))
 | 
				
			||||||
        self.assert_unpack("RGBA", "BGRA;15", 2, (0, 131, 8, 0), (8, 0, 24, 0))
 | 
					        self.assert_unpack("RGBA", "BGRA;15", 2, (0, 131, 8, 0), (8, 0, 24, 0))
 | 
				
			||||||
        self.assert_unpack("RGBA", "RGBA;4B", 2, (17, 0, 34, 0), (51, 0, 68, 0))
 | 
					        self.assert_unpack(
 | 
				
			||||||
        self.assert_unpack("RGBA", "RGBA;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16))
 | 
					            "RGBA", "RGBA;4B", 2, (17, 0, 34, 0), (51, 0, 68, 0))
 | 
				
			||||||
        self.assert_unpack("RGBA", "RGBA;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15))
 | 
					        self.assert_unpack(
 | 
				
			||||||
 | 
					            "RGBA", "RGBA;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16))
 | 
				
			||||||
 | 
					        self.assert_unpack(
 | 
				
			||||||
 | 
					            "RGBA", "RGBA;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15))
 | 
				
			||||||
        self.assert_unpack(
 | 
					        self.assert_unpack(
 | 
				
			||||||
            "RGBA", "BGRA", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12))
 | 
					            "RGBA", "BGRA", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12))
 | 
				
			||||||
        self.assert_unpack(
 | 
					        self.assert_unpack(
 | 
				
			||||||
| 
						 | 
					@ -335,10 +362,14 @@ class TestLibUnpack(PillowTestCase):
 | 
				
			||||||
            "RGBA", "YCCA;P",
 | 
					            "RGBA", "YCCA;P",
 | 
				
			||||||
            b']bE\x04\xdd\xbej\xed57T\xce\xac\xce:\x11',  # random data
 | 
					            b']bE\x04\xdd\xbej\xed57T\xce\xac\xce:\x11',  # random data
 | 
				
			||||||
            (0, 161, 0, 4), (255, 255, 255, 237), (27, 158, 0, 206), (0, 118, 0, 17))
 | 
					            (0, 161, 0, 4), (255, 255, 255, 237), (27, 158, 0, 206), (0, 118, 0, 17))
 | 
				
			||||||
        self.assert_unpack("RGBA", "R", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0))
 | 
					        self.assert_unpack(
 | 
				
			||||||
        self.assert_unpack("RGBA", "G", 1, (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0))
 | 
					            "RGBA", "R", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0))
 | 
				
			||||||
        self.assert_unpack("RGBA", "B", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0))
 | 
					        self.assert_unpack(
 | 
				
			||||||
        self.assert_unpack("RGBA", "A", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3))
 | 
					            "RGBA", "G", 1, (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0))
 | 
				
			||||||
 | 
					        self.assert_unpack(
 | 
				
			||||||
 | 
					            "RGBA", "B", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0))
 | 
				
			||||||
 | 
					        self.assert_unpack(
 | 
				
			||||||
 | 
					            "RGBA", "A", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_RGBa(self):
 | 
					    def test_RGBa(self):
 | 
				
			||||||
        self.assert_unpack(
 | 
					        self.assert_unpack(
 | 
				
			||||||
| 
						 | 
					@ -351,10 +382,13 @@ class TestLibUnpack(PillowTestCase):
 | 
				
			||||||
            "RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9))
 | 
					            "RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_RGBX(self):
 | 
					    def test_RGBX(self):
 | 
				
			||||||
        self.assert_unpack("RGBX", "RGB", 3, (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X))
 | 
					        self.assert_unpack("RGBX", "RGB", 3,
 | 
				
			||||||
        self.assert_unpack("RGBX", "RGB;L", 3, (1, 4, 7, X), (2, 5, 8, X), (3, 6, 9, X))
 | 
					                           (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X))
 | 
				
			||||||
 | 
					        self.assert_unpack("RGBX", "RGB;L", 3,
 | 
				
			||||||
 | 
					                           (1, 4, 7, X), (2, 5, 8, X), (3, 6, 9, X))
 | 
				
			||||||
        self.assert_unpack("RGBX", "RGB;16B", 6, (1, 3, 5, X), (7, 9, 11, X))
 | 
					        self.assert_unpack("RGBX", "RGB;16B", 6, (1, 3, 5, X), (7, 9, 11, X))
 | 
				
			||||||
        self.assert_unpack("RGBX", "BGR", 3, (3, 2, 1, X), (6, 5, 4, X), (9, 8, 7, X))
 | 
					        self.assert_unpack("RGBX", "BGR", 3,
 | 
				
			||||||
 | 
					                           (3, 2, 1, X), (6, 5, 4, X), (9, 8, 7, X))
 | 
				
			||||||
        self.assert_unpack("RGBX", "RGB;15", 2, (8, 131, 0, X), (24, 0, 8, X))
 | 
					        self.assert_unpack("RGBX", "RGB;15", 2, (8, 131, 0, X), (24, 0, 8, X))
 | 
				
			||||||
        self.assert_unpack("RGBX", "BGR;15", 2, (0, 131, 8, X), (8, 0, 24, X))
 | 
					        self.assert_unpack("RGBX", "BGR;15", 2, (0, 131, 8, X), (8, 0, 24, X))
 | 
				
			||||||
        self.assert_unpack("RGBX", "RGB;4B", 2, (17, 0, 34, X), (51, 0, 68, X))
 | 
					        self.assert_unpack("RGBX", "RGB;4B", 2, (17, 0, 34, X), (51, 0, 68, X))
 | 
				
			||||||
| 
						 | 
					@ -366,19 +400,28 @@ class TestLibUnpack(PillowTestCase):
 | 
				
			||||||
            "RGBX", "RGBXXX", 6, (1, 2, 3, 4), (7, 8, 9, 10), (13, 14, 15, 16))
 | 
					            "RGBX", "RGBXXX", 6, (1, 2, 3, 4), (7, 8, 9, 10), (13, 14, 15, 16))
 | 
				
			||||||
        self.assert_unpack(
 | 
					        self.assert_unpack(
 | 
				
			||||||
            "RGBX", "RGBX;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12))
 | 
					            "RGBX", "RGBX;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12))
 | 
				
			||||||
        self.assert_unpack("RGBX", "RGBX;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16))
 | 
					        self.assert_unpack("RGBX", "RGBX;16L", 8,
 | 
				
			||||||
        self.assert_unpack("RGBX", "RGBX;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15))
 | 
					                           (2, 4, 6, 8), (10, 12, 14, 16))
 | 
				
			||||||
        self.assert_unpack("RGBX", "BGRX", 4, (3, 2, 1, X), (7, 6, 5, X), (11, 10, 9, X))
 | 
					        self.assert_unpack("RGBX", "RGBX;16B", 8,
 | 
				
			||||||
        self.assert_unpack("RGBX", "XRGB", 4, (2, 3, 4, X), (6, 7, 8, X), (10, 11, 12, X))
 | 
					                           (1, 3, 5, 7), (9, 11, 13, 15))
 | 
				
			||||||
        self.assert_unpack("RGBX", "XBGR", 4, (4, 3, 2, X), (8, 7, 6, X), (12, 11, 10, X))
 | 
					        self.assert_unpack("RGBX", "BGRX", 4,
 | 
				
			||||||
 | 
					                           (3, 2, 1, X), (7, 6, 5, X), (11, 10, 9, X))
 | 
				
			||||||
 | 
					        self.assert_unpack("RGBX", "XRGB", 4,
 | 
				
			||||||
 | 
					                           (2, 3, 4, X), (6, 7, 8, X), (10, 11, 12, X))
 | 
				
			||||||
 | 
					        self.assert_unpack("RGBX", "XBGR", 4,
 | 
				
			||||||
 | 
					                           (4, 3, 2, X), (8, 7, 6, X), (12, 11, 10, X))
 | 
				
			||||||
        self.assert_unpack(
 | 
					        self.assert_unpack(
 | 
				
			||||||
            "RGBX", "YCC;P",
 | 
					            "RGBX", "YCC;P",
 | 
				
			||||||
            b'D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12',  # random data
 | 
					            b'D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12',  # random data
 | 
				
			||||||
            (127, 102, 0, X), (192, 227, 0, X), (213, 255, 170, X), (98, 255, 133, X))
 | 
					            (127, 102, 0, X), (192, 227, 0, X), (213, 255, 170, X), (98, 255, 133, X))
 | 
				
			||||||
        self.assert_unpack("RGBX", "R", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0))
 | 
					        self.assert_unpack("RGBX", "R", 1,
 | 
				
			||||||
        self.assert_unpack("RGBX", "G", 1, (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0))
 | 
					                           (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0))
 | 
				
			||||||
        self.assert_unpack("RGBX", "B", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0))
 | 
					        self.assert_unpack("RGBX", "G", 1,
 | 
				
			||||||
        self.assert_unpack("RGBX", "X", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3))
 | 
					                           (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0))
 | 
				
			||||||
 | 
					        self.assert_unpack("RGBX", "B", 1,
 | 
				
			||||||
 | 
					                           (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0))
 | 
				
			||||||
 | 
					        self.assert_unpack("RGBX", "X", 1,
 | 
				
			||||||
 | 
					                           (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_CMYK(self):
 | 
					    def test_CMYK(self):
 | 
				
			||||||
        self.assert_unpack(
 | 
					        self.assert_unpack(
 | 
				
			||||||
| 
						 | 
					@ -392,10 +435,14 @@ class TestLibUnpack(PillowTestCase):
 | 
				
			||||||
            (254, 253, 252, 251), (250, 249, 248, 247), (246, 245, 244, 243))
 | 
					            (254, 253, 252, 251), (250, 249, 248, 247), (246, 245, 244, 243))
 | 
				
			||||||
        self.assert_unpack(
 | 
					        self.assert_unpack(
 | 
				
			||||||
            "CMYK", "CMYK;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12))
 | 
					            "CMYK", "CMYK;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12))
 | 
				
			||||||
        self.assert_unpack("CMYK", "C", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0))
 | 
					        self.assert_unpack("CMYK", "C", 1,
 | 
				
			||||||
        self.assert_unpack("CMYK", "M", 1, (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0))
 | 
					                           (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0))
 | 
				
			||||||
        self.assert_unpack("CMYK", "Y", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0))
 | 
					        self.assert_unpack("CMYK", "M", 1,
 | 
				
			||||||
        self.assert_unpack("CMYK", "K", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3))
 | 
					                           (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0))
 | 
				
			||||||
 | 
					        self.assert_unpack("CMYK", "Y", 1,
 | 
				
			||||||
 | 
					                           (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0))
 | 
				
			||||||
 | 
					        self.assert_unpack("CMYK", "K", 1,
 | 
				
			||||||
 | 
					                           (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3))
 | 
				
			||||||
        self.assert_unpack(
 | 
					        self.assert_unpack(
 | 
				
			||||||
            "CMYK", "C;I", 1, (254, 0, 0, 0), (253, 0, 0, 0), (252, 0, 0, 0))
 | 
					            "CMYK", "C;I", 1, (254, 0, 0, 0), (253, 0, 0, 0), (252, 0, 0, 0))
 | 
				
			||||||
        self.assert_unpack(
 | 
					        self.assert_unpack(
 | 
				
			||||||
| 
						 | 
					@ -451,7 +498,8 @@ class TestLibUnpack(PillowTestCase):
 | 
				
			||||||
        if sys.byteorder == 'little':
 | 
					        if sys.byteorder == 'little':
 | 
				
			||||||
            self.assert_unpack("I", "I", 4, 0x04030201, 0x08070605)
 | 
					            self.assert_unpack("I", "I", 4, 0x04030201, 0x08070605)
 | 
				
			||||||
            self.assert_unpack("I", "I;16N", 2, 0x0201, 0x0403)
 | 
					            self.assert_unpack("I", "I;16N", 2, 0x0201, 0x0403)
 | 
				
			||||||
            self.assert_unpack("I", "I;16NS", b'\x83\x01\x01\x83', 0x0183, -31999)
 | 
					            self.assert_unpack("I", "I;16NS",
 | 
				
			||||||
 | 
					                               b'\x83\x01\x01\x83', 0x0183, -31999)
 | 
				
			||||||
            self.assert_unpack("I", "I;32N", 4, 0x04030201, 0x08070605)
 | 
					            self.assert_unpack("I", "I;32N", 4, 0x04030201, 0x08070605)
 | 
				
			||||||
            self.assert_unpack(
 | 
					            self.assert_unpack(
 | 
				
			||||||
                "I", "I;32NS",
 | 
					                "I", "I;32NS",
 | 
				
			||||||
| 
						 | 
					@ -459,7 +507,8 @@ class TestLibUnpack(PillowTestCase):
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            self.assert_unpack("I", "I", 4, 0x01020304, 0x05060708)
 | 
					            self.assert_unpack("I", "I", 4, 0x01020304, 0x05060708)
 | 
				
			||||||
            self.assert_unpack("I", "I;16N", 2, 0x0102, 0x0304)
 | 
					            self.assert_unpack("I", "I;16N", 2, 0x0102, 0x0304)
 | 
				
			||||||
            self.assert_unpack("I", "I;16NS", b'\x83\x01\x01\x83', -31999, 0x0183)
 | 
					            self.assert_unpack("I", "I;16NS",
 | 
				
			||||||
 | 
					                               b'\x83\x01\x01\x83', -31999, 0x0183)
 | 
				
			||||||
            self.assert_unpack("I", "I;32N", 4, 0x01020304, 0x05060708)
 | 
					            self.assert_unpack("I", "I;32N", 4, 0x01020304, 0x05060708)
 | 
				
			||||||
            self.assert_unpack(
 | 
					            self.assert_unpack(
 | 
				
			||||||
                "I", "I;32NS",
 | 
					                "I", "I;32NS",
 | 
				
			||||||
| 
						 | 
					@ -483,14 +532,18 @@ class TestLibUnpack(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if sys.byteorder == 'little':
 | 
					        if sys.byteorder == 'little':
 | 
				
			||||||
            self.assert_unpack("F", "F;16N", 2, 0x0201, 0x0403)
 | 
					            self.assert_unpack("F", "F;16N", 2, 0x0201, 0x0403)
 | 
				
			||||||
            self.assert_unpack("F", "F;16NS", b'\x83\x01\x01\x83', 0x0183, -31999)
 | 
					            self.assert_unpack(
 | 
				
			||||||
 | 
					                "F", "F;16NS",
 | 
				
			||||||
 | 
					                b'\x83\x01\x01\x83', 0x0183, -31999)
 | 
				
			||||||
            self.assert_unpack("F", "F;32N", 4, 67305984, 134678016)
 | 
					            self.assert_unpack("F", "F;32N", 4, 67305984, 134678016)
 | 
				
			||||||
            self.assert_unpack(
 | 
					            self.assert_unpack(
 | 
				
			||||||
                "F", "F;32NS",
 | 
					                "F", "F;32NS",
 | 
				
			||||||
                b'\x83\x00\x00\x01\x01\x00\x00\x83', 16777348, -2097152000)
 | 
					                b'\x83\x00\x00\x01\x01\x00\x00\x83', 16777348, -2097152000)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            self.assert_unpack("F", "F;16N", 2, 0x0102, 0x0304)
 | 
					            self.assert_unpack("F", "F;16N", 2, 0x0102, 0x0304)
 | 
				
			||||||
            self.assert_unpack("F", "F;16NS", b'\x83\x01\x01\x83', -31999, 0x0183)
 | 
					            self.assert_unpack(
 | 
				
			||||||
 | 
					                "F", "F;16NS",
 | 
				
			||||||
 | 
					                b'\x83\x01\x01\x83', -31999, 0x0183)
 | 
				
			||||||
            self.assert_unpack("F", "F;32N", 4, 0x01020304, 0x05060708)
 | 
					            self.assert_unpack("F", "F;32N", 4, 0x01020304, 0x05060708)
 | 
				
			||||||
            self.assert_unpack(
 | 
					            self.assert_unpack(
 | 
				
			||||||
                "F", "F;32NS",
 | 
					                "F", "F;32NS",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,8 @@ import sys
 | 
				
			||||||
from PIL import Image
 | 
					from PIL import Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@unittest.skipIf(sys.platform.startswith('win32'), "Win32 does not call map_buffer")
 | 
					@unittest.skipIf(sys.platform.startswith('win32'),
 | 
				
			||||||
 | 
					                 "Win32 does not call map_buffer")
 | 
				
			||||||
class TestMap(PillowTestCase):
 | 
					class TestMap(PillowTestCase):
 | 
				
			||||||
    def test_overflow(self):
 | 
					    def test_overflow(self):
 | 
				
			||||||
        # There is the potential to overflow comparisons in map.c
 | 
					        # There is the potential to overflow comparisons in map.c
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -124,7 +124,9 @@ class TestNumpy(PillowTestCase):
 | 
				
			||||||
    def test_save_tiff_uint16(self):
 | 
					    def test_save_tiff_uint16(self):
 | 
				
			||||||
        # Tests that we're getting the pixel value in the right byte order.
 | 
					        # Tests that we're getting the pixel value in the right byte order.
 | 
				
			||||||
        pixel_value = 0x1234
 | 
					        pixel_value = 0x1234
 | 
				
			||||||
        a = numpy.array([pixel_value] * TEST_IMAGE_SIZE[0] * TEST_IMAGE_SIZE[1], dtype=numpy.uint16)
 | 
					        a = numpy.array(
 | 
				
			||||||
 | 
					            [pixel_value] * TEST_IMAGE_SIZE[0] * TEST_IMAGE_SIZE[1],
 | 
				
			||||||
 | 
					            dtype=numpy.uint16)
 | 
				
			||||||
        a.shape = TEST_IMAGE_SIZE
 | 
					        a.shape = TEST_IMAGE_SIZE
 | 
				
			||||||
        img = Image.fromarray(a)
 | 
					        img = Image.fromarray(a)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
from helper import unittest, PillowTestCase
 | 
					from helper import unittest, PillowTestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from PIL.PdfParser import IndirectObjectDef, IndirectReference, PdfBinary, PdfDict, PdfFormatError, PdfName, PdfParser, PdfStream, decode_text, encode_text, pdf_repr
 | 
					from PIL.PdfParser import IndirectObjectDef, IndirectReference, PdfBinary, \
 | 
				
			||||||
 | 
					                          PdfDict, PdfFormatError, PdfName, PdfParser, \
 | 
				
			||||||
 | 
					                          PdfStream, decode_text, encode_text, pdf_repr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestPdfParser(PillowTestCase):
 | 
					class TestPdfParser(PillowTestCase):
 | 
				
			||||||
| 
						 | 
					@ -22,23 +24,35 @@ class TestPdfParser(PillowTestCase):
 | 
				
			||||||
        self.assertNotEqual(IndirectObjectDef(1, 2), (1, 2))
 | 
					        self.assertNotEqual(IndirectObjectDef(1, 2), (1, 2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_parsing(self):
 | 
					    def test_parsing(self):
 | 
				
			||||||
        self.assertEqual(PdfParser.interpret_name(b"Name#23Hash"), b"Name#Hash")
 | 
					        self.assertEqual(PdfParser.interpret_name(b"Name#23Hash"),
 | 
				
			||||||
 | 
					                         b"Name#Hash")
 | 
				
			||||||
        self.assertEqual(PdfParser.interpret_name(b"Name#23Hash", as_text=True), "Name#Hash")
 | 
					        self.assertEqual(PdfParser.interpret_name(b"Name#23Hash", as_text=True), "Name#Hash")
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"1 2 R ", 0), (IndirectReference(1, 2), 5))
 | 
					        self.assertEqual(PdfParser.get_value(b"1 2 R ", 0),
 | 
				
			||||||
 | 
					                         (IndirectReference(1, 2), 5))
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"true[", 0), (True, 4))
 | 
					        self.assertEqual(PdfParser.get_value(b"true[", 0), (True, 4))
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"false%", 0), (False, 5))
 | 
					        self.assertEqual(PdfParser.get_value(b"false%", 0), (False, 5))
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"null<", 0), (None, 4))
 | 
					        self.assertEqual(PdfParser.get_value(b"null<", 0), (None, 4))
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"%cmt\n %cmt\n 123\n", 0), (123, 15))
 | 
					        self.assertEqual(PdfParser.get_value(b"%cmt\n %cmt\n 123\n", 0),
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"<901FA3>", 0), (b"\x90\x1F\xA3", 8))
 | 
					                         (123, 15))
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"asd < 9 0 1 f A > qwe", 3), (b"\x90\x1F\xA0", 17))
 | 
					        self.assertEqual(PdfParser.get_value(b"<901FA3>", 0),
 | 
				
			||||||
 | 
					                         (b"\x90\x1F\xA3", 8))
 | 
				
			||||||
 | 
					        self.assertEqual(PdfParser.get_value(b"asd < 9 0 1 f A > qwe", 3),
 | 
				
			||||||
 | 
					                         (b"\x90\x1F\xA0", 17))
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"(asd)", 0), (b"asd", 5))
 | 
					        self.assertEqual(PdfParser.get_value(b"(asd)", 0), (b"asd", 5))
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"(asd(qwe)zxc)zzz(aaa)", 0), (b"asd(qwe)zxc", 13))
 | 
					        self.assertEqual(PdfParser.get_value(b"(asd(qwe)zxc)zzz(aaa)", 0),
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"(Two \\\nwords.)", 0), (b"Two words.", 14))
 | 
					                         (b"asd(qwe)zxc", 13))
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"(Two\nlines.)", 0), (b"Two\nlines.", 12))
 | 
					        self.assertEqual(PdfParser.get_value(b"(Two \\\nwords.)", 0),
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"(Two\r\nlines.)", 0), (b"Two\nlines.", 13))
 | 
					                         (b"Two words.", 14))
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"(Two\\nlines.)", 0), (b"Two\nlines.", 13))
 | 
					        self.assertEqual(PdfParser.get_value(b"(Two\nlines.)", 0),
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"(One\\(paren).", 0), (b"One(paren", 12))
 | 
					                         (b"Two\nlines.", 12))
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"(One\\)paren).", 0), (b"One)paren", 12))
 | 
					        self.assertEqual(PdfParser.get_value(b"(Two\r\nlines.)", 0),
 | 
				
			||||||
 | 
					                         (b"Two\nlines.", 13))
 | 
				
			||||||
 | 
					        self.assertEqual(PdfParser.get_value(b"(Two\\nlines.)", 0),
 | 
				
			||||||
 | 
					                         (b"Two\nlines.", 13))
 | 
				
			||||||
 | 
					        self.assertEqual(PdfParser.get_value(b"(One\\(paren).", 0),
 | 
				
			||||||
 | 
					                         (b"One(paren", 12))
 | 
				
			||||||
 | 
					        self.assertEqual(PdfParser.get_value(b"(One\\)paren).", 0),
 | 
				
			||||||
 | 
					                         (b"One)paren", 12))
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"(\\0053)", 0), (b"\x053", 7))
 | 
					        self.assertEqual(PdfParser.get_value(b"(\\0053)", 0), (b"\x053", 7))
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"(\\053)", 0), (b"\x2B", 6))
 | 
					        self.assertEqual(PdfParser.get_value(b"(\\053)", 0), (b"\x2B", 6))
 | 
				
			||||||
        self.assertEqual(PdfParser.get_value(b"(\\53)", 0), (b"\x2B", 5))
 | 
					        self.assertEqual(PdfParser.get_value(b"(\\53)", 0), (b"\x2B", 5))
 | 
				
			||||||
| 
						 | 
					@ -65,23 +79,30 @@ class TestPdfParser(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_pdf_repr(self):
 | 
					    def test_pdf_repr(self):
 | 
				
			||||||
        self.assertEqual(bytes(IndirectReference(1, 2)), b"1 2 R")
 | 
					        self.assertEqual(bytes(IndirectReference(1, 2)), b"1 2 R")
 | 
				
			||||||
        self.assertEqual(bytes(IndirectObjectDef(*IndirectReference(1, 2))), b"1 2 obj")
 | 
					        self.assertEqual(bytes(IndirectObjectDef(*IndirectReference(1, 2))),
 | 
				
			||||||
 | 
					                         b"1 2 obj")
 | 
				
			||||||
        self.assertEqual(bytes(PdfName(b"Name#Hash")), b"/Name#23Hash")
 | 
					        self.assertEqual(bytes(PdfName(b"Name#Hash")), b"/Name#23Hash")
 | 
				
			||||||
        self.assertEqual(bytes(PdfName("Name#Hash")), b"/Name#23Hash")
 | 
					        self.assertEqual(bytes(PdfName("Name#Hash")), b"/Name#23Hash")
 | 
				
			||||||
        self.assertEqual(bytes(PdfDict({b"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>")
 | 
					        self.assertEqual(bytes(PdfDict({b"Name": IndirectReference(1, 2)})),
 | 
				
			||||||
        self.assertEqual(bytes(PdfDict({"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>")
 | 
					                         b"<<\n/Name 1 2 R\n>>")
 | 
				
			||||||
 | 
					        self.assertEqual(bytes(PdfDict({"Name": IndirectReference(1, 2)})),
 | 
				
			||||||
 | 
					                         b"<<\n/Name 1 2 R\n>>")
 | 
				
			||||||
        self.assertEqual(pdf_repr(IndirectReference(1, 2)), b"1 2 R")
 | 
					        self.assertEqual(pdf_repr(IndirectReference(1, 2)), b"1 2 R")
 | 
				
			||||||
        self.assertEqual(pdf_repr(IndirectObjectDef(*IndirectReference(1, 2))), b"1 2 obj")
 | 
					        self.assertEqual(pdf_repr(IndirectObjectDef(*IndirectReference(1, 2))),
 | 
				
			||||||
 | 
					                         b"1 2 obj")
 | 
				
			||||||
        self.assertEqual(pdf_repr(PdfName(b"Name#Hash")), b"/Name#23Hash")
 | 
					        self.assertEqual(pdf_repr(PdfName(b"Name#Hash")), b"/Name#23Hash")
 | 
				
			||||||
        self.assertEqual(pdf_repr(PdfName("Name#Hash")), b"/Name#23Hash")
 | 
					        self.assertEqual(pdf_repr(PdfName("Name#Hash")), b"/Name#23Hash")
 | 
				
			||||||
        self.assertEqual(pdf_repr(PdfDict({b"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>")
 | 
					        self.assertEqual(pdf_repr(PdfDict({b"Name": IndirectReference(1, 2)})),
 | 
				
			||||||
        self.assertEqual(pdf_repr(PdfDict({"Name": IndirectReference(1, 2)})), b"<<\n/Name 1 2 R\n>>")
 | 
					                         b"<<\n/Name 1 2 R\n>>")
 | 
				
			||||||
 | 
					        self.assertEqual(pdf_repr(PdfDict({"Name": IndirectReference(1, 2)})),
 | 
				
			||||||
 | 
					                         b"<<\n/Name 1 2 R\n>>")
 | 
				
			||||||
        self.assertEqual(pdf_repr(123), b"123")
 | 
					        self.assertEqual(pdf_repr(123), b"123")
 | 
				
			||||||
        self.assertEqual(pdf_repr(True), b"true")
 | 
					        self.assertEqual(pdf_repr(True), b"true")
 | 
				
			||||||
        self.assertEqual(pdf_repr(False), b"false")
 | 
					        self.assertEqual(pdf_repr(False), b"false")
 | 
				
			||||||
        self.assertEqual(pdf_repr(None), b"null")
 | 
					        self.assertEqual(pdf_repr(None), b"null")
 | 
				
			||||||
        self.assertEqual(pdf_repr(b"a)/b\\(c"), br"(a\)/b\\\(c)")
 | 
					        self.assertEqual(pdf_repr(b"a)/b\\(c"), br"(a\)/b\\\(c)")
 | 
				
			||||||
        self.assertEqual(pdf_repr([123, True, {"a": PdfName(b"b")}]), b"[ 123 true <<\n/a /b\n>> ]")
 | 
					        self.assertEqual(pdf_repr([123, True, {"a": PdfName(b"b")}]),
 | 
				
			||||||
 | 
					                         b"[ 123 true <<\n/a /b\n>> ]")
 | 
				
			||||||
        self.assertEqual(pdf_repr(PdfBinary(b"\x90\x1F\xA0")), b"<901FA0>")
 | 
					        self.assertEqual(pdf_repr(PdfBinary(b"\x90\x1F\xA0")), b"<901FA0>")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										15
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								setup.py
									
									
									
									
									
								
							| 
						 | 
					@ -424,7 +424,8 @@ class pil_build_ext(build_ext):
 | 
				
			||||||
            best_path = None
 | 
					            best_path = None
 | 
				
			||||||
            for name in os.listdir(program_files):
 | 
					            for name in os.listdir(program_files):
 | 
				
			||||||
                if name.startswith('OpenJPEG '):
 | 
					                if name.startswith('OpenJPEG '):
 | 
				
			||||||
                    version = tuple(int(x) for x in name[9:].strip().split('.'))
 | 
					                    version = tuple(int(x) for x in
 | 
				
			||||||
 | 
					                                    name[9:].strip().split('.'))
 | 
				
			||||||
                    if version > best_version:
 | 
					                    if version > best_version:
 | 
				
			||||||
                        best_version = version
 | 
					                        best_version = version
 | 
				
			||||||
                        best_path = os.path.join(program_files, name)
 | 
					                        best_path = os.path.join(program_files, name)
 | 
				
			||||||
| 
						 | 
					@ -501,7 +502,8 @@ class pil_build_ext(build_ext):
 | 
				
			||||||
                # possible.
 | 
					                # possible.
 | 
				
			||||||
                _add_directory(self.compiler.include_dirs, best_path, 0)
 | 
					                _add_directory(self.compiler.include_dirs, best_path, 0)
 | 
				
			||||||
                feature.jpeg2000 = 'openjp2'
 | 
					                feature.jpeg2000 = 'openjp2'
 | 
				
			||||||
                feature.openjpeg_version = '.'.join(str(x) for x in best_version)
 | 
					                feature.openjpeg_version = '.'.join(str(x) for x in
 | 
				
			||||||
 | 
					                                                    best_version)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if feature.want('imagequant'):
 | 
					        if feature.want('imagequant'):
 | 
				
			||||||
            _dbg('Looking for imagequant')
 | 
					            _dbg('Looking for imagequant')
 | 
				
			||||||
| 
						 | 
					@ -516,7 +518,8 @@ class pil_build_ext(build_ext):
 | 
				
			||||||
            if _find_include_file(self, 'tiff.h'):
 | 
					            if _find_include_file(self, 'tiff.h'):
 | 
				
			||||||
                if _find_library_file(self, "tiff"):
 | 
					                if _find_library_file(self, "tiff"):
 | 
				
			||||||
                    feature.tiff = "tiff"
 | 
					                    feature.tiff = "tiff"
 | 
				
			||||||
                if sys.platform == "win32" and _find_library_file(self, "libtiff"):
 | 
					                if (sys.platform == "win32" and
 | 
				
			||||||
 | 
					                        _find_library_file(self, "libtiff")):
 | 
				
			||||||
                    feature.tiff = "libtiff"
 | 
					                    feature.tiff = "libtiff"
 | 
				
			||||||
                if (sys.platform == "darwin" and
 | 
					                if (sys.platform == "darwin" and
 | 
				
			||||||
                        _find_library_file(self, "libtiff")):
 | 
					                        _find_library_file(self, "libtiff")):
 | 
				
			||||||
| 
						 | 
					@ -528,14 +531,16 @@ class pil_build_ext(build_ext):
 | 
				
			||||||
                # look for freetype2 include files
 | 
					                # look for freetype2 include files
 | 
				
			||||||
                freetype_version = 0
 | 
					                freetype_version = 0
 | 
				
			||||||
                for subdir in self.compiler.include_dirs:
 | 
					                for subdir in self.compiler.include_dirs:
 | 
				
			||||||
                    _dbg('Checking for include file %s in %s', ("ft2build.h", subdir))
 | 
					                    _dbg('Checking for include file %s in %s',
 | 
				
			||||||
 | 
					                         ("ft2build.h", subdir))
 | 
				
			||||||
                    if os.path.isfile(os.path.join(subdir, "ft2build.h")):
 | 
					                    if os.path.isfile(os.path.join(subdir, "ft2build.h")):
 | 
				
			||||||
                        _dbg('Found %s in %s', ("ft2build.h", subdir))
 | 
					                        _dbg('Found %s in %s', ("ft2build.h", subdir))
 | 
				
			||||||
                        freetype_version = 21
 | 
					                        freetype_version = 21
 | 
				
			||||||
                        subdir = os.path.join(subdir, "freetype2")
 | 
					                        subdir = os.path.join(subdir, "freetype2")
 | 
				
			||||||
                        break
 | 
					                        break
 | 
				
			||||||
                    subdir = os.path.join(subdir, "freetype2")
 | 
					                    subdir = os.path.join(subdir, "freetype2")
 | 
				
			||||||
                    _dbg('Checking for include file %s in %s', ("ft2build.h", subdir))
 | 
					                    _dbg('Checking for include file %s in %s',
 | 
				
			||||||
 | 
					                         ("ft2build.h", subdir))
 | 
				
			||||||
                    if os.path.isfile(os.path.join(subdir, "ft2build.h")):
 | 
					                    if os.path.isfile(os.path.join(subdir, "ft2build.h")):
 | 
				
			||||||
                        _dbg('Found %s in %s', ("ft2build.h", subdir))
 | 
					                        _dbg('Found %s in %s', ("ft2build.h", subdir))
 | 
				
			||||||
                        freetype_version = 21
 | 
					                        freetype_version = 21
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,7 +60,14 @@ class BmpImageFile(ImageFile.ImageFile):
 | 
				
			||||||
    format_description = "Windows Bitmap"
 | 
					    format_description = "Windows Bitmap"
 | 
				
			||||||
    format = "BMP"
 | 
					    format = "BMP"
 | 
				
			||||||
    # --------------------------------------------------- BMP Compression values
 | 
					    # --------------------------------------------------- BMP Compression values
 | 
				
			||||||
    COMPRESSIONS = {'RAW': 0, 'RLE8': 1, 'RLE4': 2, 'BITFIELDS': 3, 'JPEG': 4, 'PNG': 5}
 | 
					    COMPRESSIONS = {
 | 
				
			||||||
 | 
					        'RAW': 0,
 | 
				
			||||||
 | 
					        'RLE8': 1,
 | 
				
			||||||
 | 
					        'RLE4': 2,
 | 
				
			||||||
 | 
					        'BITFIELDS': 3,
 | 
				
			||||||
 | 
					        'JPEG': 4,
 | 
				
			||||||
 | 
					        'PNG': 5
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    RAW, RLE8, RLE4, BITFIELDS, JPEG, PNG = 0, 1, 2, 3, 4, 5
 | 
					    RAW, RLE8, RLE4, BITFIELDS, JPEG, PNG = 0, 1, 2, 3, 4, 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _bitmap(self, header=0, offset=0):
 | 
					    def _bitmap(self, header=0, offset=0):
 | 
				
			||||||
| 
						 | 
					@ -69,10 +76,13 @@ class BmpImageFile(ImageFile.ImageFile):
 | 
				
			||||||
        if header:
 | 
					        if header:
 | 
				
			||||||
            seek(header)
 | 
					            seek(header)
 | 
				
			||||||
        file_info = {}
 | 
					        file_info = {}
 | 
				
			||||||
        file_info['header_size'] = i32(read(4))  # read bmp header size @offset 14 (this is part of the header size)
 | 
					        # read bmp header size @offset 14 (this is part of the header size)
 | 
				
			||||||
 | 
					        file_info['header_size'] = i32(read(4))
 | 
				
			||||||
        file_info['direction'] = -1
 | 
					        file_info['direction'] = -1
 | 
				
			||||||
        # --------------------- If requested, read header at a specific position
 | 
					        # --------------------- If requested, read header at a specific position
 | 
				
			||||||
        header_data = ImageFile._safe_read(self.fp, file_info['header_size'] - 4)  # read the rest of the bmp header, without its size
 | 
					        # read the rest of the bmp header, without its size
 | 
				
			||||||
 | 
					        header_data = ImageFile._safe_read(self.fp,
 | 
				
			||||||
 | 
					                                           file_info['header_size'] - 4)
 | 
				
			||||||
        # --------------------------------------------------- IBM OS/2 Bitmap v1
 | 
					        # --------------------------------------------------- IBM OS/2 Bitmap v1
 | 
				
			||||||
        # ------ This format has different offsets because of width/height types
 | 
					        # ------ This format has different offsets because of width/height types
 | 
				
			||||||
        if file_info['header_size'] == 12:
 | 
					        if file_info['header_size'] == 12:
 | 
				
			||||||
| 
						 | 
					@ -88,12 +98,16 @@ class BmpImageFile(ImageFile.ImageFile):
 | 
				
			||||||
                file_info['y_flip'] = i8(header_data[7]) == 0xff
 | 
					                file_info['y_flip'] = i8(header_data[7]) == 0xff
 | 
				
			||||||
                file_info['direction'] = 1 if file_info['y_flip'] else -1
 | 
					                file_info['direction'] = 1 if file_info['y_flip'] else -1
 | 
				
			||||||
                file_info['width'] = i32(header_data[0:4])
 | 
					                file_info['width'] = i32(header_data[0:4])
 | 
				
			||||||
                file_info['height'] = i32(header_data[4:8]) if not file_info['y_flip'] else 2**32 - i32(header_data[4:8])
 | 
					                file_info['height'] = (i32(header_data[4:8])
 | 
				
			||||||
 | 
					                                       if not file_info['y_flip']
 | 
				
			||||||
 | 
					                                       else 2**32 - i32(header_data[4:8]))
 | 
				
			||||||
                file_info['planes'] = i16(header_data[8:10])
 | 
					                file_info['planes'] = i16(header_data[8:10])
 | 
				
			||||||
                file_info['bits'] = i16(header_data[10:12])
 | 
					                file_info['bits'] = i16(header_data[10:12])
 | 
				
			||||||
                file_info['compression'] = i32(header_data[12:16])
 | 
					                file_info['compression'] = i32(header_data[12:16])
 | 
				
			||||||
                file_info['data_size'] = i32(header_data[16:20])  # byte size of pixel data
 | 
					                # byte size of pixel data
 | 
				
			||||||
                file_info['pixels_per_meter'] = (i32(header_data[20:24]), i32(header_data[24:28]))
 | 
					                file_info['data_size'] = i32(header_data[16:20])
 | 
				
			||||||
 | 
					                file_info['pixels_per_meter'] = (i32(header_data[20:24]),
 | 
				
			||||||
 | 
					                                                 i32(header_data[24:28]))
 | 
				
			||||||
                file_info['colors'] = i32(header_data[28:32])
 | 
					                file_info['colors'] = i32(header_data[28:32])
 | 
				
			||||||
                file_info['palette_padding'] = 4
 | 
					                file_info['palette_padding'] = 4
 | 
				
			||||||
                self.info["dpi"] = tuple(
 | 
					                self.info["dpi"] = tuple(
 | 
				
			||||||
| 
						 | 
					@ -101,21 +115,32 @@ class BmpImageFile(ImageFile.ImageFile):
 | 
				
			||||||
                        file_info['pixels_per_meter']))
 | 
					                        file_info['pixels_per_meter']))
 | 
				
			||||||
                if file_info['compression'] == self.BITFIELDS:
 | 
					                if file_info['compression'] == self.BITFIELDS:
 | 
				
			||||||
                    if len(header_data) >= 52:
 | 
					                    if len(header_data) >= 52:
 | 
				
			||||||
                        for idx, mask in enumerate(['r_mask', 'g_mask', 'b_mask', 'a_mask']):
 | 
					                        for idx, mask in enumerate(['r_mask',
 | 
				
			||||||
 | 
					                                                    'g_mask',
 | 
				
			||||||
 | 
					                                                    'b_mask',
 | 
				
			||||||
 | 
					                                                    'a_mask']):
 | 
				
			||||||
                            file_info[mask] = i32(header_data[36+idx*4:40+idx*4])
 | 
					                            file_info[mask] = i32(header_data[36+idx*4:40+idx*4])
 | 
				
			||||||
                    else:
 | 
					                    else:
 | 
				
			||||||
                        # 40 byte headers only have the three components in the bitfields masks,
 | 
					                        # 40 byte headers only have the three components in the
 | 
				
			||||||
 | 
					                        # bitfields masks,
 | 
				
			||||||
                        # ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx
 | 
					                        # ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx
 | 
				
			||||||
                        # See also https://github.com/python-pillow/Pillow/issues/1293
 | 
					                        # See also https://github.com/python-pillow/Pillow/issues/1293
 | 
				
			||||||
                        # There is a 4th component in the RGBQuad, in the alpha location, but it
 | 
					                        # There is a 4th component in the RGBQuad, in the alpha
 | 
				
			||||||
                        # is listed as a reserved component, and it is not generally an alpha channel
 | 
					                        # location, but it is listed as a reserved component,
 | 
				
			||||||
 | 
					                        # and it is not generally an alpha channel
 | 
				
			||||||
                        file_info['a_mask'] = 0x0
 | 
					                        file_info['a_mask'] = 0x0
 | 
				
			||||||
                        for mask in ['r_mask', 'g_mask', 'b_mask']:
 | 
					                        for mask in ['r_mask', 'g_mask', 'b_mask']:
 | 
				
			||||||
                            file_info[mask] = i32(read(4))
 | 
					                            file_info[mask] = i32(read(4))
 | 
				
			||||||
                    file_info['rgb_mask'] = (file_info['r_mask'], file_info['g_mask'], file_info['b_mask'])
 | 
					                    file_info['rgb_mask'] = (file_info['r_mask'],
 | 
				
			||||||
                    file_info['rgba_mask'] = (file_info['r_mask'], file_info['g_mask'], file_info['b_mask'], file_info['a_mask'])
 | 
					                                             file_info['g_mask'],
 | 
				
			||||||
 | 
					                                             file_info['b_mask'])
 | 
				
			||||||
 | 
					                    file_info['rgba_mask'] = (file_info['r_mask'],
 | 
				
			||||||
 | 
					                                              file_info['g_mask'],
 | 
				
			||||||
 | 
					                                              file_info['b_mask'],
 | 
				
			||||||
 | 
					                                              file_info['a_mask'])
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            raise IOError("Unsupported BMP header type (%d)" % file_info['header_size'])
 | 
					            raise IOError("Unsupported BMP header type (%d)" %
 | 
				
			||||||
 | 
					                          file_info['header_size'])
 | 
				
			||||||
        # ------------------ Special case : header is reported 40, which
 | 
					        # ------------------ Special case : header is reported 40, which
 | 
				
			||||||
        # ---------------------- is shorter than real size for bpp >= 16
 | 
					        # ---------------------- is shorter than real size for bpp >= 16
 | 
				
			||||||
        self.size = file_info['width'], file_info['height']
 | 
					        self.size = file_info['width'], file_info['height']
 | 
				
			||||||
| 
						 | 
					@ -127,11 +152,15 @@ class BmpImageFile(ImageFile.ImageFile):
 | 
				
			||||||
        # ----------------------- Check bit depth for unusual unsupported values
 | 
					        # ----------------------- Check bit depth for unusual unsupported values
 | 
				
			||||||
        self.mode, raw_mode = BIT2MODE.get(file_info['bits'], (None, None))
 | 
					        self.mode, raw_mode = BIT2MODE.get(file_info['bits'], (None, None))
 | 
				
			||||||
        if self.mode is None:
 | 
					        if self.mode is None:
 | 
				
			||||||
            raise IOError("Unsupported BMP pixel depth (%d)" % file_info['bits'])
 | 
					            raise IOError("Unsupported BMP pixel depth (%d)"
 | 
				
			||||||
 | 
					                          % file_info['bits'])
 | 
				
			||||||
        # ----------------- Process BMP with Bitfields compression (not palette)
 | 
					        # ----------------- Process BMP with Bitfields compression (not palette)
 | 
				
			||||||
        if file_info['compression'] == self.BITFIELDS:
 | 
					        if file_info['compression'] == self.BITFIELDS:
 | 
				
			||||||
            SUPPORTED = {
 | 
					            SUPPORTED = {
 | 
				
			||||||
                32: [(0xff0000, 0xff00, 0xff, 0x0), (0xff0000, 0xff00, 0xff, 0xff000000), (0x0, 0x0, 0x0, 0x0), (0xff000000, 0xff0000, 0xff00, 0x0)],
 | 
					                32: [(0xff0000, 0xff00, 0xff, 0x0),
 | 
				
			||||||
 | 
					                     (0xff0000, 0xff00, 0xff, 0xff000000),
 | 
				
			||||||
 | 
					                     (0x0, 0x0, 0x0, 0x0),
 | 
				
			||||||
 | 
					                     (0xff000000, 0xff0000, 0xff00, 0x0)],
 | 
				
			||||||
                24: [(0xff0000, 0xff00, 0xff)],
 | 
					                24: [(0xff0000, 0xff00, 0xff)],
 | 
				
			||||||
                16: [(0xf800, 0x7e0, 0x1f), (0x7c00, 0x3e0, 0x1f)]
 | 
					                16: [(0xf800, 0x7e0, 0x1f), (0x7c00, 0x3e0, 0x1f)]
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -145,11 +174,15 @@ class BmpImageFile(ImageFile.ImageFile):
 | 
				
			||||||
                (16, (0x7c00, 0x3e0, 0x1f)): "BGR;15"
 | 
					                (16, (0x7c00, 0x3e0, 0x1f)): "BGR;15"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if file_info['bits'] in SUPPORTED:
 | 
					            if file_info['bits'] in SUPPORTED:
 | 
				
			||||||
                if file_info['bits'] == 32 and file_info['rgba_mask'] in SUPPORTED[file_info['bits']]:
 | 
					                if file_info['bits'] == 32 and \
 | 
				
			||||||
 | 
					                   file_info['rgba_mask'] in SUPPORTED[file_info['bits']]:
 | 
				
			||||||
                    raw_mode = MASK_MODES[(file_info['bits'], file_info['rgba_mask'])]
 | 
					                    raw_mode = MASK_MODES[(file_info['bits'], file_info['rgba_mask'])]
 | 
				
			||||||
                    self.mode = "RGBA" if raw_mode in ("BGRA",) else self.mode
 | 
					                    self.mode = "RGBA" if raw_mode in ("BGRA",) else self.mode
 | 
				
			||||||
                elif file_info['bits'] in (24, 16) and file_info['rgb_mask'] in SUPPORTED[file_info['bits']]:
 | 
					                elif (file_info['bits'] in (24, 16) and
 | 
				
			||||||
                    raw_mode = MASK_MODES[(file_info['bits'], file_info['rgb_mask'])]
 | 
					                      file_info['rgb_mask'] in SUPPORTED[file_info['bits']]):
 | 
				
			||||||
 | 
					                    raw_mode = MASK_MODES[
 | 
				
			||||||
 | 
					                        (file_info['bits'], file_info['rgb_mask'])
 | 
				
			||||||
 | 
					                    ]
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    raise IOError("Unsupported BMP bitfields layout")
 | 
					                    raise IOError("Unsupported BMP bitfields layout")
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
| 
						 | 
					@ -158,17 +191,20 @@ class BmpImageFile(ImageFile.ImageFile):
 | 
				
			||||||
            if file_info['bits'] == 32 and header == 22:  # 32-bit .cur offset
 | 
					            if file_info['bits'] == 32 and header == 22:  # 32-bit .cur offset
 | 
				
			||||||
                raw_mode, self.mode = "BGRA", "RGBA"
 | 
					                raw_mode, self.mode = "BGRA", "RGBA"
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            raise IOError("Unsupported BMP compression (%d)" % file_info['compression'])
 | 
					            raise IOError("Unsupported BMP compression (%d)" %
 | 
				
			||||||
 | 
					                          file_info['compression'])
 | 
				
			||||||
        # ---------------- Once the header is processed, process the palette/LUT
 | 
					        # ---------------- Once the header is processed, process the palette/LUT
 | 
				
			||||||
        if self.mode == "P":  # Paletted for 1, 4 and 8 bit images
 | 
					        if self.mode == "P":  # Paletted for 1, 4 and 8 bit images
 | 
				
			||||||
            # ----------------------------------------------------- 1-bit images
 | 
					            # ----------------------------------------------------- 1-bit images
 | 
				
			||||||
            if not (0 < file_info['colors'] <= 65536):
 | 
					            if not (0 < file_info['colors'] <= 65536):
 | 
				
			||||||
                raise IOError("Unsupported BMP Palette size (%d)" % file_info['colors'])
 | 
					                raise IOError("Unsupported BMP Palette size (%d)" %
 | 
				
			||||||
 | 
					                              file_info['colors'])
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                padding = file_info['palette_padding']
 | 
					                padding = file_info['palette_padding']
 | 
				
			||||||
                palette = read(padding * file_info['colors'])
 | 
					                palette = read(padding * file_info['colors'])
 | 
				
			||||||
                greyscale = True
 | 
					                greyscale = True
 | 
				
			||||||
                indices = (0, 255) if file_info['colors'] == 2 else list(range(file_info['colors']))
 | 
					                indices = (0, 255) if file_info['colors'] == 2 else \
 | 
				
			||||||
 | 
					                    list(range(file_info['colors']))
 | 
				
			||||||
                # ------------------ Check if greyscale and ignore palette if so
 | 
					                # ------------------ Check if greyscale and ignore palette if so
 | 
				
			||||||
                for ind, val in enumerate(indices):
 | 
					                for ind, val in enumerate(indices):
 | 
				
			||||||
                    rgb = palette[ind*padding:ind*padding + 3]
 | 
					                    rgb = palette[ind*padding:ind*padding + 3]
 | 
				
			||||||
| 
						 | 
					@ -180,13 +216,19 @@ class BmpImageFile(ImageFile.ImageFile):
 | 
				
			||||||
                    raw_mode = self.mode
 | 
					                    raw_mode = self.mode
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    self.mode = "P"
 | 
					                    self.mode = "P"
 | 
				
			||||||
                    self.palette = ImagePalette.raw("BGRX" if padding == 4 else "BGR", palette)
 | 
					                    self.palette = ImagePalette.raw(
 | 
				
			||||||
 | 
					                        "BGRX" if padding == 4 else "BGR", palette)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # ----------------------------- Finally set the tile data for the plugin
 | 
					        # ----------------------------- Finally set the tile data for the plugin
 | 
				
			||||||
        self.info['compression'] = file_info['compression']
 | 
					        self.info['compression'] = file_info['compression']
 | 
				
			||||||
        self.tile = [('raw', (0, 0, file_info['width'], file_info['height']), offset or self.fp.tell(),
 | 
					        self.tile = [
 | 
				
			||||||
                      (raw_mode, ((file_info['width'] * file_info['bits'] + 31) >> 3) & (~3), file_info['direction'])
 | 
					            ('raw',
 | 
				
			||||||
                      )]
 | 
					             (0, 0, file_info['width'], file_info['height']),
 | 
				
			||||||
 | 
					             offset or self.fp.tell(),
 | 
				
			||||||
 | 
					             (raw_mode,
 | 
				
			||||||
 | 
					              ((file_info['width'] * file_info['bits'] + 31) >> 3) & (~3),
 | 
				
			||||||
 | 
					              file_info['direction']))
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _open(self):
 | 
					    def _open(self):
 | 
				
			||||||
        """ Open file, check magic number and read header """
 | 
					        """ Open file, check magic number and read header """
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -142,7 +142,8 @@ class DdsImageFile(ImageFile.ImageFile):
 | 
				
			||||||
            # ignoring flags which pertain to volume textures and cubemaps
 | 
					            # ignoring flags which pertain to volume textures and cubemaps
 | 
				
			||||||
            dxt10 = BytesIO(self.fp.read(20))
 | 
					            dxt10 = BytesIO(self.fp.read(20))
 | 
				
			||||||
            dxgi_format, dimension = struct.unpack("<II", dxt10.read(8))
 | 
					            dxgi_format, dimension = struct.unpack("<II", dxt10.read(8))
 | 
				
			||||||
            if dxgi_format in (DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM):
 | 
					            if dxgi_format in (DXGI_FORMAT_BC7_TYPELESS,
 | 
				
			||||||
 | 
					                               DXGI_FORMAT_BC7_UNORM):
 | 
				
			||||||
                self.pixel_format = "BC7"
 | 
					                self.pixel_format = "BC7"
 | 
				
			||||||
                n = 7
 | 
					                n = 7
 | 
				
			||||||
            elif dxgi_format == DXGI_FORMAT_BC7_UNORM_SRGB:
 | 
					            elif dxgi_format == DXGI_FORMAT_BC7_UNORM_SRGB:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,8 @@ Full text of the CC0 license:
 | 
				
			||||||
Independence War 2: Edge Of Chaos - Texture File Format - 16 October 2001
 | 
					Independence War 2: Edge Of Chaos - Texture File Format - 16 October 2001
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The textures used for 3D objects in Independence War 2: Edge Of Chaos are in a
 | 
					The textures used for 3D objects in Independence War 2: Edge Of Chaos are in a
 | 
				
			||||||
packed custom format called FTEX. This file format uses file extensions FTC and FTU.
 | 
					packed custom format called FTEX. This file format uses file extensions FTC
 | 
				
			||||||
 | 
					and FTU.
 | 
				
			||||||
* FTC files are compressed textures (using standard texture compression).
 | 
					* FTC files are compressed textures (using standard texture compression).
 | 
				
			||||||
* FTU files are not compressed.
 | 
					* FTU files are not compressed.
 | 
				
			||||||
Texture File Format
 | 
					Texture File Format
 | 
				
			||||||
| 
						 | 
					@ -24,18 +25,21 @@ Where:
 | 
				
			||||||
* The "magic" number is "FTEX".
 | 
					* The "magic" number is "FTEX".
 | 
				
			||||||
* "width" and "height" are the dimensions of the texture.
 | 
					* "width" and "height" are the dimensions of the texture.
 | 
				
			||||||
* "mipmap_count" is the number of mipmaps in the texture.
 | 
					* "mipmap_count" is the number of mipmaps in the texture.
 | 
				
			||||||
* "format_count" is the number of texture formats (different versions of the same texture) in this file.
 | 
					* "format_count" is the number of texture formats (different versions of the
 | 
				
			||||||
 | 
					same texture) in this file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{format_directory} = format_count * { u32:format, u32:where }
 | 
					{format_directory} = format_count * { u32:format, u32:where }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The format value is 0 for DXT1 compressed textures and 1 for 24-bit RGB uncompressed textures.
 | 
					The format value is 0 for DXT1 compressed textures and 1 for 24-bit RGB
 | 
				
			||||||
 | 
					uncompressed textures.
 | 
				
			||||||
The texture data for a format starts at the position "where" in the file.
 | 
					The texture data for a format starts at the position "where" in the file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Each set of texture data in the file has the following structure:
 | 
					Each set of texture data in the file has the following structure:
 | 
				
			||||||
{data} = format_count * { u32:mipmap_size, mipmap_size * { u8 } }
 | 
					{data} = format_count * { u32:mipmap_size, mipmap_size * { u8 } }
 | 
				
			||||||
* "mipmap_size" is the number of bytes in that mip level. For compressed textures this is the
 | 
					* "mipmap_size" is the number of bytes in that mip level. For compressed
 | 
				
			||||||
size of the texture data compressed with DXT1. For 24 bit uncompressed textures, this is 3 * width * height.
 | 
					textures this is the size of the texture data compressed with DXT1. For 24 bit
 | 
				
			||||||
Following this are the image bytes for that mipmap level.
 | 
					uncompressed textures, this is 3 * width * height. Following this are the image
 | 
				
			||||||
 | 
					bytes for that mipmap level.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Note: All data is stored in little-Endian (Intel) byte order.
 | 
					Note: All data is stored in little-Endian (Intel) byte order.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
| 
						 | 
					@ -62,7 +66,8 @@ class FtexImageFile(ImageFile.ImageFile):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.mode = "RGB"
 | 
					        self.mode = "RGB"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Only support single-format files. I don't know of any multi-format file.
 | 
					        # Only support single-format files.
 | 
				
			||||||
 | 
					        # I don't know of any multi-format file.
 | 
				
			||||||
        assert format_count == 1
 | 
					        assert format_count == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        format, where = struct.unpack("<2i", self.fp.read(8))
 | 
					        format, where = struct.unpack("<2i", self.fp.read(8))
 | 
				
			||||||
| 
						 | 
					@ -77,7 +82,8 @@ class FtexImageFile(ImageFile.ImageFile):
 | 
				
			||||||
        elif format == FORMAT_UNCOMPRESSED:
 | 
					        elif format == FORMAT_UNCOMPRESSED:
 | 
				
			||||||
            self.tile = [("raw", (0, 0) + self.size, 0, ('RGB', 0, 1))]
 | 
					            self.tile = [("raw", (0, 0) + self.size, 0, ('RGB', 0, 1))]
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            raise ValueError("Invalid texture compression format: %r" % (format))
 | 
					            raise ValueError(
 | 
				
			||||||
 | 
					                "Invalid texture compression format: %r" % (format))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.fp.close()
 | 
					        self.fp.close()
 | 
				
			||||||
        self.fp = BytesIO(data)
 | 
					        self.fp = BytesIO(data)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,8 @@ from ._binary import i32be as i32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _accept(prefix):
 | 
					def _accept(prefix):
 | 
				
			||||||
    return len(prefix) >= 8 and i32(prefix[:4]) >= 20 and i32(prefix[4:8]) in (1, 2)
 | 
					    return len(prefix) >= 8 and \
 | 
				
			||||||
 | 
					           i32(prefix[:4]) >= 20 and i32(prefix[4:8]) in (1, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##
 | 
					##
 | 
				
			||||||
| 
						 | 
					@ -54,7 +55,8 @@ class GbrImageFile(ImageFile.ImageFile):
 | 
				
			||||||
        if width <= 0 or height <= 0:
 | 
					        if width <= 0 or height <= 0:
 | 
				
			||||||
            raise SyntaxError("not a GIMP brush")
 | 
					            raise SyntaxError("not a GIMP brush")
 | 
				
			||||||
        if color_depth not in (1, 4):
 | 
					        if color_depth not in (1, 4):
 | 
				
			||||||
            raise SyntaxError("Unsupported GIMP brush color depth: %s" % color_depth)
 | 
					            raise SyntaxError(
 | 
				
			||||||
 | 
					                "Unsupported GIMP brush color depth: %s" % color_depth)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if version == 1:
 | 
					        if version == 1:
 | 
				
			||||||
            comment_length = header_size-20
 | 
					            comment_length = header_size-20
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -397,7 +397,8 @@ def _write_multiple_frames(im, fp, palette):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    im_frames = []
 | 
					    im_frames = []
 | 
				
			||||||
    frame_count = 0
 | 
					    frame_count = 0
 | 
				
			||||||
    for imSequence in itertools.chain([im], im.encoderinfo.get("append_images", [])):
 | 
					    for imSequence in itertools.chain([im],
 | 
				
			||||||
 | 
					                                      im.encoderinfo.get("append_images", [])):
 | 
				
			||||||
        for im_frame in ImageSequence.Iterator(imSequence):
 | 
					        for im_frame in ImageSequence.Iterator(imSequence):
 | 
				
			||||||
            # a copy is required here since seek can still mutate the image
 | 
					            # a copy is required here since seek can still mutate the image
 | 
				
			||||||
            im_frame = _normalize_mode(im_frame.copy())
 | 
					            im_frame = _normalize_mode(im_frame.copy())
 | 
				
			||||||
| 
						 | 
					@ -413,17 +414,19 @@ def _write_multiple_frames(im, fp, palette):
 | 
				
			||||||
            if im_frames:
 | 
					            if im_frames:
 | 
				
			||||||
                # delta frame
 | 
					                # delta frame
 | 
				
			||||||
                previous = im_frames[-1]
 | 
					                previous = im_frames[-1]
 | 
				
			||||||
                if _get_palette_bytes(im_frame) == _get_palette_bytes(previous['im']):
 | 
					                if _get_palette_bytes(im_frame) == \
 | 
				
			||||||
 | 
					                   _get_palette_bytes(previous['im']):
 | 
				
			||||||
                    delta = ImageChops.subtract_modulo(im_frame,
 | 
					                    delta = ImageChops.subtract_modulo(im_frame,
 | 
				
			||||||
                                                       previous['im'])
 | 
					                                                       previous['im'])
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    delta = ImageChops.subtract_modulo(im_frame.convert('RGB'),
 | 
					                    delta = ImageChops.subtract_modulo(
 | 
				
			||||||
                                                       previous['im'].convert('RGB'))
 | 
					                        im_frame.convert('RGB'), previous['im'].convert('RGB'))
 | 
				
			||||||
                bbox = delta.getbbox()
 | 
					                bbox = delta.getbbox()
 | 
				
			||||||
                if not bbox:
 | 
					                if not bbox:
 | 
				
			||||||
                    # This frame is identical to the previous frame
 | 
					                    # This frame is identical to the previous frame
 | 
				
			||||||
                    if duration:
 | 
					                    if duration:
 | 
				
			||||||
                        previous['encoderinfo']['duration'] += encoderinfo['duration']
 | 
					                        previous['encoderinfo']['duration'] += \
 | 
				
			||||||
 | 
					                            encoderinfo['duration']
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                bbox = None
 | 
					                bbox = None
 | 
				
			||||||
| 
						 | 
					@ -525,7 +528,8 @@ def _write_local_header(fp, im, offset, flags):
 | 
				
			||||||
                 o8(transparency) +       # transparency index
 | 
					                 o8(transparency) +       # transparency index
 | 
				
			||||||
                 o8(0))
 | 
					                 o8(0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if "comment" in im.encoderinfo and 1 <= len(im.encoderinfo["comment"]) <= 255:
 | 
					    if "comment" in im.encoderinfo and \
 | 
				
			||||||
 | 
					       1 <= len(im.encoderinfo["comment"]) <= 255:
 | 
				
			||||||
        fp.write(b"!" +
 | 
					        fp.write(b"!" +
 | 
				
			||||||
                 o8(254) +                # extension intro
 | 
					                 o8(254) +                # extension intro
 | 
				
			||||||
                 o8(len(im.encoderinfo["comment"])) +
 | 
					                 o8(len(im.encoderinfo["comment"])) +
 | 
				
			||||||
| 
						 | 
					@ -691,7 +695,8 @@ def _get_global_header(im, info):
 | 
				
			||||||
    for extensionKey in ["transparency", "duration", "loop", "comment"]:
 | 
					    for extensionKey in ["transparency", "duration", "loop", "comment"]:
 | 
				
			||||||
        if info and extensionKey in info:
 | 
					        if info and extensionKey in info:
 | 
				
			||||||
            if ((extensionKey == "duration" and info[extensionKey] == 0) or
 | 
					            if ((extensionKey == "duration" and info[extensionKey] == 0) or
 | 
				
			||||||
               (extensionKey == "comment" and not (1 <= len(info[extensionKey]) <= 255))):
 | 
					                (extensionKey == "comment" and
 | 
				
			||||||
 | 
					                 not (1 <= len(info[extensionKey]) <= 255))):
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            version = b"89a"
 | 
					            version = b"89a"
 | 
				
			||||||
            break
 | 
					            break
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -305,10 +305,10 @@ def profileToProfile(
 | 
				
			||||||
    :param renderingIntent: Integer (0-3) specifying the rendering intent you
 | 
					    :param renderingIntent: Integer (0-3) specifying the rendering intent you
 | 
				
			||||||
        wish to use for the transform
 | 
					        wish to use for the transform
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            INTENT_PERCEPTUAL            = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL)
 | 
					            ImageCms.INTENT_PERCEPTUAL            = 0 (DEFAULT)
 | 
				
			||||||
            INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC)
 | 
					            ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
 | 
				
			||||||
            INTENT_SATURATION            = 2 (ImageCms.INTENT_SATURATION)
 | 
					            ImageCms.INTENT_SATURATION            = 2
 | 
				
			||||||
            INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC)
 | 
					            ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        see the pyCMS documentation for details on rendering intents and what
 | 
					        see the pyCMS documentation for details on rendering intents and what
 | 
				
			||||||
        they do.
 | 
					        they do.
 | 
				
			||||||
| 
						 | 
					@ -424,10 +424,10 @@ def buildTransform(
 | 
				
			||||||
    :param renderingIntent: Integer (0-3) specifying the rendering intent you
 | 
					    :param renderingIntent: Integer (0-3) specifying the rendering intent you
 | 
				
			||||||
        wish to use for the transform
 | 
					        wish to use for the transform
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            INTENT_PERCEPTUAL            = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL)
 | 
					            ImageCms.INTENT_PERCEPTUAL            = 0 (DEFAULT)
 | 
				
			||||||
            INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC)
 | 
					            ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
 | 
				
			||||||
            INTENT_SATURATION            = 2 (ImageCms.INTENT_SATURATION)
 | 
					            ImageCms.INTENT_SATURATION            = 2
 | 
				
			||||||
            INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC)
 | 
					            ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        see the pyCMS documentation for details on rendering intents and what
 | 
					        see the pyCMS documentation for details on rendering intents and what
 | 
				
			||||||
        they do.
 | 
					        they do.
 | 
				
			||||||
| 
						 | 
					@ -512,20 +512,20 @@ def buildProofTransform(
 | 
				
			||||||
    :param renderingIntent: Integer (0-3) specifying the rendering intent you
 | 
					    :param renderingIntent: Integer (0-3) specifying the rendering intent you
 | 
				
			||||||
        wish to use for the input->proof (simulated) transform
 | 
					        wish to use for the input->proof (simulated) transform
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            INTENT_PERCEPTUAL            = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL)
 | 
					            ImageCms.INTENT_PERCEPTUAL            = 0 (DEFAULT)
 | 
				
			||||||
            INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC)
 | 
					            ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
 | 
				
			||||||
            INTENT_SATURATION            = 2 (ImageCms.INTENT_SATURATION)
 | 
					            ImageCms.INTENT_SATURATION            = 2
 | 
				
			||||||
            INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC)
 | 
					            ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        see the pyCMS documentation for details on rendering intents and what
 | 
					        see the pyCMS documentation for details on rendering intents and what
 | 
				
			||||||
        they do.
 | 
					        they do.
 | 
				
			||||||
    :param proofRenderingIntent: Integer (0-3) specifying the rendering intent you
 | 
					    :param proofRenderingIntent: Integer (0-3) specifying the rendering intent
 | 
				
			||||||
        wish to use for proof->output transform
 | 
					        you wish to use for proof->output transform
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            INTENT_PERCEPTUAL            = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL)
 | 
					            ImageCms.INTENT_PERCEPTUAL            = 0 (DEFAULT)
 | 
				
			||||||
            INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC)
 | 
					            ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
 | 
				
			||||||
            INTENT_SATURATION            = 2 (ImageCms.INTENT_SATURATION)
 | 
					            ImageCms.INTENT_SATURATION            = 2
 | 
				
			||||||
            INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC)
 | 
					            ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        see the pyCMS documentation for details on rendering intents and what
 | 
					        see the pyCMS documentation for details on rendering intents and what
 | 
				
			||||||
        they do.
 | 
					        they do.
 | 
				
			||||||
| 
						 | 
					@ -875,10 +875,10 @@ def getDefaultIntent(profile):
 | 
				
			||||||
    :returns: Integer 0-3 specifying the default rendering intent for this
 | 
					    :returns: Integer 0-3 specifying the default rendering intent for this
 | 
				
			||||||
        profile.
 | 
					        profile.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            INTENT_PERCEPTUAL            = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL)
 | 
					            ImageCms.INTENT_PERCEPTUAL            = 0 (DEFAULT)
 | 
				
			||||||
            INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC)
 | 
					            ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
 | 
				
			||||||
            INTENT_SATURATION            = 2 (ImageCms.INTENT_SATURATION)
 | 
					            ImageCms.INTENT_SATURATION            = 2
 | 
				
			||||||
            INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC)
 | 
					            ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        see the pyCMS documentation for details on rendering intents and what
 | 
					        see the pyCMS documentation for details on rendering intents and what
 | 
				
			||||||
            they do.
 | 
					            they do.
 | 
				
			||||||
| 
						 | 
					@ -913,15 +913,15 @@ def isIntentSupported(profile, intent, direction):
 | 
				
			||||||
    :param intent: Integer (0-3) specifying the rendering intent you wish to
 | 
					    :param intent: Integer (0-3) specifying the rendering intent you wish to
 | 
				
			||||||
        use with this profile
 | 
					        use with this profile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            INTENT_PERCEPTUAL            = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL)
 | 
					            ImageCms.INTENT_PERCEPTUAL            = 0 (DEFAULT)
 | 
				
			||||||
            INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC)
 | 
					            ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
 | 
				
			||||||
            INTENT_SATURATION            = 2 (ImageCms.INTENT_SATURATION)
 | 
					            ImageCms.INTENT_SATURATION            = 2
 | 
				
			||||||
            INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC)
 | 
					            ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        see the pyCMS documentation for details on rendering intents and what
 | 
					        see the pyCMS documentation for details on rendering intents and what
 | 
				
			||||||
            they do.
 | 
					            they do.
 | 
				
			||||||
    :param direction: Integer specifying if the profile is to be used for input,
 | 
					    :param direction: Integer specifying if the profile is to be used for
 | 
				
			||||||
        output, or proof
 | 
					        input, output, or proof
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            INPUT  = 0 (or use ImageCms.DIRECTION_INPUT)
 | 
					            INPUT  = 0 (or use ImageCms.DIRECTION_INPUT)
 | 
				
			||||||
            OUTPUT = 1 (or use ImageCms.DIRECTION_OUTPUT)
 | 
					            OUTPUT = 1 (or use ImageCms.DIRECTION_OUTPUT)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -217,7 +217,8 @@ class ImageDraw(object):
 | 
				
			||||||
            ink = fill
 | 
					            ink = fill
 | 
				
			||||||
        if ink is not None:
 | 
					        if ink is not None:
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                mask, offset = font.getmask2(text, self.fontmode, *args, **kwargs)
 | 
					                mask, offset = font.getmask2(text, self.fontmode,
 | 
				
			||||||
 | 
					                                             *args, **kwargs)
 | 
				
			||||||
                xy = xy[0] + offset[0], xy[1] + offset[1]
 | 
					                xy = xy[0] + offset[0], xy[1] + offset[1]
 | 
				
			||||||
            except AttributeError:
 | 
					            except AttributeError:
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,7 +51,8 @@ class Color(_Enhance):
 | 
				
			||||||
        if 'A' in image.getbands():
 | 
					        if 'A' in image.getbands():
 | 
				
			||||||
            self.intermediate_mode = 'LA'
 | 
					            self.intermediate_mode = 'LA'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.degenerate = image.convert(self.intermediate_mode).convert(image.mode)
 | 
					        self.degenerate = image.convert(
 | 
				
			||||||
 | 
					            self.intermediate_mode).convert(image.mode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Contrast(_Enhance):
 | 
					class Contrast(_Enhance):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -166,8 +166,9 @@ class ImageFile(Image.Image):
 | 
				
			||||||
        if use_mmap:
 | 
					        if use_mmap:
 | 
				
			||||||
            # try memory mapping
 | 
					            # try memory mapping
 | 
				
			||||||
            decoder_name, extents, offset, args = self.tile[0]
 | 
					            decoder_name, extents, offset, args = self.tile[0]
 | 
				
			||||||
            if decoder_name == "raw" and len(args) >= 3 and args[0] == self.mode \
 | 
					            if decoder_name == "raw" and len(args) >= 3 and \
 | 
				
			||||||
               and args[0] in Image._MAPMODES:
 | 
					               args[0] == self.mode and \
 | 
				
			||||||
 | 
					               args[0] in Image._MAPMODES:
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    if hasattr(Image.core, "map"):
 | 
					                    if hasattr(Image.core, "map"):
 | 
				
			||||||
                        # use built-in mapper  WIN32 only
 | 
					                        # use built-in mapper  WIN32 only
 | 
				
			||||||
| 
						 | 
					@ -180,12 +181,14 @@ class ImageFile(Image.Image):
 | 
				
			||||||
                        # use mmap, if possible
 | 
					                        # use mmap, if possible
 | 
				
			||||||
                        import mmap
 | 
					                        import mmap
 | 
				
			||||||
                        with open(self.filename, "r") as fp:
 | 
					                        with open(self.filename, "r") as fp:
 | 
				
			||||||
                            self.map = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ)
 | 
					                            self.map = mmap.mmap(fp.fileno(), 0,
 | 
				
			||||||
 | 
					                                                 access=mmap.ACCESS_READ)
 | 
				
			||||||
                        self.im = Image.core.map_buffer(
 | 
					                        self.im = Image.core.map_buffer(
 | 
				
			||||||
                            self.map, self.size, decoder_name, extents, offset, args
 | 
					                            self.map, self.size, decoder_name, extents,
 | 
				
			||||||
                            )
 | 
					                            offset, args)
 | 
				
			||||||
                    readonly = 1
 | 
					                    readonly = 1
 | 
				
			||||||
                    # After trashing self.im, we might need to reload the palette data.
 | 
					                    # After trashing self.im,
 | 
				
			||||||
 | 
					                    # we might need to reload the palette data.
 | 
				
			||||||
                    if self.palette:
 | 
					                    if self.palette:
 | 
				
			||||||
                        self.palette.dirty = 1
 | 
					                        self.palette.dirty = 1
 | 
				
			||||||
                except (AttributeError, EnvironmentError, ImportError):
 | 
					                except (AttributeError, EnvironmentError, ImportError):
 | 
				
			||||||
| 
						 | 
					@ -217,7 +220,8 @@ class ImageFile(Image.Image):
 | 
				
			||||||
                        while True:
 | 
					                        while True:
 | 
				
			||||||
                            try:
 | 
					                            try:
 | 
				
			||||||
                                s = read(self.decodermaxblock)
 | 
					                                s = read(self.decodermaxblock)
 | 
				
			||||||
                            except (IndexError, struct.error):  # truncated png/gif
 | 
					                            except (IndexError, struct.error):
 | 
				
			||||||
 | 
					                                # truncated png/gif
 | 
				
			||||||
                                if LOAD_TRUNCATED_IMAGES:
 | 
					                                if LOAD_TRUNCATED_IMAGES:
 | 
				
			||||||
                                    break
 | 
					                                    break
 | 
				
			||||||
                                else:
 | 
					                                else:
 | 
				
			||||||
| 
						 | 
					@ -229,7 +233,8 @@ class ImageFile(Image.Image):
 | 
				
			||||||
                                else:
 | 
					                                else:
 | 
				
			||||||
                                    self.tile = []
 | 
					                                    self.tile = []
 | 
				
			||||||
                                    raise IOError("image file is truncated "
 | 
					                                    raise IOError("image file is truncated "
 | 
				
			||||||
                                                  "(%d bytes not processed)" % len(b))
 | 
					                                                  "(%d bytes not processed)" %
 | 
				
			||||||
 | 
					                                                  len(b))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            b = b + s
 | 
					                            b = b + s
 | 
				
			||||||
                            n, err_code = decoder.decode(b)
 | 
					                            n, err_code = decoder.decode(b)
 | 
				
			||||||
| 
						 | 
					@ -588,10 +593,12 @@ class PyDecoder(object):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Override to perform the decoding process.
 | 
					        Override to perform the decoding process.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :param buffer: A bytes object with the data to be decoded.  If `handles_eof`
 | 
					        :param buffer: A bytes object with the data to be decoded.
 | 
				
			||||||
             is set, then `buffer` will be empty and `self.fd` will be set.
 | 
					            If `handles_eof` is set, then `buffer` will be empty and `self.fd`
 | 
				
			||||||
        :returns: A tuple of (bytes consumed, errcode). If finished with decoding
 | 
					            will be set.
 | 
				
			||||||
             return <0 for the bytes consumed. Err codes are from `ERRORS`
 | 
					        :returns: A tuple of (bytes consumed, errcode).
 | 
				
			||||||
 | 
					            If finished with decoding return <0 for the bytes consumed.
 | 
				
			||||||
 | 
					            Err codes are from `ERRORS`
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        raise NotImplementedError()
 | 
					        raise NotImplementedError()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -650,8 +657,8 @@ class PyDecoder(object):
 | 
				
			||||||
        Convenience method to set the internal image from a stream of raw data
 | 
					        Convenience method to set the internal image from a stream of raw data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :param data: Bytes to be set
 | 
					        :param data: Bytes to be set
 | 
				
			||||||
        :param rawmode: The rawmode to be used for the decoder. If not specified,
 | 
					        :param rawmode: The rawmode to be used for the decoder.
 | 
				
			||||||
             it will default to the mode of the image
 | 
					            If not specified, it will default to the mode of the image
 | 
				
			||||||
        :returns: None
 | 
					        :returns: None
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -141,7 +141,8 @@ class FreeTypeFont(object):
 | 
				
			||||||
        self.layout_engine = layout_engine
 | 
					        self.layout_engine = layout_engine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if isPath(font):
 | 
					        if isPath(font):
 | 
				
			||||||
            self.font = core.getfont(font, size, index, encoding, layout_engine=layout_engine)
 | 
					            self.font = core.getfont(font, size, index, encoding,
 | 
				
			||||||
 | 
					                                     layout_engine=layout_engine)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            self.font_bytes = font.read()
 | 
					            self.font_bytes = font.read()
 | 
				
			||||||
            self.font = core.getfont(
 | 
					            self.font = core.getfont(
 | 
				
			||||||
| 
						 | 
					@ -175,9 +176,11 @@ class FreeTypeFont(object):
 | 
				
			||||||
        return self.font.getsize(text)[1]
 | 
					        return self.font.getsize(text)[1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getmask(self, text, mode="", direction=None, features=None):
 | 
					    def getmask(self, text, mode="", direction=None, features=None):
 | 
				
			||||||
        return self.getmask2(text, mode, direction=direction, features=features)[0]
 | 
					        return self.getmask2(text, mode, direction=direction,
 | 
				
			||||||
 | 
					                             features=features)[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getmask2(self, text, mode="", fill=Image.core.fill, direction=None, features=None, *args, **kwargs):
 | 
					    def getmask2(self, text, mode="", fill=Image.core.fill, direction=None,
 | 
				
			||||||
 | 
					                 features=None, *args, **kwargs):
 | 
				
			||||||
        size, offset = self.font.getsize(text, direction, features)
 | 
					        size, offset = self.font.getsize(text, direction, features)
 | 
				
			||||||
        im = fill("L", size, 0)
 | 
					        im = fill("L", size, 0)
 | 
				
			||||||
        self.font.render(text, im.id, mode == "1", direction, features)
 | 
					        self.font.render(text, im.id, mode == "1", direction, features)
 | 
				
			||||||
| 
						 | 
					@ -194,12 +197,13 @@ class FreeTypeFont(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :return: A FreeTypeFont object.
 | 
					        :return: A FreeTypeFont object.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        return FreeTypeFont(font=self.path if font is None else font,
 | 
					        return FreeTypeFont(
 | 
				
			||||||
                            size=self.size if size is None else size,
 | 
					            font=self.path if font is None else font,
 | 
				
			||||||
                            index=self.index if index is None else index,
 | 
					            size=self.size if size is None else size,
 | 
				
			||||||
                            encoding=self.encoding if encoding is None else encoding,
 | 
					            index=self.index if index is None else index,
 | 
				
			||||||
                            layout_engine=self.layout_engine if layout_engine is None else layout_engine
 | 
					            encoding=self.encoding if encoding is None else encoding,
 | 
				
			||||||
                            )
 | 
					            layout_engine=self.layout_engine if layout_engine is None else layout_engine
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TransposedFont(object):
 | 
					class TransposedFont(object):
 | 
				
			||||||
| 
						 | 
					@ -303,12 +307,16 @@ def truetype(font=None, size=10, index=0, encoding="",
 | 
				
			||||||
                for walkfilename in walkfilenames:
 | 
					                for walkfilename in walkfilenames:
 | 
				
			||||||
                    if ext and walkfilename == ttf_filename:
 | 
					                    if ext and walkfilename == ttf_filename:
 | 
				
			||||||
                        fontpath = os.path.join(walkroot, walkfilename)
 | 
					                        fontpath = os.path.join(walkroot, walkfilename)
 | 
				
			||||||
                        return FreeTypeFont(fontpath, size, index, encoding, layout_engine)
 | 
					                        return FreeTypeFont(fontpath, size, index,
 | 
				
			||||||
                    elif not ext and os.path.splitext(walkfilename)[0] == ttf_filename:
 | 
					                                            encoding, layout_engine)
 | 
				
			||||||
 | 
					                    elif (not ext and
 | 
				
			||||||
 | 
					                          os.path.splitext(walkfilename)[0] == ttf_filename):
 | 
				
			||||||
                        fontpath = os.path.join(walkroot, walkfilename)
 | 
					                        fontpath = os.path.join(walkroot, walkfilename)
 | 
				
			||||||
                        if os.path.splitext(fontpath)[1] == '.ttf':
 | 
					                        if os.path.splitext(fontpath)[1] == '.ttf':
 | 
				
			||||||
                            return FreeTypeFont(fontpath, size, index, encoding, layout_engine)
 | 
					                            return FreeTypeFont(fontpath, size, index,
 | 
				
			||||||
                        if not ext and first_font_with_a_different_extension is None:
 | 
					                                                encoding, layout_engine)
 | 
				
			||||||
 | 
					                        if not ext \
 | 
				
			||||||
 | 
					                           and first_font_with_a_different_extension is None:
 | 
				
			||||||
                            first_font_with_a_different_extension = fontpath
 | 
					                            first_font_with_a_different_extension = fontpath
 | 
				
			||||||
        if first_font_with_a_different_extension:
 | 
					        if first_font_with_a_different_extension:
 | 
				
			||||||
            return FreeTypeFont(first_font_with_a_different_extension, size,
 | 
					            return FreeTypeFont(first_font_with_a_different_extension, size,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,8 @@ def getmode(mode):
 | 
				
			||||||
        for m, (basemode, basetype, bands) in Image._MODEINFO.items():
 | 
					        for m, (basemode, basetype, bands) in Image._MODEINFO.items():
 | 
				
			||||||
            modes[m] = ModeDescriptor(m, bands, basemode, basetype)
 | 
					            modes[m] = ModeDescriptor(m, bands, basemode, basetype)
 | 
				
			||||||
        # extra experimental modes
 | 
					        # extra experimental modes
 | 
				
			||||||
        modes["RGBa"] = ModeDescriptor("RGBa", ("R", "G", "B", "a"), "RGB", "L")
 | 
					        modes["RGBa"] = ModeDescriptor("RGBa",
 | 
				
			||||||
 | 
					                                       ("R", "G", "B", "a"), "RGB", "L")
 | 
				
			||||||
        modes["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L")
 | 
					        modes["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L")
 | 
				
			||||||
        modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L")
 | 
					        modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L")
 | 
				
			||||||
        modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L")
 | 
					        modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -119,7 +119,8 @@ def align8to32(bytes, width, mode):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    new_data = []
 | 
					    new_data = []
 | 
				
			||||||
    for i in range(len(bytes) // bytes_per_line):
 | 
					    for i in range(len(bytes) // bytes_per_line):
 | 
				
			||||||
        new_data.append(bytes[i*bytes_per_line:(i+1)*bytes_per_line] + b'\x00' * extra_padding)
 | 
					        new_data.append(bytes[i*bytes_per_line:(i+1)*bytes_per_line]
 | 
				
			||||||
 | 
					                        + b'\x00' * extra_padding)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return b''.join(new_data)
 | 
					    return b''.join(new_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -195,7 +195,8 @@ class PhotoImage(object):
 | 
				
			||||||
                        # Pypy is using a ffi cdata element
 | 
					                        # Pypy is using a ffi cdata element
 | 
				
			||||||
                        # (Pdb) self.tk.interp
 | 
					                        # (Pdb) self.tk.interp
 | 
				
			||||||
                        #  <cdata 'Tcl_Interp *' 0x3061b50>
 | 
					                        #  <cdata 'Tcl_Interp *' 0x3061b50>
 | 
				
			||||||
                        _imagingtk.tkinit(int(ffi.cast("uintptr_t", tk.interp)), 1)
 | 
					                        _imagingtk.tkinit(
 | 
				
			||||||
 | 
					                            int(ffi.cast("uintptr_t", tk.interp)), 1)
 | 
				
			||||||
                    else:
 | 
					                    else:
 | 
				
			||||||
                        _imagingtk.tkinit(tk.interpaddr(), 1)
 | 
					                        _imagingtk.tkinit(tk.interpaddr(), 1)
 | 
				
			||||||
                except AttributeError:
 | 
					                except AttributeError:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -270,7 +270,8 @@ def _save(im, fp, filename):
 | 
				
			||||||
Image.register_open(Jpeg2KImageFile.format, Jpeg2KImageFile, _accept)
 | 
					Image.register_open(Jpeg2KImageFile.format, Jpeg2KImageFile, _accept)
 | 
				
			||||||
Image.register_save(Jpeg2KImageFile.format, _save)
 | 
					Image.register_save(Jpeg2KImageFile.format, _save)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Image.register_extensions(Jpeg2KImageFile.format, [".jp2", ".j2k", ".jpc", ".jpf", ".jpx", ".j2c"])
 | 
					Image.register_extensions(Jpeg2KImageFile.format,
 | 
				
			||||||
 | 
					                          [".jp2", ".j2k", ".jpc", ".jpf", ".jpx", ".j2c"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Image.register_mime(Jpeg2KImageFile.format, 'image/jp2')
 | 
					Image.register_mime(Jpeg2KImageFile.format, 'image/jp2')
 | 
				
			||||||
Image.register_mime(Jpeg2KImageFile.format, 'image/jpx')
 | 
					Image.register_mime(Jpeg2KImageFile.format, 'image/jpx')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -799,6 +799,7 @@ def jpeg_factory(fp=None, filename=None):
 | 
				
			||||||
Image.register_open(JpegImageFile.format, jpeg_factory, _accept)
 | 
					Image.register_open(JpegImageFile.format, jpeg_factory, _accept)
 | 
				
			||||||
Image.register_save(JpegImageFile.format, _save)
 | 
					Image.register_save(JpegImageFile.format, _save)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Image.register_extensions(JpegImageFile.format, [".jfif", ".jpe", ".jpg", ".jpeg"])
 | 
					Image.register_extensions(JpegImageFile.format,
 | 
				
			||||||
 | 
					                          [".jfif", ".jpe", ".jpg", ".jpeg"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Image.register_mime(JpegImageFile.format, "image/jpeg")
 | 
					Image.register_mime(JpegImageFile.format, "image/jpeg")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,8 +126,9 @@ class MspDecoder(ImageFile.PyDecoder):
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
                row = self.fd.read(rowlen)
 | 
					                row = self.fd.read(rowlen)
 | 
				
			||||||
                if len(row) != rowlen:
 | 
					                if len(row) != rowlen:
 | 
				
			||||||
                    raise IOError("Truncated MSP file, expected %d bytes on row %s",
 | 
					                    raise IOError(
 | 
				
			||||||
                                  (rowlen, x))
 | 
					                        "Truncated MSP file, expected %d bytes on row %s",
 | 
				
			||||||
 | 
					                        (rowlen, x))
 | 
				
			||||||
                idx = 0
 | 
					                idx = 0
 | 
				
			||||||
                while idx < rowlen:
 | 
					                while idx < rowlen:
 | 
				
			||||||
                    runtype = i8(row[idx])
 | 
					                    runtype = i8(row[idx])
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,7 +98,8 @@ def _save(im, fp, filename, save_all=False):
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                im_numberOfPages = im.n_frames
 | 
					                im_numberOfPages = im.n_frames
 | 
				
			||||||
            except AttributeError:
 | 
					            except AttributeError:
 | 
				
			||||||
                # Image format does not have n_frames. It is a single frame image
 | 
					                # Image format does not have n_frames.
 | 
				
			||||||
 | 
					                # It is a single frame image
 | 
				
			||||||
                pass
 | 
					                pass
 | 
				
			||||||
        numberOfPages += im_numberOfPages
 | 
					        numberOfPages += im_numberOfPages
 | 
				
			||||||
        for i in range(im_numberOfPages):
 | 
					        for i in range(im_numberOfPages):
 | 
				
			||||||
| 
						 | 
					@ -115,9 +116,9 @@ def _save(im, fp, filename, save_all=False):
 | 
				
			||||||
    for imSequence in ims:
 | 
					    for imSequence in ims:
 | 
				
			||||||
        im_pages = ImageSequence.Iterator(imSequence) if save_all else [imSequence]
 | 
					        im_pages = ImageSequence.Iterator(imSequence) if save_all else [imSequence]
 | 
				
			||||||
        for im in im_pages:
 | 
					        for im in im_pages:
 | 
				
			||||||
            # FIXME: Should replace ASCIIHexDecode with RunLengthDecode (packbits)
 | 
					            # FIXME: Should replace ASCIIHexDecode with RunLengthDecode
 | 
				
			||||||
            # or LZWDecode (tiff/lzw compression).  Note that PDF 1.2 also supports
 | 
					            # (packbits) or LZWDecode (tiff/lzw compression).  Note that
 | 
				
			||||||
            # Flatedecode (zip compression).
 | 
					            # PDF 1.2 also supports Flatedecode (zip compression).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            bits = 8
 | 
					            bits = 8
 | 
				
			||||||
            params = None
 | 
					            params = None
 | 
				
			||||||
| 
						 | 
					@ -135,7 +136,12 @@ def _save(im, fp, filename, save_all=False):
 | 
				
			||||||
            elif im.mode == "P":
 | 
					            elif im.mode == "P":
 | 
				
			||||||
                filter = "ASCIIHexDecode"
 | 
					                filter = "ASCIIHexDecode"
 | 
				
			||||||
                palette = im.im.getpalette("RGB")
 | 
					                palette = im.im.getpalette("RGB")
 | 
				
			||||||
                colorspace = [PdfParser.PdfName("Indexed"), PdfParser.PdfName("DeviceRGB"), 255, PdfParser.PdfBinary(palette)]
 | 
					                colorspace = [
 | 
				
			||||||
 | 
					                    PdfParser.PdfName("Indexed"),
 | 
				
			||||||
 | 
					                    PdfParser.PdfName("DeviceRGB"),
 | 
				
			||||||
 | 
					                    255,
 | 
				
			||||||
 | 
					                    PdfParser.PdfBinary(palette)
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
                procset = "ImageI"  # indexed color
 | 
					                procset = "ImageI"  # indexed color
 | 
				
			||||||
            elif im.mode == "RGB":
 | 
					            elif im.mode == "RGB":
 | 
				
			||||||
                filter = "DCTDecode"
 | 
					                filter = "DCTDecode"
 | 
				
			||||||
| 
						 | 
					@ -166,7 +172,8 @@ def _save(im, fp, filename, save_all=False):
 | 
				
			||||||
            elif filter == "FlateDecode":
 | 
					            elif filter == "FlateDecode":
 | 
				
			||||||
                ImageFile._save(im, op, [("zip", (0, 0)+im.size, 0, im.mode)])
 | 
					                ImageFile._save(im, op, [("zip", (0, 0)+im.size, 0, im.mode)])
 | 
				
			||||||
            elif filter == "RunLengthDecode":
 | 
					            elif filter == "RunLengthDecode":
 | 
				
			||||||
                ImageFile._save(im, op, [("packbits", (0, 0)+im.size, 0, im.mode)])
 | 
					                ImageFile._save(im, op,
 | 
				
			||||||
 | 
					                                [("packbits", (0, 0)+im.size, 0, im.mode)])
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                raise ValueError("unsupported PDF filter (%s)" % filter)
 | 
					                raise ValueError("unsupported PDF filter (%s)" % filter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -175,26 +182,37 @@ def _save(im, fp, filename, save_all=False):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            width, height = im.size
 | 
					            width, height = im.size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            existing_pdf.write_obj(image_refs[pageNumber], stream=op.getvalue(),
 | 
					            existing_pdf.write_obj(image_refs[pageNumber],
 | 
				
			||||||
                Type=PdfParser.PdfName("XObject"),
 | 
					                                   stream=op.getvalue(),
 | 
				
			||||||
                Subtype=PdfParser.PdfName("Image"),
 | 
					                                   Type=PdfParser.PdfName("XObject"),
 | 
				
			||||||
                Width=width,  # * 72.0 / resolution,
 | 
					                                   Subtype=PdfParser.PdfName("Image"),
 | 
				
			||||||
                Height=height,  # * 72.0 / resolution,
 | 
					                                   Width=width,  # * 72.0 / resolution,
 | 
				
			||||||
                Filter=PdfParser.PdfName(filter),
 | 
					                                   Height=height,  # * 72.0 / resolution,
 | 
				
			||||||
                BitsPerComponent=bits,
 | 
					                                   Filter=PdfParser.PdfName(filter),
 | 
				
			||||||
                DecodeParams=params,
 | 
					                                   BitsPerComponent=bits,
 | 
				
			||||||
                ColorSpace=colorspace)
 | 
					                                   DecodeParams=params,
 | 
				
			||||||
 | 
					                                   ColorSpace=colorspace)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            #
 | 
					            #
 | 
				
			||||||
            # page
 | 
					            # page
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            existing_pdf.write_page(page_refs[pageNumber],
 | 
					            existing_pdf.write_page(page_refs[pageNumber],
 | 
				
			||||||
                Resources=PdfParser.PdfDict(
 | 
					                                    Resources=PdfParser.PdfDict(
 | 
				
			||||||
                    ProcSet=[PdfParser.PdfName("PDF"), PdfParser.PdfName(procset)],
 | 
					                                        ProcSet=[
 | 
				
			||||||
                    XObject=PdfParser.PdfDict(image=image_refs[pageNumber])),
 | 
					                                            PdfParser.PdfName("PDF"),
 | 
				
			||||||
                MediaBox=[0, 0, int(width * 72.0 / resolution), int(height * 72.0 / resolution)],
 | 
					                                            PdfParser.PdfName(procset)
 | 
				
			||||||
                Contents=contents_refs[pageNumber]
 | 
					                                        ],
 | 
				
			||||||
                )
 | 
					                                        XObject=PdfParser.PdfDict(
 | 
				
			||||||
 | 
					                                            image=image_refs[pageNumber]
 | 
				
			||||||
 | 
					                                        )
 | 
				
			||||||
 | 
					                                    ),
 | 
				
			||||||
 | 
					                                    MediaBox=[
 | 
				
			||||||
 | 
					                                        0,
 | 
				
			||||||
 | 
					                                        0,
 | 
				
			||||||
 | 
					                                        int(width * 72.0 / resolution),
 | 
				
			||||||
 | 
					                                        int(height * 72.0 / resolution)
 | 
				
			||||||
 | 
					                                    ],
 | 
				
			||||||
 | 
					                                    Contents=contents_refs[pageNumber])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            #
 | 
					            #
 | 
				
			||||||
            # page contents
 | 
					            # page contents
 | 
				
			||||||
| 
						 | 
					@ -204,7 +222,8 @@ def _save(im, fp, filename, save_all=False):
 | 
				
			||||||
                    int(width * 72.0 / resolution),
 | 
					                    int(width * 72.0 / resolution),
 | 
				
			||||||
                    int(height * 72.0 / resolution)))
 | 
					                    int(height * 72.0 / resolution)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            existing_pdf.write_obj(contents_refs[pageNumber], stream=page_contents)
 | 
					            existing_pdf.write_obj(contents_refs[pageNumber],
 | 
				
			||||||
 | 
					                                   stream=page_contents)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            pageNumber += 1
 | 
					            pageNumber += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,8 @@ else:  # Python 2.x
 | 
				
			||||||
        return s        # pragma: no cover
 | 
					        return s        # pragma: no cover
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# see 7.9.2.2 Text String Type on page 86 and D.3 PDFDocEncoding Character Set on page 656
 | 
					# see 7.9.2.2 Text String Type on page 86 and D.3 PDFDocEncoding Character Set
 | 
				
			||||||
 | 
					# on page 656
 | 
				
			||||||
def encode_text(s):
 | 
					def encode_text(s):
 | 
				
			||||||
    return codecs.BOM_UTF16_BE + s.encode("utf_16_be")
 | 
					    return codecs.BOM_UTF16_BE + s.encode("utf_16_be")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -80,7 +81,8 @@ def decode_text(b):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PdfFormatError(RuntimeError):
 | 
					class PdfFormatError(RuntimeError):
 | 
				
			||||||
    """An error that probably indicates a syntactic or semantic error in the PDF file structure"""
 | 
					    """An error that probably indicates a syntactic or semantic error in the
 | 
				
			||||||
 | 
					    PDF file structure"""
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,7 +91,8 @@ def check_format_condition(condition, error_message):
 | 
				
			||||||
        raise PdfFormatError(error_message)
 | 
					        raise PdfFormatError(error_message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class IndirectReference(collections.namedtuple("IndirectReferenceTuple", ["object_id", "generation"])):
 | 
					class IndirectReference(collections.namedtuple("IndirectReferenceTuple",
 | 
				
			||||||
 | 
					                        ["object_id", "generation"])):
 | 
				
			||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
        return "%s %s R" % self
 | 
					        return "%s %s R" % self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,7 +100,9 @@ class IndirectReference(collections.namedtuple("IndirectReferenceTuple", ["objec
 | 
				
			||||||
        return self.__str__().encode("us-ascii")
 | 
					        return self.__str__().encode("us-ascii")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __eq__(self, other):
 | 
					    def __eq__(self, other):
 | 
				
			||||||
        return other.__class__ is self.__class__ and other.object_id == self.object_id and other.generation == self.generation
 | 
					        return other.__class__ is self.__class__ and \
 | 
				
			||||||
 | 
					               other.object_id == self.object_id and \
 | 
				
			||||||
 | 
					               other.generation == self.generation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __ne__(self, other):
 | 
					    def __ne__(self, other):
 | 
				
			||||||
        return not (self == other)
 | 
					        return not (self == other)
 | 
				
			||||||
| 
						 | 
					@ -143,19 +148,26 @@ class XrefTable:
 | 
				
			||||||
        elif key in self.deleted_entries:
 | 
					        elif key in self.deleted_entries:
 | 
				
			||||||
            generation = self.deleted_entries[key]
 | 
					            generation = self.deleted_entries[key]
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            raise IndexError("object ID " + str(key) + " cannot be deleted because it doesn't exist")
 | 
					            raise IndexError("object ID " + str(key) +
 | 
				
			||||||
 | 
					                             " cannot be deleted because it doesn't exist")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __contains__(self, key):
 | 
					    def __contains__(self, key):
 | 
				
			||||||
        return key in self.existing_entries or key in self.new_entries
 | 
					        return key in self.existing_entries or key in self.new_entries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __len__(self):
 | 
					    def __len__(self):
 | 
				
			||||||
        return len(set(self.existing_entries.keys()) | set(self.new_entries.keys()) | set(self.deleted_entries.keys()))
 | 
					        return len(set(self.existing_entries.keys()) |
 | 
				
			||||||
 | 
					                   set(self.new_entries.keys()) |
 | 
				
			||||||
 | 
					                   set(self.deleted_entries.keys()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def keys(self):
 | 
					    def keys(self):
 | 
				
			||||||
        return (set(self.existing_entries.keys()) - set(self.deleted_entries.keys())) | set(self.new_entries.keys())
 | 
					        return (
 | 
				
			||||||
 | 
					            set(self.existing_entries.keys()) -
 | 
				
			||||||
 | 
					            set(self.deleted_entries.keys())
 | 
				
			||||||
 | 
					        ) | set(self.new_entries.keys())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def write(self, f):
 | 
					    def write(self, f):
 | 
				
			||||||
        keys = sorted(set(self.new_entries.keys()) | set(self.deleted_entries.keys()))
 | 
					        keys = sorted(set(self.new_entries.keys()) |
 | 
				
			||||||
 | 
					                      set(self.deleted_entries.keys()))
 | 
				
			||||||
        deleted_keys = sorted(set(self.deleted_entries.keys()))
 | 
					        deleted_keys = sorted(set(self.deleted_entries.keys()))
 | 
				
			||||||
        startxref = f.tell()
 | 
					        startxref = f.tell()
 | 
				
			||||||
        f.write(b"xref\n")
 | 
					        f.write(b"xref\n")
 | 
				
			||||||
| 
						 | 
					@ -172,10 +184,12 @@ class XrefTable:
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                contiguous_keys = keys
 | 
					                contiguous_keys = keys
 | 
				
			||||||
                keys = None
 | 
					                keys = None
 | 
				
			||||||
            f.write(make_bytes("%d %d\n" % (contiguous_keys[0], len(contiguous_keys))))
 | 
					            f.write(make_bytes("%d %d\n" %
 | 
				
			||||||
 | 
					                               (contiguous_keys[0], len(contiguous_keys))))
 | 
				
			||||||
            for object_id in contiguous_keys:
 | 
					            for object_id in contiguous_keys:
 | 
				
			||||||
                if object_id in self.new_entries:
 | 
					                if object_id in self.new_entries:
 | 
				
			||||||
                    f.write(make_bytes("%010d %05d n \n" % self.new_entries[object_id]))
 | 
					                    f.write(make_bytes("%010d %05d n \n" %
 | 
				
			||||||
 | 
					                                       self.new_entries[object_id]))
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    this_deleted_object_id = deleted_keys.pop(0)
 | 
					                    this_deleted_object_id = deleted_keys.pop(0)
 | 
				
			||||||
                    check_format_condition(object_id == this_deleted_object_id,
 | 
					                    check_format_condition(object_id == this_deleted_object_id,
 | 
				
			||||||
| 
						 | 
					@ -186,7 +200,9 @@ class XrefTable:
 | 
				
			||||||
                        next_in_linked_list = deleted_keys[0]
 | 
					                        next_in_linked_list = deleted_keys[0]
 | 
				
			||||||
                    except IndexError:
 | 
					                    except IndexError:
 | 
				
			||||||
                        next_in_linked_list = 0
 | 
					                        next_in_linked_list = 0
 | 
				
			||||||
                    f.write(make_bytes("%010d %05d f \n" % (next_in_linked_list, self.deleted_entries[object_id])))
 | 
					                    f.write(make_bytes("%010d %05d f \n" %
 | 
				
			||||||
 | 
					                                       (next_in_linked_list,
 | 
				
			||||||
 | 
					                                        self.deleted_entries[object_id])))
 | 
				
			||||||
        return startxref
 | 
					        return startxref
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,7 +219,8 @@ class PdfName:
 | 
				
			||||||
        return self.name.decode("us-ascii")
 | 
					        return self.name.decode("us-ascii")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __eq__(self, other):
 | 
					    def __eq__(self, other):
 | 
				
			||||||
        return (isinstance(other, PdfName) and other.name == self.name) or other == self.name
 | 
					        return (isinstance(other, PdfName) and other.name == self.name) or \
 | 
				
			||||||
 | 
					               other == self.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __hash__(self):
 | 
					    def __hash__(self):
 | 
				
			||||||
        return hash(self.name)
 | 
					        return hash(self.name)
 | 
				
			||||||
| 
						 | 
					@ -313,7 +330,9 @@ class PdfStream:
 | 
				
			||||||
                expected_length = self.dictionary.Length
 | 
					                expected_length = self.dictionary.Length
 | 
				
			||||||
            return zlib.decompress(self.buf, bufsize=int(expected_length))
 | 
					            return zlib.decompress(self.buf, bufsize=int(expected_length))
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            raise NotImplementedError("stream filter %s unknown/unsupported" % repr(self.dictionary.Filter))
 | 
					            raise NotImplementedError(
 | 
				
			||||||
 | 
					                "stream filter %s unknown/unsupported" %
 | 
				
			||||||
 | 
					                repr(self.dictionary.Filter))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def pdf_repr(x):
 | 
					def pdf_repr(x):
 | 
				
			||||||
| 
						 | 
					@ -323,7 +342,8 @@ def pdf_repr(x):
 | 
				
			||||||
        return b"false"
 | 
					        return b"false"
 | 
				
			||||||
    elif x is None:
 | 
					    elif x is None:
 | 
				
			||||||
        return b"null"
 | 
					        return b"null"
 | 
				
			||||||
    elif isinstance(x, PdfName) or isinstance(x, PdfDict) or isinstance(x, PdfArray) or isinstance(x, PdfBinary):
 | 
					    elif (isinstance(x, PdfName) or isinstance(x, PdfDict) or
 | 
				
			||||||
 | 
					          isinstance(x, PdfArray) or isinstance(x, PdfBinary)):
 | 
				
			||||||
        return bytes(x)
 | 
					        return bytes(x)
 | 
				
			||||||
    elif isinstance(x, int):
 | 
					    elif isinstance(x, int):
 | 
				
			||||||
        return str(x).encode("us-ascii")
 | 
					        return str(x).encode("us-ascii")
 | 
				
			||||||
| 
						 | 
					@ -331,10 +351,15 @@ def pdf_repr(x):
 | 
				
			||||||
        return bytes(PdfDict(x))
 | 
					        return bytes(PdfDict(x))
 | 
				
			||||||
    elif isinstance(x, list):
 | 
					    elif isinstance(x, list):
 | 
				
			||||||
        return bytes(PdfArray(x))
 | 
					        return bytes(PdfArray(x))
 | 
				
			||||||
    elif (py3 and isinstance(x, str)) or (not py3 and isinstance(x, unicode)):
 | 
					    elif ((py3 and isinstance(x, str)) or
 | 
				
			||||||
 | 
					          (not py3 and isinstance(x, unicode))):
 | 
				
			||||||
        return pdf_repr(encode_text(x))
 | 
					        return pdf_repr(encode_text(x))
 | 
				
			||||||
    elif isinstance(x, bytes):
 | 
					    elif isinstance(x, bytes):
 | 
				
			||||||
        return b"(" + x.replace(b"\\", b"\\\\").replace(b"(", b"\\(").replace(b")", b"\\)") + b")"  # XXX escape more chars? handle binary garbage
 | 
					        # XXX escape more chars? handle binary garbage
 | 
				
			||||||
 | 
					        x = x.replace(b"\\", b"\\\\")
 | 
				
			||||||
 | 
					        x = x.replace(b"(", b"\\(")
 | 
				
			||||||
 | 
					        x = x.replace(b")", b"\\)")
 | 
				
			||||||
 | 
					        return b"(" + x + b")"
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        return bytes(x)
 | 
					        return bytes(x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -344,10 +369,13 @@ class PdfParser:
 | 
				
			||||||
    Supports PDF up to 1.4
 | 
					    Supports PDF up to 1.4
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, filename=None, f=None, buf=None, start_offset=0, mode="rb"):
 | 
					    def __init__(self, filename=None, f=None,
 | 
				
			||||||
        # type: (PdfParser, str, file, Union[bytes, bytearray], int, str) -> None
 | 
					                 buf=None, start_offset=0, mode="rb"):
 | 
				
			||||||
 | 
					        # type: (PdfParser, str, file, Union[bytes, bytearray], int, str)
 | 
				
			||||||
 | 
					        #       -> None
 | 
				
			||||||
        if buf and f:
 | 
					        if buf and f:
 | 
				
			||||||
            raise RuntimeError("specify buf or f or filename, but not both buf and f")
 | 
					            raise RuntimeError(
 | 
				
			||||||
 | 
					                "specify buf or f or filename, but not both buf and f")
 | 
				
			||||||
        self.filename = filename
 | 
					        self.filename = filename
 | 
				
			||||||
        self.buf = buf
 | 
					        self.buf = buf
 | 
				
			||||||
        self.f = f
 | 
					        self.f = f
 | 
				
			||||||
| 
						 | 
					@ -473,7 +501,8 @@ class PdfParser:
 | 
				
			||||||
        if self.info:
 | 
					        if self.info:
 | 
				
			||||||
            trailer_dict[b"Info"] = self.info_ref
 | 
					            trailer_dict[b"Info"] = self.info_ref
 | 
				
			||||||
        self.last_xref_section_offset = start_xref
 | 
					        self.last_xref_section_offset = start_xref
 | 
				
			||||||
        self.f.write(b"trailer\n" + bytes(PdfDict(trailer_dict)) + make_bytes("\nstartxref\n%d\n%%%%EOF" % start_xref))
 | 
					        self.f.write(b"trailer\n" + bytes(PdfDict(trailer_dict)) +
 | 
				
			||||||
 | 
					                     make_bytes("\nstartxref\n%d\n%%%%EOF" % start_xref))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def write_page(self, ref, *objs, **dict_obj):
 | 
					    def write_page(self, ref, *objs, **dict_obj):
 | 
				
			||||||
        if isinstance(ref, int):
 | 
					        if isinstance(ref, int):
 | 
				
			||||||
| 
						 | 
					@ -535,13 +564,18 @@ class PdfParser:
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            self.info = PdfDict(self.read_indirect(self.info_ref))
 | 
					            self.info = PdfDict(self.read_indirect(self.info_ref))
 | 
				
			||||||
        check_format_condition(b"Type" in self.root, "/Type missing in Root")
 | 
					        check_format_condition(b"Type" in self.root, "/Type missing in Root")
 | 
				
			||||||
        check_format_condition(self.root[b"Type"] == b"Catalog", "/Type in Root is not /Catalog")
 | 
					        check_format_condition(self.root[b"Type"] == b"Catalog",
 | 
				
			||||||
 | 
					                               "/Type in Root is not /Catalog")
 | 
				
			||||||
        check_format_condition(b"Pages" in self.root, "/Pages missing in Root")
 | 
					        check_format_condition(b"Pages" in self.root, "/Pages missing in Root")
 | 
				
			||||||
        check_format_condition(isinstance(self.root[b"Pages"], IndirectReference), "/Pages in Root is not an indirect reference")
 | 
					        check_format_condition(isinstance(self.root[b"Pages"],
 | 
				
			||||||
 | 
					                               IndirectReference),
 | 
				
			||||||
 | 
					                               "/Pages in Root is not an indirect reference")
 | 
				
			||||||
        self.pages_ref = self.root[b"Pages"]
 | 
					        self.pages_ref = self.root[b"Pages"]
 | 
				
			||||||
        self.page_tree_root = self.read_indirect(self.pages_ref)
 | 
					        self.page_tree_root = self.read_indirect(self.pages_ref)
 | 
				
			||||||
        self.pages = self.linearize_page_tree(self.page_tree_root)
 | 
					        self.pages = self.linearize_page_tree(self.page_tree_root)
 | 
				
			||||||
        # save the original list of page references in case the user modifies, adds or deletes some pages and we need to rewrite the pages and their list
 | 
					        # save the original list of page references
 | 
				
			||||||
 | 
					        # in case the user modifies, adds or deletes some pages
 | 
				
			||||||
 | 
					        # and we need to rewrite the pages and their list
 | 
				
			||||||
        self.orig_pages = self.pages[:]
 | 
					        self.orig_pages = self.pages[:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def next_object_id(self, offset=None):
 | 
					    def next_object_id(self, offset=None):
 | 
				
			||||||
| 
						 | 
					@ -562,10 +596,14 @@ class PdfParser:
 | 
				
			||||||
    whitespace_mandatory = whitespace + b"+"
 | 
					    whitespace_mandatory = whitespace + b"+"
 | 
				
			||||||
    newline_only = br"[\r\n]+"
 | 
					    newline_only = br"[\r\n]+"
 | 
				
			||||||
    newline = whitespace_optional + newline_only + whitespace_optional
 | 
					    newline = whitespace_optional + newline_only + whitespace_optional
 | 
				
			||||||
    re_trailer_end = re.compile(whitespace_mandatory + br"trailer" + whitespace_optional + br"\<\<(.*\>\>)" + newline
 | 
					    re_trailer_end = re.compile(
 | 
				
			||||||
        + br"startxref" + newline + br"([0-9]+)" + newline + br"%%EOF" + whitespace_optional + br"$", re.DOTALL)
 | 
					        whitespace_mandatory + br"trailer" + whitespace_optional +
 | 
				
			||||||
    re_trailer_prev = re.compile(whitespace_optional + br"trailer" + whitespace_optional + br"\<\<(.*?\>\>)" + newline
 | 
					        br"\<\<(.*\>\>)" + newline + br"startxref" + newline + br"([0-9]+)" +
 | 
				
			||||||
        + br"startxref" + newline + br"([0-9]+)" + newline + br"%%EOF" + whitespace_optional, re.DOTALL)
 | 
					        newline + br"%%EOF" + whitespace_optional + br"$", re.DOTALL)
 | 
				
			||||||
 | 
					    re_trailer_prev = re.compile(
 | 
				
			||||||
 | 
					        whitespace_optional + br"trailer" + whitespace_optional +
 | 
				
			||||||
 | 
					        br"\<\<(.*?\>\>)" + newline + br"startxref" + newline + br"([0-9]+)" +
 | 
				
			||||||
 | 
					        newline + br"%%EOF" + whitespace_optional, re.DOTALL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def read_trailer(self):
 | 
					    def read_trailer(self):
 | 
				
			||||||
        search_start_offset = len(self.buf) - 16384
 | 
					        search_start_offset = len(self.buf) - 16384
 | 
				
			||||||
| 
						 | 
					@ -589,19 +627,26 @@ class PdfParser:
 | 
				
			||||||
            self.read_prev_trailer(self.trailer_dict[b"Prev"])
 | 
					            self.read_prev_trailer(self.trailer_dict[b"Prev"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def read_prev_trailer(self, xref_section_offset):
 | 
					    def read_prev_trailer(self, xref_section_offset):
 | 
				
			||||||
        trailer_offset = self.read_xref_table(xref_section_offset=xref_section_offset)
 | 
					        trailer_offset = self.read_xref_table(
 | 
				
			||||||
        m = self.re_trailer_prev.search(self.buf[trailer_offset:trailer_offset+16384])
 | 
					            xref_section_offset=xref_section_offset)
 | 
				
			||||||
 | 
					        m = self.re_trailer_prev.search(
 | 
				
			||||||
 | 
					            self.buf[trailer_offset:trailer_offset+16384])
 | 
				
			||||||
        check_format_condition(m, "previous trailer not found")
 | 
					        check_format_condition(m, "previous trailer not found")
 | 
				
			||||||
        trailer_data = m.group(1)
 | 
					        trailer_data = m.group(1)
 | 
				
			||||||
        check_format_condition(int(m.group(2)) == xref_section_offset, "xref section offset in previous trailer doesn't match what was expected")
 | 
					        check_format_condition(int(m.group(2)) == xref_section_offset,
 | 
				
			||||||
 | 
					                               "xref section offset in previous trailer "
 | 
				
			||||||
 | 
					                               "doesn't match what was expected")
 | 
				
			||||||
        trailer_dict = self.interpret_trailer(trailer_data)
 | 
					        trailer_dict = self.interpret_trailer(trailer_data)
 | 
				
			||||||
        if b"Prev" in trailer_dict:
 | 
					        if b"Prev" in trailer_dict:
 | 
				
			||||||
            self.read_prev_trailer(trailer_dict[b"Prev"])
 | 
					            self.read_prev_trailer(trailer_dict[b"Prev"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    re_whitespace_optional = re.compile(whitespace_optional)
 | 
					    re_whitespace_optional = re.compile(whitespace_optional)
 | 
				
			||||||
    re_name = re.compile(whitespace_optional + br"/([!-$&'*-.0-;=?-Z\\^-z|~]+)(?=" + delimiter_or_ws + br")")
 | 
					    re_name = re.compile(
 | 
				
			||||||
 | 
					        whitespace_optional + br"/([!-$&'*-.0-;=?-Z\\^-z|~]+)(?=" +
 | 
				
			||||||
 | 
					        delimiter_or_ws + br")")
 | 
				
			||||||
    re_dict_start = re.compile(whitespace_optional + br"\<\<")
 | 
					    re_dict_start = re.compile(whitespace_optional + br"\<\<")
 | 
				
			||||||
    re_dict_end = re.compile(whitespace_optional + br"\>\>" + whitespace_optional)
 | 
					    re_dict_end = re.compile(
 | 
				
			||||||
 | 
					        whitespace_optional + br"\>\>" + whitespace_optional)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def interpret_trailer(cls, trailer_data):
 | 
					    def interpret_trailer(cls, trailer_data):
 | 
				
			||||||
| 
						 | 
					@ -611,13 +656,21 @@ class PdfParser:
 | 
				
			||||||
            m = cls.re_name.match(trailer_data, offset)
 | 
					            m = cls.re_name.match(trailer_data, offset)
 | 
				
			||||||
            if not m:
 | 
					            if not m:
 | 
				
			||||||
                m = cls.re_dict_end.match(trailer_data, offset)
 | 
					                m = cls.re_dict_end.match(trailer_data, offset)
 | 
				
			||||||
                check_format_condition(m and m.end() == len(trailer_data), "name not found in trailer, remaining data: " + repr(trailer_data[offset:]))
 | 
					                check_format_condition(
 | 
				
			||||||
 | 
					                    m and m.end() == len(trailer_data),
 | 
				
			||||||
 | 
					                    "name not found in trailer, remaining data: " +
 | 
				
			||||||
 | 
					                    repr(trailer_data[offset:]))
 | 
				
			||||||
                break
 | 
					                break
 | 
				
			||||||
            key = cls.interpret_name(m.group(1))
 | 
					            key = cls.interpret_name(m.group(1))
 | 
				
			||||||
            value, offset = cls.get_value(trailer_data, m.end())
 | 
					            value, offset = cls.get_value(trailer_data, m.end())
 | 
				
			||||||
            trailer[key] = value
 | 
					            trailer[key] = value
 | 
				
			||||||
        check_format_condition(b"Size" in trailer and isinstance(trailer[b"Size"], int), "/Size not in trailer or not an integer")
 | 
					        check_format_condition(
 | 
				
			||||||
        check_format_condition(b"Root" in trailer and isinstance(trailer[b"Root"], IndirectReference), "/Root not in trailer or not an indirect reference")
 | 
					            b"Size" in trailer and isinstance(trailer[b"Size"], int),
 | 
				
			||||||
 | 
					            "/Size not in trailer or not an integer")
 | 
				
			||||||
 | 
					        check_format_condition(
 | 
				
			||||||
 | 
					            b"Root" in trailer and
 | 
				
			||||||
 | 
					            isinstance(trailer[b"Root"], IndirectReference),
 | 
				
			||||||
 | 
					            "/Root not in trailer or not an indirect reference")
 | 
				
			||||||
        return trailer
 | 
					        return trailer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    re_hashes_in_name = re.compile(br"([^#]*)(#([0-9a-fA-F]{2}))?")
 | 
					    re_hashes_in_name = re.compile(br"([^#]*)(#([0-9a-fA-F]{2}))?")
 | 
				
			||||||
| 
						 | 
					@ -627,7 +680,8 @@ class PdfParser:
 | 
				
			||||||
        name = b""
 | 
					        name = b""
 | 
				
			||||||
        for m in cls.re_hashes_in_name.finditer(raw):
 | 
					        for m in cls.re_hashes_in_name.finditer(raw):
 | 
				
			||||||
            if m.group(3):
 | 
					            if m.group(3):
 | 
				
			||||||
                name += m.group(1) + bytearray.fromhex(m.group(3).decode("us-ascii"))
 | 
					                name += m.group(1) + \
 | 
				
			||||||
 | 
					                    bytearray.fromhex(m.group(3).decode("us-ascii"))
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                name += m.group(1)
 | 
					                name += m.group(1)
 | 
				
			||||||
        if as_text:
 | 
					        if as_text:
 | 
				
			||||||
| 
						 | 
					@ -635,21 +689,37 @@ class PdfParser:
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return bytes(name)
 | 
					            return bytes(name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    re_null = re.compile(whitespace_optional + br"null(?=" + delimiter_or_ws + br")")
 | 
					    re_null = re.compile(
 | 
				
			||||||
    re_true = re.compile(whitespace_optional + br"true(?=" + delimiter_or_ws + br")")
 | 
					        whitespace_optional + br"null(?=" + delimiter_or_ws + br")")
 | 
				
			||||||
    re_false = re.compile(whitespace_optional + br"false(?=" + delimiter_or_ws + br")")
 | 
					    re_true = re.compile(
 | 
				
			||||||
    re_int = re.compile(whitespace_optional + br"([-+]?[0-9]+)(?=" + delimiter_or_ws + br")")
 | 
					        whitespace_optional + br"true(?=" + delimiter_or_ws + br")")
 | 
				
			||||||
    re_real = re.compile(whitespace_optional + br"([-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+))(?=" + delimiter_or_ws + br")")
 | 
					    re_false = re.compile(
 | 
				
			||||||
 | 
					        whitespace_optional + br"false(?=" + delimiter_or_ws + br")")
 | 
				
			||||||
 | 
					    re_int = re.compile(
 | 
				
			||||||
 | 
					        whitespace_optional + br"([-+]?[0-9]+)(?=" + delimiter_or_ws + br")")
 | 
				
			||||||
 | 
					    re_real = re.compile(
 | 
				
			||||||
 | 
					        whitespace_optional + br"([-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+))(?=" +
 | 
				
			||||||
 | 
					        delimiter_or_ws + br")")
 | 
				
			||||||
    re_array_start = re.compile(whitespace_optional + br"\[")
 | 
					    re_array_start = re.compile(whitespace_optional + br"\[")
 | 
				
			||||||
    re_array_end = re.compile(whitespace_optional + br"]")
 | 
					    re_array_end = re.compile(whitespace_optional + br"]")
 | 
				
			||||||
    re_string_hex = re.compile(whitespace_optional + br"\<(" + whitespace_or_hex + br"*)\>")
 | 
					    re_string_hex = re.compile(
 | 
				
			||||||
 | 
					        whitespace_optional + br"\<(" + whitespace_or_hex + br"*)\>")
 | 
				
			||||||
    re_string_lit = re.compile(whitespace_optional + br"\(")
 | 
					    re_string_lit = re.compile(whitespace_optional + br"\(")
 | 
				
			||||||
    re_indirect_reference = re.compile(whitespace_optional + br"([-+]?[0-9]+)" + whitespace_mandatory + br"([-+]?[0-9]+)" + whitespace_mandatory + br"R(?=" + delimiter_or_ws + br")")
 | 
					    re_indirect_reference = re.compile(
 | 
				
			||||||
    re_indirect_def_start = re.compile(whitespace_optional + br"([-+]?[0-9]+)" + whitespace_mandatory + br"([-+]?[0-9]+)" + whitespace_mandatory + br"obj(?=" + delimiter_or_ws + br")")
 | 
					        whitespace_optional + br"([-+]?[0-9]+)" + whitespace_mandatory +
 | 
				
			||||||
    re_indirect_def_end = re.compile(whitespace_optional + br"endobj(?=" + delimiter_or_ws + br")")
 | 
					        br"([-+]?[0-9]+)" + whitespace_mandatory + br"R(?=" + delimiter_or_ws +
 | 
				
			||||||
    re_comment = re.compile(br"(" + whitespace_optional + br"%[^\r\n]*" + newline + br")*")
 | 
					        br")")
 | 
				
			||||||
 | 
					    re_indirect_def_start = re.compile(
 | 
				
			||||||
 | 
					        whitespace_optional + br"([-+]?[0-9]+)" + whitespace_mandatory +
 | 
				
			||||||
 | 
					        br"([-+]?[0-9]+)" + whitespace_mandatory + br"obj(?=" +
 | 
				
			||||||
 | 
					        delimiter_or_ws + br")")
 | 
				
			||||||
 | 
					    re_indirect_def_end = re.compile(
 | 
				
			||||||
 | 
					        whitespace_optional + br"endobj(?=" + delimiter_or_ws + br")")
 | 
				
			||||||
 | 
					    re_comment = re.compile(
 | 
				
			||||||
 | 
					        br"(" + whitespace_optional + br"%[^\r\n]*" + newline + br")*")
 | 
				
			||||||
    re_stream_start = re.compile(whitespace_optional + br"stream\r?\n")
 | 
					    re_stream_start = re.compile(whitespace_optional + br"stream\r?\n")
 | 
				
			||||||
    re_stream_end = re.compile(whitespace_optional + br"endstream(?=" + delimiter_or_ws + br")")
 | 
					    re_stream_end = re.compile(
 | 
				
			||||||
 | 
					        whitespace_optional + br"endstream(?=" + delimiter_or_ws + br")")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def get_value(cls, data, offset, expect_indirect=None, max_nesting=-1):
 | 
					    def get_value(cls, data, offset, expect_indirect=None, max_nesting=-1):
 | 
				
			||||||
| 
						 | 
					@ -660,21 +730,34 @@ class PdfParser:
 | 
				
			||||||
            offset = m.end()
 | 
					            offset = m.end()
 | 
				
			||||||
        m = cls.re_indirect_def_start.match(data, offset)
 | 
					        m = cls.re_indirect_def_start.match(data, offset)
 | 
				
			||||||
        if m:
 | 
					        if m:
 | 
				
			||||||
            check_format_condition(int(m.group(1)) > 0, "indirect object definition: object ID must be greater than 0")
 | 
					            check_format_condition(
 | 
				
			||||||
            check_format_condition(int(m.group(2)) >= 0, "indirect object definition: generation must be non-negative")
 | 
					                int(m.group(1)) > 0,
 | 
				
			||||||
            check_format_condition(expect_indirect is None or expect_indirect == IndirectReference(int(m.group(1)), int(m.group(2))),
 | 
					                "indirect object definition: object ID must be greater than 0")
 | 
				
			||||||
 | 
					            check_format_condition(
 | 
				
			||||||
 | 
					                int(m.group(2)) >= 0,
 | 
				
			||||||
 | 
					                "indirect object definition: generation must be non-negative")
 | 
				
			||||||
 | 
					            check_format_condition(
 | 
				
			||||||
 | 
					                expect_indirect is None or expect_indirect ==
 | 
				
			||||||
 | 
					                IndirectReference(int(m.group(1)), int(m.group(2))),
 | 
				
			||||||
                "indirect object definition different than expected")
 | 
					                "indirect object definition different than expected")
 | 
				
			||||||
            object, offset = cls.get_value(data, m.end(), max_nesting=max_nesting-1)
 | 
					            object, offset = cls.get_value(
 | 
				
			||||||
 | 
					                data, m.end(), max_nesting=max_nesting-1)
 | 
				
			||||||
            if offset is None:
 | 
					            if offset is None:
 | 
				
			||||||
                return object, None
 | 
					                return object, None
 | 
				
			||||||
            m = cls.re_indirect_def_end.match(data, offset)
 | 
					            m = cls.re_indirect_def_end.match(data, offset)
 | 
				
			||||||
            check_format_condition(m, "indirect object definition end not found")
 | 
					            check_format_condition(
 | 
				
			||||||
 | 
					                m, "indirect object definition end not found")
 | 
				
			||||||
            return object, m.end()
 | 
					            return object, m.end()
 | 
				
			||||||
        check_format_condition(not expect_indirect, "indirect object definition not found")
 | 
					        check_format_condition(
 | 
				
			||||||
 | 
					            not expect_indirect, "indirect object definition not found")
 | 
				
			||||||
        m = cls.re_indirect_reference.match(data, offset)
 | 
					        m = cls.re_indirect_reference.match(data, offset)
 | 
				
			||||||
        if m:
 | 
					        if m:
 | 
				
			||||||
            check_format_condition(int(m.group(1)) > 0, "indirect object reference: object ID must be greater than 0")
 | 
					            check_format_condition(
 | 
				
			||||||
            check_format_condition(int(m.group(2)) >= 0, "indirect object reference: generation must be non-negative")
 | 
					                int(m.group(1)) > 0,
 | 
				
			||||||
 | 
					                "indirect object reference: object ID must be greater than 0")
 | 
				
			||||||
 | 
					            check_format_condition(
 | 
				
			||||||
 | 
					                int(m.group(2)) >= 0,
 | 
				
			||||||
 | 
					                "indirect object reference: generation must be non-negative")
 | 
				
			||||||
            return IndirectReference(int(m.group(1)), int(m.group(2))), m.end()
 | 
					            return IndirectReference(int(m.group(1)), int(m.group(2))), m.end()
 | 
				
			||||||
        m = cls.re_dict_start.match(data, offset)
 | 
					        m = cls.re_dict_start.match(data, offset)
 | 
				
			||||||
        if m:
 | 
					        if m:
 | 
				
			||||||
| 
						 | 
					@ -682,10 +765,12 @@ class PdfParser:
 | 
				
			||||||
            result = {}
 | 
					            result = {}
 | 
				
			||||||
            m = cls.re_dict_end.match(data, offset)
 | 
					            m = cls.re_dict_end.match(data, offset)
 | 
				
			||||||
            while not m:
 | 
					            while not m:
 | 
				
			||||||
                key, offset = cls.get_value(data, offset, max_nesting=max_nesting-1)
 | 
					                key, offset = cls.get_value(
 | 
				
			||||||
 | 
					                    data, offset, max_nesting=max_nesting-1)
 | 
				
			||||||
                if offset is None:
 | 
					                if offset is None:
 | 
				
			||||||
                    return result, None
 | 
					                    return result, None
 | 
				
			||||||
                value, offset = cls.get_value(data, offset, max_nesting=max_nesting-1)
 | 
					                value, offset = cls.get_value(
 | 
				
			||||||
 | 
					                    data, offset, max_nesting=max_nesting-1)
 | 
				
			||||||
                result[key] = value
 | 
					                result[key] = value
 | 
				
			||||||
                if offset is None:
 | 
					                if offset is None:
 | 
				
			||||||
                    return result, None
 | 
					                    return result, None
 | 
				
			||||||
| 
						 | 
					@ -696,7 +781,9 @@ class PdfParser:
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    stream_len = int(result[b"Length"])
 | 
					                    stream_len = int(result[b"Length"])
 | 
				
			||||||
                except (TypeError, KeyError, ValueError):
 | 
					                except (TypeError, KeyError, ValueError):
 | 
				
			||||||
                    raise PdfFormatError("bad or missing Length in stream dict (%r)" % result.get(b"Length", None))
 | 
					                    raise PdfFormatError(
 | 
				
			||||||
 | 
					                        "bad or missing Length in stream dict (%r)" %
 | 
				
			||||||
 | 
					                        result.get(b"Length", None))
 | 
				
			||||||
                stream_data = data[m.end():m.end() + stream_len]
 | 
					                stream_data = data[m.end():m.end() + stream_len]
 | 
				
			||||||
                m = cls.re_stream_end.match(data, m.end() + stream_len)
 | 
					                m = cls.re_stream_end.match(data, m.end() + stream_len)
 | 
				
			||||||
                check_format_condition(m, "stream end not found")
 | 
					                check_format_condition(m, "stream end not found")
 | 
				
			||||||
| 
						 | 
					@ -711,7 +798,8 @@ class PdfParser:
 | 
				
			||||||
            result = []
 | 
					            result = []
 | 
				
			||||||
            m = cls.re_array_end.match(data, offset)
 | 
					            m = cls.re_array_end.match(data, offset)
 | 
				
			||||||
            while not m:
 | 
					            while not m:
 | 
				
			||||||
                value, offset = cls.get_value(data, offset, max_nesting=max_nesting-1)
 | 
					                value, offset = cls.get_value(
 | 
				
			||||||
 | 
					                    data, offset, max_nesting=max_nesting-1)
 | 
				
			||||||
                result.append(value)
 | 
					                result.append(value)
 | 
				
			||||||
                if offset is None:
 | 
					                if offset is None:
 | 
				
			||||||
                    return result, None
 | 
					                    return result, None
 | 
				
			||||||
| 
						 | 
					@ -734,18 +822,25 @@ class PdfParser:
 | 
				
			||||||
            return int(m.group(1)), m.end()
 | 
					            return int(m.group(1)), m.end()
 | 
				
			||||||
        m = cls.re_real.match(data, offset)
 | 
					        m = cls.re_real.match(data, offset)
 | 
				
			||||||
        if m:
 | 
					        if m:
 | 
				
			||||||
            return float(m.group(1)), m.end()  # XXX Decimal instead of float???
 | 
					            # XXX Decimal instead of float???
 | 
				
			||||||
 | 
					            return float(m.group(1)), m.end()
 | 
				
			||||||
        m = cls.re_string_hex.match(data, offset)
 | 
					        m = cls.re_string_hex.match(data, offset)
 | 
				
			||||||
        if m:
 | 
					        if m:
 | 
				
			||||||
            hex_string = bytearray([b for b in m.group(1) if b in b"0123456789abcdefABCDEF"])  # filter out whitespace
 | 
					            # filter out whitespace
 | 
				
			||||||
 | 
					            hex_string = bytearray([
 | 
				
			||||||
 | 
					                b for b in m.group(1)
 | 
				
			||||||
 | 
					                if b in b"0123456789abcdefABCDEF"
 | 
				
			||||||
 | 
					            ])
 | 
				
			||||||
            if len(hex_string) % 2 == 1:
 | 
					            if len(hex_string) % 2 == 1:
 | 
				
			||||||
                hex_string.append(ord(b"0"))  # append a 0 if the length is not even - yes, at the end
 | 
					                # append a 0 if the length is not even - yes, at the end
 | 
				
			||||||
 | 
					                hex_string.append(ord(b"0"))
 | 
				
			||||||
            return bytearray.fromhex(hex_string.decode("us-ascii")), m.end()
 | 
					            return bytearray.fromhex(hex_string.decode("us-ascii")), m.end()
 | 
				
			||||||
        m = cls.re_string_lit.match(data, offset)
 | 
					        m = cls.re_string_lit.match(data, offset)
 | 
				
			||||||
        if m:
 | 
					        if m:
 | 
				
			||||||
            return cls.get_literal_string(data, m.end())
 | 
					            return cls.get_literal_string(data, m.end())
 | 
				
			||||||
        # return None, offset  # fallback (only for debugging)
 | 
					        # return None, offset  # fallback (only for debugging)
 | 
				
			||||||
        raise PdfFormatError("unrecognized object: " + repr(data[offset:offset+32]))
 | 
					        raise PdfFormatError(
 | 
				
			||||||
 | 
					            "unrecognized object: " + repr(data[offset:offset+32]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    re_lit_str_token = re.compile(br"(\\[nrtbf()\\])|(\\[0-9]{1,3})|(\\(\r\n|\r|\n))|(\r\n|\r|\n)|(\()|(\))")
 | 
					    re_lit_str_token = re.compile(br"(\\[nrtbf()\\])|(\\[0-9]{1,3})|(\\(\r\n|\r|\n))|(\r\n|\r|\n)|(\()|(\))")
 | 
				
			||||||
    escaped_chars = {
 | 
					    escaped_chars = {
 | 
				
			||||||
| 
						 | 
					@ -792,19 +887,24 @@ class PdfParser:
 | 
				
			||||||
            offset = m.end()
 | 
					            offset = m.end()
 | 
				
			||||||
        raise PdfFormatError("unfinished literal string")
 | 
					        raise PdfFormatError("unfinished literal string")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    re_xref_section_start = re.compile(whitespace_optional + br"xref" + newline)
 | 
					    re_xref_section_start = re.compile(
 | 
				
			||||||
    re_xref_subsection_start = re.compile(whitespace_optional + br"([0-9]+)" + whitespace_mandatory + br"([0-9]+)" + whitespace_optional + newline_only)
 | 
					        whitespace_optional + br"xref" + newline)
 | 
				
			||||||
 | 
					    re_xref_subsection_start = re.compile(
 | 
				
			||||||
 | 
					        whitespace_optional + br"([0-9]+)" + whitespace_mandatory +
 | 
				
			||||||
 | 
					        br"([0-9]+)" + whitespace_optional + newline_only)
 | 
				
			||||||
    re_xref_entry = re.compile(br"([0-9]{10}) ([0-9]{5}) ([fn])( \r| \n|\r\n)")
 | 
					    re_xref_entry = re.compile(br"([0-9]{10}) ([0-9]{5}) ([fn])( \r| \n|\r\n)")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def read_xref_table(self, xref_section_offset):
 | 
					    def read_xref_table(self, xref_section_offset):
 | 
				
			||||||
        subsection_found = False
 | 
					        subsection_found = False
 | 
				
			||||||
        m = self.re_xref_section_start.match(self.buf, xref_section_offset + self.start_offset)
 | 
					        m = self.re_xref_section_start.match(
 | 
				
			||||||
 | 
					            self.buf, xref_section_offset + self.start_offset)
 | 
				
			||||||
        check_format_condition(m, "xref section start not found")
 | 
					        check_format_condition(m, "xref section start not found")
 | 
				
			||||||
        offset = m.end()
 | 
					        offset = m.end()
 | 
				
			||||||
        while True:
 | 
					        while True:
 | 
				
			||||||
            m = self.re_xref_subsection_start.match(self.buf, offset)
 | 
					            m = self.re_xref_subsection_start.match(self.buf, offset)
 | 
				
			||||||
            if not m:
 | 
					            if not m:
 | 
				
			||||||
                check_format_condition(subsection_found, "xref subsection start not found")
 | 
					                check_format_condition(
 | 
				
			||||||
 | 
					                    subsection_found, "xref subsection start not found")
 | 
				
			||||||
                break
 | 
					                break
 | 
				
			||||||
            subsection_found = True
 | 
					            subsection_found = True
 | 
				
			||||||
            offset = m.end()
 | 
					            offset = m.end()
 | 
				
			||||||
| 
						 | 
					@ -818,22 +918,31 @@ class PdfParser:
 | 
				
			||||||
                generation = int(m.group(2))
 | 
					                generation = int(m.group(2))
 | 
				
			||||||
                if not is_free:
 | 
					                if not is_free:
 | 
				
			||||||
                    new_entry = (int(m.group(1)), generation)
 | 
					                    new_entry = (int(m.group(1)), generation)
 | 
				
			||||||
                    check_format_condition(i not in self.xref_table or self.xref_table[i] == new_entry, "xref entry duplicated (and not identical)")
 | 
					                    check_format_condition(
 | 
				
			||||||
 | 
					                        i not in self.xref_table or
 | 
				
			||||||
 | 
					                        self.xref_table[i] == new_entry,
 | 
				
			||||||
 | 
					                        "xref entry duplicated (and not identical)")
 | 
				
			||||||
                    self.xref_table[i] = new_entry
 | 
					                    self.xref_table[i] = new_entry
 | 
				
			||||||
        return offset
 | 
					        return offset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def read_indirect(self, ref, max_nesting=-1):
 | 
					    def read_indirect(self, ref, max_nesting=-1):
 | 
				
			||||||
        offset, generation = self.xref_table[ref[0]]
 | 
					        offset, generation = self.xref_table[ref[0]]
 | 
				
			||||||
        check_format_condition(generation == ref[1], "expected to find generation %s for object ID %s in xref table, instead found generation %s at offset %s"
 | 
					        check_format_condition(
 | 
				
			||||||
 | 
					            generation == ref[1],
 | 
				
			||||||
 | 
					            "expected to find generation %s for object ID %s in xref table, "
 | 
				
			||||||
 | 
					            "instead found generation %s at offset %s"
 | 
				
			||||||
            % (ref[1], ref[0], generation, offset))
 | 
					            % (ref[1], ref[0], generation, offset))
 | 
				
			||||||
        value = self.get_value(self.buf, offset + self.start_offset, expect_indirect=IndirectReference(*ref), max_nesting=max_nesting)[0]
 | 
					        value = self.get_value(self.buf, offset + self.start_offset,
 | 
				
			||||||
 | 
					                               expect_indirect=IndirectReference(*ref),
 | 
				
			||||||
 | 
					                               max_nesting=max_nesting)[0]
 | 
				
			||||||
        self.cached_objects[ref] = value
 | 
					        self.cached_objects[ref] = value
 | 
				
			||||||
        return value
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def linearize_page_tree(self, node=None):
 | 
					    def linearize_page_tree(self, node=None):
 | 
				
			||||||
        if node is None:
 | 
					        if node is None:
 | 
				
			||||||
            node = self.page_tree_root
 | 
					            node = self.page_tree_root
 | 
				
			||||||
        check_format_condition(node[b"Type"] == b"Pages", "/Type of page tree node is not /Pages")
 | 
					        check_format_condition(
 | 
				
			||||||
 | 
					            node[b"Type"] == b"Pages", "/Type of page tree node is not /Pages")
 | 
				
			||||||
        pages = []
 | 
					        pages = []
 | 
				
			||||||
        for kid in node[b"Kids"]:
 | 
					        for kid in node[b"Kids"]:
 | 
				
			||||||
            kid_object = self.read_indirect(kid)
 | 
					            kid_object = self.read_indirect(kid)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -142,7 +142,8 @@ class ChunkStream(object):
 | 
				
			||||||
    def crc(self, cid, data):
 | 
					    def crc(self, cid, data):
 | 
				
			||||||
        "Read and verify checksum"
 | 
					        "Read and verify checksum"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Skip CRC checks for ancillary chunks if allowed to load truncated images
 | 
					        # Skip CRC checks for ancillary chunks if allowed to load truncated
 | 
				
			||||||
 | 
					        # images
 | 
				
			||||||
        # 5th byte of first char is 1 [specs, section 5.4]
 | 
					        # 5th byte of first char is 1 [specs, section 5.4]
 | 
				
			||||||
        if ImageFile.LOAD_TRUNCATED_IMAGES and (i8(cid[0]) >> 5 & 1):
 | 
					        if ImageFile.LOAD_TRUNCATED_IMAGES and (i8(cid[0]) >> 5 & 1):
 | 
				
			||||||
            self.crc_skip(cid, data)
 | 
					            self.crc_skip(cid, data)
 | 
				
			||||||
| 
						 | 
					@ -301,8 +302,8 @@ class PngStream(ChunkStream):
 | 
				
			||||||
    def check_text_memory(self, chunklen):
 | 
					    def check_text_memory(self, chunklen):
 | 
				
			||||||
        self.text_memory += chunklen
 | 
					        self.text_memory += chunklen
 | 
				
			||||||
        if self.text_memory > MAX_TEXT_MEMORY:
 | 
					        if self.text_memory > MAX_TEXT_MEMORY:
 | 
				
			||||||
            raise ValueError("Too much memory used in text chunks: %s>MAX_TEXT_MEMORY" %
 | 
					            raise ValueError("Too much memory used in text chunks: "
 | 
				
			||||||
                             self.text_memory)
 | 
					                             "%s>MAX_TEXT_MEMORY" % self.text_memory)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def chunk_iCCP(self, pos, length):
 | 
					    def chunk_iCCP(self, pos, length):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,7 +83,8 @@ class PpmImageFile(ImageFile.ImageFile):
 | 
				
			||||||
                    if s not in b_whitespace:
 | 
					                    if s not in b_whitespace:
 | 
				
			||||||
                        break
 | 
					                        break
 | 
				
			||||||
                    if s == b"":
 | 
					                    if s == b"":
 | 
				
			||||||
                        raise ValueError("File does not extend beyond magic number")
 | 
					                        raise ValueError(
 | 
				
			||||||
 | 
					                            "File does not extend beyond magic number")
 | 
				
			||||||
                if s != b"#":
 | 
					                if s != b"#":
 | 
				
			||||||
                    break
 | 
					                    break
 | 
				
			||||||
                s = self.fp.readline()
 | 
					                s = self.fp.readline()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -222,6 +222,7 @@ Image.register_save(SgiImageFile.format, _save)
 | 
				
			||||||
Image.register_mime(SgiImageFile.format, "image/sgi")
 | 
					Image.register_mime(SgiImageFile.format, "image/sgi")
 | 
				
			||||||
Image.register_mime(SgiImageFile.format, "image/rgb")
 | 
					Image.register_mime(SgiImageFile.format, "image/rgb")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Image.register_extensions(SgiImageFile.format, [".bw", ".rgb", ".rgba", ".sgi"])
 | 
					Image.register_extensions(SgiImageFile.format,
 | 
				
			||||||
 | 
					                          [".bw", ".rgb", ".rgba", ".sgi"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# End of file
 | 
					# End of file
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,7 +94,8 @@ class SunImageFile(ImageFile.ImageFile):
 | 
				
			||||||
                raise SyntaxError("Unsupported Palette Type")
 | 
					                raise SyntaxError("Unsupported Palette Type")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            offset = offset + palette_length
 | 
					            offset = offset + palette_length
 | 
				
			||||||
            self.palette = ImagePalette.raw("RGB;L", self.fp.read(palette_length))
 | 
					            self.palette = ImagePalette.raw("RGB;L",
 | 
				
			||||||
 | 
					                                            self.fp.read(palette_length))
 | 
				
			||||||
            if self.mode == "L":
 | 
					            if self.mode == "L":
 | 
				
			||||||
                self.mode = "P"
 | 
					                self.mode = "P"
 | 
				
			||||||
                rawmode = rawmode.replace('L', 'P')
 | 
					                rawmode = rawmode.replace('L', 'P')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -431,7 +431,8 @@ class ImageFileDirectory_v2(MutableMapping):
 | 
				
			||||||
        * self.tagtype = {}
 | 
					        * self.tagtype = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          * Key: numerical tiff tag number
 | 
					          * Key: numerical tiff tag number
 | 
				
			||||||
          * Value: integer corresponding to the data type from `~PIL.TiffTags.TYPES`
 | 
					          * Value: integer corresponding to the data type from
 | 
				
			||||||
 | 
					                   ~PIL.TiffTags.TYPES`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .. versionadded:: 3.0.0
 | 
					    .. versionadded:: 3.0.0
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,8 @@ from collections import namedtuple
 | 
				
			||||||
class TagInfo(namedtuple("_TagInfo", "value name type length enum")):
 | 
					class TagInfo(namedtuple("_TagInfo", "value name type length enum")):
 | 
				
			||||||
    __slots__ = []
 | 
					    __slots__ = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __new__(cls, value=None, name="unknown", type=None, length=None, enum=None):
 | 
					    def __new__(cls, value=None, name="unknown",
 | 
				
			||||||
 | 
					                type=None, length=None, enum=None):
 | 
				
			||||||
        return super(TagInfo, cls).__new__(
 | 
					        return super(TagInfo, cls).__new__(
 | 
				
			||||||
            cls, value, name, type, length, enum or {})
 | 
					            cls, value, name, type, length, enum or {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,8 +73,8 @@ TAGS_V2 = {
 | 
				
			||||||
    257: ("ImageLength", LONG, 1),
 | 
					    257: ("ImageLength", LONG, 1),
 | 
				
			||||||
    258: ("BitsPerSample", SHORT, 0),
 | 
					    258: ("BitsPerSample", SHORT, 0),
 | 
				
			||||||
    259: ("Compression", SHORT, 1,
 | 
					    259: ("Compression", SHORT, 1,
 | 
				
			||||||
          {"Uncompressed": 1, "CCITT 1d": 2, "Group 3 Fax": 3, "Group 4 Fax": 4,
 | 
					          {"Uncompressed": 1, "CCITT 1d": 2, "Group 3 Fax": 3,
 | 
				
			||||||
           "LZW": 5, "JPEG": 6, "PackBits": 32773}),
 | 
					           "Group 4 Fax": 4, "LZW": 5, "JPEG": 6, "PackBits": 32773}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    262: ("PhotometricInterpretation", SHORT, 1,
 | 
					    262: ("PhotometricInterpretation", SHORT, 1,
 | 
				
			||||||
          {"WhiteIsZero": 0, "BlackIsZero": 1, "RGB": 2, "RGB Palette": 3,
 | 
					          {"WhiteIsZero": 0, "BlackIsZero": 1, "RGB": 2, "RGB Palette": 3,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,8 @@
 | 
				
			||||||
from __future__ import print_function
 | 
					from __future__ import print_function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from . import Image, ImageFile
 | 
					from . import Image, ImageFile
 | 
				
			||||||
from ._binary import i16le as word, si16le as short, i32le as dword, si32le as _long
 | 
					from ._binary import i16le as word, si16le as short, \
 | 
				
			||||||
 | 
					                     i32le as dword, si32le as _long
 | 
				
			||||||
from ._util import py3
 | 
					from ._util import py3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user