def test_use_zopfli(self): png = zopfli.ZopfliPNG() self.assertTrue(png.use_zopfli) png.use_zopfli = False self.assertFalse(png.use_zopfli) png = zopfli.ZopfliPNG(use_zopfli=False) self.assertFalse(png.use_zopfli) with self.assertRaises(TypeError): del zopfli.ZopfliPNG().use_zopfli
def test_lossy_8bit(self): png = zopfli.ZopfliPNG() self.assertFalse(png.lossy_8bit) png.lossy_8bit = True self.assertTrue(png.lossy_8bit) png = zopfli.ZopfliPNG(lossy_8bit=True) self.assertTrue(png.lossy_8bit) with self.assertRaises(TypeError): del zopfli.ZopfliPNG().lossy_8bit
def test_verbose(self): png = zopfli.ZopfliPNG() self.assertFalse(png.verbose) png.verbose = True self.assertTrue(png.verbose) png = zopfli.ZopfliPNG(verbose=True) self.assertTrue(png.verbose) with self.assertRaises(TypeError): del zopfli.ZopfliPNG().verbose
def test_iterations_large(self): png = zopfli.ZopfliPNG() self.assertEqual(png.iterations_large, 5) png.iterations_large *= 2 self.assertEqual(png.iterations_large, 10) png = zopfli.ZopfliPNG(iterations_large=10) self.assertEqual(png.iterations_large, 10) with self.assertRaises(TypeError): zopfli.ZopfliPNG(iterations_large=None) with self.assertRaises(TypeError): zopfli.ZopfliPNG().iterations_large = None with self.assertRaises(TypeError): del zopfli.ZopfliPNG().iterations_large
def test_iterations(self): png = zopfli.ZopfliPNG() self.assertEqual(png.iterations, 15) png.iterations *= 2 self.assertEqual(png.iterations, 30) png = zopfli.ZopfliPNG(iterations=30) self.assertEqual(png.iterations, 30) with self.assertRaises(TypeError): zopfli.ZopfliPNG(iterations=None) with self.assertRaises(TypeError): zopfli.ZopfliPNG().iterations = None with self.assertRaises(TypeError): del zopfli.ZopfliPNG().iterations
def test_optimize(self): png = zopfli.ZopfliPNG() self.assertGreater(len(black_png), len(png.optimize(black_png))) with self.assertRaises(TypeError): png.optimize(None) with self.assertRaises(ValueError): png.optimize(b'')
def test_filter_strategies(self): png = zopfli.ZopfliPNG() self.assertEqual(png.filter_strategies, '') self.assertTrue(png.auto_filter_strategy) png.filter_strategies = '01234mepb' self.assertEqual(png.filter_strategies, '01234mepb') self.assertFalse(png.auto_filter_strategy) with self.assertRaises(ValueError): png.filter_strategies = '.' self.assertEqual(png.filter_strategies, '') self.assertTrue(png.auto_filter_strategy) png = zopfli.ZopfliPNG(filter_strategies='01234mepb') self.assertEqual(png.filter_strategies, '01234mepb') self.assertFalse(png.auto_filter_strategy) png.auto_filter_strategy = True self.assertEqual(png.filter_strategies, '') self.assertTrue(png.auto_filter_strategy) with self.assertRaises(TypeError): zopfli.ZopfliPNG(filter_strategies=None) with self.assertRaises(ValueError): zopfli.ZopfliPNG(filter_strategies=u'\u00B7') with self.assertRaises(ValueError): zopfli.ZopfliPNG(filter_strategies='z') with self.assertRaises(TypeError): del zopfli.ZopfliPNG().filter_strategies with self.assertRaises(TypeError): del zopfli.ZopfliPNG().auto_filter_strategy
def optimize(input_file, output_file, options={}, verbose=False, quiet=False): options = normalize_options(options) image = Image.open(input_file) if options["output_format"] == "orig" and image.format not in ( "JPEG", "PNG"): # noqa raise ValueError( "The input image must be a JPEG or a PNG when setting 'output_format' to 'orig'" ) # noqa # resize if options["resize"] != "orig": image.thumbnail(options["resize"], Image.LANCZOS) # output format output_format = None if options["output_format"] == "orig": output_format = image.format.lower() elif options["output_format"] in ("jpeg", "png"): output_format = options["output_format"] else: # auto if image_have_alpha(image, options["opacity_threshold"]): output_format = "png" else: # XXX Maybe we should try to encode in both format # and choose the smaller output? output_format = "jpeg" # convert / optimize output_image_bytes = None if output_format == "jpeg": output_image_bytes = pyguetzli.process_pil_image( image, int(options["jpeg_quality"] * 100)) else: pass image_io = io.BytesIO() image.save(image_io, format="PNG", optimize=False) image_io.seek(0) image_bytes = image_io.read() # Optimize using zopflipng zopflipng = zopfli.ZopfliPNG() zopflipng.lossy_8bit = True zopflipng.lossy_transparent = True zopflipng.filter_strategies = "01234mepb" zopflipng.iterations = 20 zopflipng.iterations_large = 7 output_image_bytes = zopflipng.optimize(image_bytes) # write to output_file if not hasattr(output_file, "write"): output_file = open(output_file, "wb") output_file.write(output_image_bytes)
def test_keep_chunks(self): png = zopfli.ZopfliPNG() self.assertEqual(png.keep_chunks, ()) png.keep_chunks = ['tEXt', 'zTXt', 'iTXt'] self.assertEqual(png.keep_chunks, ('tEXt', 'zTXt', 'iTXt')) png = zopfli.ZopfliPNG(keep_chunks=['tEXt', 'zTXt', 'iTXt']) self.assertEqual(png.keep_chunks, ('tEXt', 'zTXt', 'iTXt')) with self.assertRaises(TypeError): zopfli.ZopfliPNG(keep_chunks=None) with self.assertRaises(TypeError): zopfli.ZopfliPNG(keep_chunks=[None]) with self.assertRaises(ValueError): zopfli.ZopfliPNG(keep_chunks=[u'\u00B7']) with self.assertRaises(TypeError): del zopfli.ZopfliPNG().keep_chunks
def _image_to_asset(self, image: PIL.Image.Image, mime_type: Union[MimeType, str]) -> Asset: """ Converts an PIL image to a MADAM asset. The conversion can also include a change in file type. :param image: PIL image :type image: PIL.Image.Image :param mime_type: MIME type of the target asset :type mime_type: MimeType or str :return: MADAM asset with the specified MIME type :rtype: Asset """ mime_type = MimeType(mime_type) pil_format = PillowProcessor.__mime_type_to_pillow_type[mime_type] pil_options = dict(PillowProcessor.__format_defaults.get( mime_type, {})) format_config = dict(self.config.get(mime_type.type, {})) format_config.update(self.config.get(str(mime_type), {})) image_buffer = io.BytesIO() if mime_type == MimeType('image/png') and image.mode != 'P': use_zopfli = format_config.get('zopfli', False) if use_zopfli: import zopfli zopfli_png = zopfli.ZopfliPNG() # Convert 16-bit per channel images to 8-bit per channel zopfli_png.lossy_8bit = False # Allow altering hidden colors of fully transparent pixels zopfli_png.lossy_transparent = True # Use all available optimization strategies zopfli_png.filter_strategies = format_config.get( 'zopfli_strategies', '0me') pil_options.pop('optimize', False) essence = io.BytesIO() image.save(essence, 'PNG', optimize=False, **pil_options) essence.seek(0) optimized_data = zopfli_png.optimize(essence.read()) image_buffer.write(optimized_data) else: image.save(image_buffer, pil_format, **pil_options) elif mime_type == MimeType('image/jpeg'): pil_options['progressive'] = int( format_config.get('progressive', pil_options['progressive'])) pil_options['quality'] = int( format_config.get('quality', pil_options['quality'])) image.save(image_buffer, pil_format, **pil_options) elif mime_type == MimeType('image/tiff') and image.mode == 'P': pil_options.pop('compression', '') image.save(image_buffer, pil_format, **pil_options) elif mime_type == MimeType('image/webp'): pil_options['method'] = int( format_config.get('method', pil_options['method'])) pil_options['quality'] = int( format_config.get('quality', pil_options['quality'])) image.save(image_buffer, pil_format, **pil_options) else: image.save(image_buffer, pil_format, **pil_options) image_buffer.seek(0) asset = self.read(image_buffer) return asset