def test_16_image_process_format(self): """Test the format parameter of image_process.""" image = tools.base64_to_image( tools.image_process(self.base64_1920x1080_jpeg, output_format='PNG')) self.assertEqual(image.format, 'PNG', "change format to PNG") image = tools.base64_to_image( tools.image_process(self.base64_1x1_png, output_format='JpEg')) self.assertEqual(image.format, 'JPEG', "change format to JPEG (case insensitive)") image = tools.base64_to_image( tools.image_process(self.base64_1920x1080_jpeg, output_format='BMP')) self.assertEqual(image.format, 'PNG', "change format to BMP converted to PNG") self.base64_image_1080_1920_rgba = tools.image_to_base64( Image.new('RGBA', (108, 192)), 'PNG') image = tools.base64_to_image( tools.image_process(self.base64_image_1080_1920_rgba, output_format='jpeg')) self.assertEqual(image.format, 'JPEG', "change format PNG with RGBA to JPEG") # pass quality to force the image to be processed self.base64_image_1080_1920_tiff = tools.image_to_base64( Image.new('RGB', (108, 192)), 'TIFF') image = tools.base64_to_image( tools.image_process(self.base64_image_1080_1920_tiff, quality=95)) self.assertEqual(image.format, 'JPEG', "unsupported format to JPEG")
def setUp(self): super(TestImage, self).setUp() self.bg_color = (135, 90, 123) self.fill_color = (0, 160, 157) self.base64_1x1_png = b'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR4nGNgYGAAAAAEAAH2FzhVAAAAAElFTkSuQmCC' self.base64_svg = base64.b64encode(b'<svg></svg>') self.base64_1920x1080_jpeg = tools.image_to_base64( Image.new('RGB', (1920, 1080)), 'JPEG') # The following image contains a tag `Lens Info` with a value of `3.99mm f/1.8` # This particular tag 0xa432 makes the `exif_transpose` method fail in 5.4.1 < Pillow < 7.2.0 self.base64_exif_jpg = b"""/9j/4AAQSkZJRgABAQAAAQABAAD/4QDQRXhpZgAATU0AKgAAAAgABgESAAMAAAABAAYAAAEaAAUA AAABAAAAVgEbAAUAAAABAAAAXgEoAAMAAAABAAEAAAITAAMAAAABAAEAAIdpAAQAAAABAAAAZgAA AAAAAAABAAAAAQAAAAEAAAABAAWQAAAHAAAABDAyMzGRAQAHAAAABAECAwCgAAAHAAAABDAxMDCg AQADAAAAAf//AACkMgAFAAAABAAAAKgAAAAAAAABjwAAAGQAAAGPAAAAZAAAAAkAAAAFAAAACQAA AAX/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAADAAYDASIAAhEBAxEB/8QAHwAAAQUBAQEB AQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1Fh ByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZ WmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAEC AwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0 dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX 2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iiigD//2Q==""" # Draw a red square in the middle of the image, this will be used to # verify crop is working. The border is going to be `self.bg_color` and # the middle is going to be `self.fill_color`. # horizontal image (border is left/right) image = Image.new('RGB', (1920, 1080), color=self.bg_color) offset = (image.size[0] - image.size[1]) / 2 draw = ImageDraw.Draw(image) draw.rectangle(xy=[(offset, 0), (image.size[0] - offset, image.size[1])], fill=self.fill_color) self.base64_1920x1080_png = tools.image_to_base64(image, 'PNG') # vertical image (border is top/bottom) image = Image.new('RGB', (1080, 1920), color=self.bg_color) offset = (image.size[1] - image.size[0]) / 2 draw = ImageDraw.Draw(image) draw.rectangle(xy=[(0, offset), (image.size[0], image.size[1] - offset)], fill=self.fill_color) self.base64_1080x1920_png = tools.image_to_base64(image, 'PNG')
def test_12_image_process_verify_resolution(self): """Test the verify_resolution parameter of image_process.""" res = tools.image_process(self.base64_1920x1080_jpeg, verify_resolution=True) self.assertNotEqual(res, False, "size ok") base64_image_excessive = tools.image_to_base64( Image.new('RGB', (45001, 1000)), 'PNG') with self.assertRaises(ValueError, msg="size excessive"): tools.image_process(base64_image_excessive, verify_resolution=True)
def test_13_image_process_quality(self): """Test the quality parameter of image_process.""" # CASE: PNG RGBA doesn't apply quality, just optimize image = tools.image_to_base64(Image.new('RGBA', (1080, 1920)), 'PNG') res = tools.image_process(image) self.assertLessEqual(len(res), len(image)) # CASE: PNG RGB doesn't apply quality, just optimize image = tools.image_to_base64(Image.new('P', (1080, 1920)), 'PNG') res = tools.image_process(image) self.assertLessEqual(len(res), len(image)) # CASE: JPEG optimize + reduced quality res = tools.image_process(self.base64_1920x1080_jpeg) self.assertLessEqual(len(res), len(self.base64_1920x1080_jpeg)) # CASE: GIF doesn't apply quality, just optimize image = tools.image_to_base64(Image.new('RGB', (1080, 1920)), 'GIF') res = tools.image_process(image) self.assertLessEqual(len(res), len(image))
def test_15_image_process_colorize(self): """Test the colorize parameter of image_process.""" # verify initial condition image_rgba = Image.new('RGBA', (1, 1)) self.assertEqual(image_rgba.mode, 'RGBA') self.assertEqual(image_rgba.getpixel((0, 0)), (0, 0, 0, 0)) base64_rgba = tools.image_to_base64(image_rgba, 'PNG') # CASE: color random, color has changed image = tools.base64_to_image( tools.image_process(base64_rgba, colorize=True)) self.assertEqual(image.mode, 'RGB') self.assertNotEqual(image.getpixel((0, 0)), (0, 0, 0))
def test_parse_company_colors_grayscale(self): """Grayscale images with transparency - make sure the color extraction does not crash""" self.company.write({ 'primary_color': '#ff0080', 'secondary_color': '#00ff00', 'paperformat_id': self.env.ref('base.paperformat_us').id, }) with Form(self.env['base.document.layout']) as doc_layout: with Image.open(os.path.join(dir_path, 'logo_ci.png'), 'r') as img: base64_img = image_to_base64(img, 'PNG') doc_layout.logo = base64_img self.assertNotEqual(None, doc_layout.primary_color)
def _get_exif_colored_square_b64(self, orientation, colors, size): image = Image.new('RGB', (size, size), color=self.bg_color) draw = ImageDraw.Draw(image) # Paint the colors on the 4 corners, to be able to test which colors # move on which corners. draw.rectangle(xy=[(0, 0), (size // 2, size // 2)], fill=colors[0]) # top/left draw.rectangle(xy=[(size // 2, 0), (size, size // 2)], fill=colors[1]) # top/right draw.rectangle(xy=[(0, size // 2), (size // 2, size)], fill=colors[2]) # bottom/left draw.rectangle(xy=[(size // 2, size // 2), (size, size)], fill=colors[3]) # bottom/right # Set the proper exif tag based on orientation params. exif = b'Exif\x00\x00II*\x00\x08\x00\x00\x00\x01\x00\x12\x01\x03\x00\x01\x00\x00\x00' + bytes( [orientation]) + b'\x00\x00\x00\x00\x00\x00\x00' # The image image is saved with the exif tag. return tools.image_to_base64(image, 'JPEG', exif=exif)
def _set_images(self): for fname in self._get_images_for_test(): fname_split = fname.split('.') if not fname_split[0] in _file_cache: with Image.open(os.path.join(dir_path, fname), 'r') as img: base64_img = image_to_base64(img, 'PNG') primary, secondary = self.env[ 'base.document.layout'].create( {})._parse_logo_colors(base64_img) _img = frozendict({ 'img': base64_img, 'colors': { 'primary_color': primary, 'secondary_color': secondary, }, }) _file_cache[fname_split[0]] = _img self.company_imgs = frozendict(_file_cache)
def test_01_website_favicon(self): """The goal of this test is to make sure the favicon is correctly handled on the website.""" # Test setting an Ico file directly, done through create Website = self.env['website'] website = Website.create({ 'name': 'Test Website', 'favicon': Website._default_favicon(), }) image = base64_to_image(website.favicon) self.assertEqual(image.format, 'ICO') # Test setting a JPEG file that is too big, done through write bg_color = (135, 90, 123) image = Image.new('RGB', (1920, 1080), color=bg_color) website.favicon = image_to_base64(image, 'JPEG') image = base64_to_image(website.favicon) self.assertEqual(image.format, 'ICO') self.assertEqual(image.size, (256, 256)) self.assertEqual(image.getpixel((0, 0)), bg_color)
def test_10_image_autoresize(self): Attachment = self.env['ir.attachment'] img_bin = io.BytesIO() dir_path = os.path.dirname(os.path.realpath(__file__)) with Image.open(os.path.join(dir_path, 'flectra.jpg'), 'r') as logo: img = Image.new('RGB', (4000, 2000), '#4169E1') img.paste(logo) img.save(img_bin, 'JPEG') img_encoded = image_to_base64(img, 'JPEG') img_bin = img_bin.getvalue() fullsize = 124.99 #################################### ### test create/write on 'datas' #################################### attach = Attachment.with_context(image_no_postprocess=True).create({ 'name': 'image', 'datas': img_encoded, }) self.assertApproximately(attach.datas, fullsize) # no resize, no compression attach = attach.with_context(image_no_postprocess=False) attach.datas = img_encoded self.assertApproximately(attach.datas, 12.06) # default resize + default compression # resize + default quality (80) self.env['ir.config_parameter'].set_param('base.image_autoresize_max_px', '1024x768') attach.datas = img_encoded self.assertApproximately(attach.datas, 3.71) # resize + quality 50 self.env['ir.config_parameter'].set_param('base.image_autoresize_quality', '50') attach.datas = img_encoded self.assertApproximately(attach.datas, 3.57) # no resize + no quality implicit self.env['ir.config_parameter'].set_param('base.image_autoresize_max_px', '0') attach.datas = img_encoded self.assertApproximately(attach.datas, fullsize) # Check that we only compress quality when we resize. We avoid to compress again during a new write. # no resize + quality -> should have no effect self.env['ir.config_parameter'].set_param('base.image_autoresize_max_px', '10000x10000') self.env['ir.config_parameter'].set_param('base.image_autoresize_quality', '50') attach.datas = img_encoded self.assertApproximately(attach.datas, fullsize) #################################### ### test create/write on 'raw' #################################### # reset default ~ delete self.env['ir.config_parameter'].search([('key', 'ilike', 'base.image_autoresize%')]).unlink() attach = Attachment.with_context(image_no_postprocess=True).create({ 'name': 'image', 'raw': img_bin, }) self.assertApproximately(attach.raw, fullsize) # no resize, no compression attach = attach.with_context(image_no_postprocess=False) attach.raw = img_bin self.assertApproximately(attach.raw, 12.06) # default resize + default compression # resize + default quality (80) self.env['ir.config_parameter'].set_param('base.image_autoresize_max_px', '1024x768') attach.raw = img_bin self.assertApproximately(attach.raw, 3.71) # resize + no quality self.env['ir.config_parameter'].set_param('base.image_autoresize_quality', '0') attach.raw = img_bin self.assertApproximately(attach.raw, 4.09) # resize + quality 50 self.env['ir.config_parameter'].set_param('base.image_autoresize_quality', '50') attach.raw = img_bin self.assertApproximately(attach.raw, 3.57) # no resize + no quality implicit self.env['ir.config_parameter'].set_param('base.image_autoresize_max_px', '0') attach.raw = img_bin self.assertApproximately(attach.raw, fullsize)
def test_01_image_to_base64(self): """Test that a PIL image is correctly saved as base64.""" image = Image.new('RGB', (1, 1)) image_base64 = tools.image_to_base64(image, 'PNG') self.assertEqual(image_base64, self.base64_1x1_png)