def save_original_and_compressed_versions_of_image(filename, entity_type, entity_id, original_image_content, filename_prefix, image_is_compressible): """Saves the three versions of the image file. Args: filename: str. The name of the image file. entity_type: str. The type of the entity. entity_id: str. The id of the entity. original_image_content: str. The content of the original image. filename_prefix: str. The string to prefix to the filename. image_is_compressible: bool. Whether the image can be compressed or not. """ filepath = '%s/%s' % (filename_prefix, filename) filename_wo_filetype = filename[:filename.rfind('.')] filetype = filename[filename.rfind('.') + 1:] compressed_image_filename = '%s_compressed.%s' % (filename_wo_filetype, filetype) compressed_image_filepath = '%s/%s' % (filename_prefix, compressed_image_filename) micro_image_filename = '%s_micro.%s' % (filename_wo_filetype, filetype) micro_image_filepath = '%s/%s' % (filename_prefix, micro_image_filename) file_system_class = get_entity_file_system_class() fs = fs_domain.AbstractFileSystem(file_system_class( entity_type, entity_id)) if image_is_compressible: compressed_image_content = image_services.compress_image( original_image_content, 0.8) micro_image_content = image_services.compress_image( original_image_content, 0.7) else: compressed_image_content = original_image_content micro_image_content = original_image_content mimetype = ('image/svg+xml' if filetype == 'svg' else 'image/%s' % filetype) # Because in case of CreateVersionsOfImageJob, the original image is # already there. Also, even if the compressed, micro versions for some # image exists, then this would prevent from creating another copy of # the same. if not fs.isfile(filepath): fs.commit(filepath, original_image_content, mimetype=mimetype) if not fs.isfile(compressed_image_filepath): fs.commit(compressed_image_filepath, compressed_image_content, mimetype=mimetype) if not fs.isfile(micro_image_filepath): fs.commit(micro_image_filepath, micro_image_content, mimetype=mimetype)
def test_compression_results_in_correct_format(self): compressed_image = (image_services.compress_image( self.jpeg_raw_image, 0.7)) pil_image = Image.open(io.BytesIO(compressed_image)) self.assertEqual(pil_image.format, 'JPEG') compressed_image = (image_services.compress_image( self.png_raw_image, 0.7)) pil_image = Image.open(io.BytesIO(compressed_image)) self.assertEqual(pil_image.format, 'PNG')
def test_compress_image_returns_correct_dimensions(self): compressed_image = ( image_services.compress_image(self.jpeg_raw_image, 0.5)) height, width = ( image_services.get_image_dimensions(compressed_image)) self.assertEqual(self.TEST_IMAGE_HEIGHT * 0.5, height) self.assertEqual(self.TEST_IMAGE_WIDTH * 0.5, width)
def test_compression_results_in_identical_files(self): with python_utils.open_file( os.path.join( feconf.TESTS_DATA_DIR, 'compressed_image.jpg'), 'rb', encoding=None) as f: correct_compressed_image = f.read() correct_height, correct_width = ( image_services.get_image_dimensions(correct_compressed_image)) compressed_image = ( image_services.compress_image(self.jpeg_raw_image, 0.5)) # In order to make sure the images are the same, the function needs to # open and save the image specifically using PIL since the "golden # image" (image that we compare the compressed image to) is saved using # PIL. This applies a slight quality change that won't appear unless we # save it using PIL. temp_image = Image.open(io.BytesIO(compressed_image)) image_format = temp_image.format with io.BytesIO() as output: temp_image.save(output, format=image_format) compressed_image_content = output.getvalue() height, width = image_services.get_image_dimensions( compressed_image_content) self.assertEqual(correct_height, height) self.assertEqual(correct_width, width) image1 = Image.open(io.BytesIO(correct_compressed_image)).convert('RGB') image2 = Image.open(io.BytesIO(compressed_image_content)).convert('RGB') diff = ImageChops.difference(image1, image2) # Function diff.getbbox() returns a bounding box on all islands or # regions of non-zero pixels. In other words, if we have a bounding # box, there will be areas that are not 0 in the difference meaning # that the 2 images are not equal. self.assertFalse(diff.getbbox())
def test_invalid_scaling_factor_triggers_value_error(self): value_exception = self.assertRaisesRegexp( ValueError, r'Scaling factor should be in the interval \(0, 1], received 1.1.') with value_exception: image_services.compress_image(self.jpeg_raw_image, 1.1) value_exception = self.assertRaisesRegexp( ValueError, r'Scaling factor should be in the interval \(0, 1], received 0.') with value_exception: image_services.compress_image(self.jpeg_raw_image, 0) value_exception = self.assertRaisesRegexp( ValueError, r'Scaling factor should be in the interval \(0, 1], received -1.') with value_exception: image_services.compress_image(self.jpeg_raw_image, -1)
def test_invalid_scaling_factor_triggers_value_error(self) -> None: value_exception = self.assertRaisesRegex(# type: ignore[no-untyped-call] ValueError, re.escape( 'Scaling factor should be in the interval (0, 1], ' 'received 1.100000.')) with value_exception: image_services.compress_image(self.jpeg_raw_image, 1.1) value_exception = self.assertRaisesRegex(# type: ignore[no-untyped-call] ValueError, re.escape( 'Scaling factor should be in the interval (0, 1], ' 'received 0.000000.')) with value_exception: image_services.compress_image(self.jpeg_raw_image, 0) value_exception = self.assertRaisesRegex(# type: ignore[no-untyped-call] ValueError, re.escape( 'Scaling factor should be in the interval (0, 1], ' 'received -1.000000.')) with value_exception: image_services.compress_image(self.jpeg_raw_image, -1)