def test_convert_conversion_not_needed_and_forbiden(self): """ Tests conversion not needed but forbidden. """ status = None code = None try: src_im = Image(src=self.blob_path ) # image in resource folder should be not jpeg ext = '.png' input_dir = os.path.split(self.blob_path)[0] input_desc = [{ 'description': 'input', 'max_pixels': '1024 * 2000', 'dtype': '3x8i', 'ext': ext, 'type': 'image', 'max_weight': 5242880, 'forbid_preprocess': 'true' }] response = self.convert(input_dir, input_desc, None) status = response.get('status') code = response.get('info').get('0').get('code') dst_file = os.path.split(self.blob_path)[0] + '/input_0' + ext dst_im = Image(src=dst_file) os.remove(dst_file) finally: self.assertEqual(status, 'OK') self.assertEqual(str(code), '0') self.assertTrue( (src_im.data == dst_im.data).all(), msg= "Preprocess is forbidden but the image data have been modified." )
def test_convert_resize_image(self): """ Tests to downsize a picture to max_pixels. """ status = None code = None try: ext = '.png' input_dir = os.path.split(self.blob_path)[0] max_pixels = 150 input_desc = [{ 'description': 'input', 'max_pixels': max_pixels, 'dtype': '3x8i', 'ext': ext, 'type': 'image', 'max_weight': 5242880 }] response = self.convert(input_dir, input_desc, None) status = response.get('status') code = response.get('info').get('0').get('code') dst_file = os.path.split(self.blob_path)[0] + '/input_0' + ext dst_im = Image(src=dst_file) dst_pixels = dst_im.width() * dst_im.height() os.remove(dst_file) finally: self.assertEqual(status, 'OK') self.assertEqual(str(code), '1') self.assertTrue( dst_pixels < max_pixels, msg="Input image has not be reduced under max_pixels {} >= {}". format(dst_pixels, max_pixels))
def test_tiff_depths(self): """ Tests the conversions between all supported dtypes in tiff. """ tif_file = tempfile.NamedTemporaryFile(suffix='.tif', prefix="ipol_", delete=True) for src_depth in ('8i', '16i', '32i', '16f', '32f'): for dst_depth in ( '8i', '16i', '32i'): # float as a destination is not strictly equal data = self.data_matrix(src_depth) im = Image(data=data) im.convert_depth(dst_depth) im.write(tif_file.name) im = Image(src=tif_file.name) data = self.data_matrix(dst_depth) self.assertTrue( im.data.dtype is data.dtype, msg="dtype expected={} found={}, conversion failed {} > {}" .format(data.dtype, im.data.dtype, src_depth, dst_depth)) self.assertTrue( (im.data == data).all(), msg="data alteration during conversion {} > {}.".format( src_depth, dst_depth)) tif_file.close()
def convert_image(input_file, input_desc, crop_info=None): """ Convert image if needed """ # Image has to be always loaded to test width and size im = Image(src=input_file) dst_file = os.path.splitext(input_file)[0] + input_desc.get('ext') program = [ # Color conversion ConverterChannels(input_desc, im), # Depth conversion ConverterDepth(input_desc, im), # Crop before reducing image to max_pixels (or the crop box will be outside of scope) ConverterCrop(input_desc, im, crop_info), # Resize image if bigger than a max. ConverterMaxPixels(input_desc, im), # Re-encoding (ex: jpg > png) ConverterEncoding(input_desc, input_file, dst_file), ] messages = [] lossy_modification = False modification = False for task in program: if not task.need_conversion(): continue if not task.can_convert(): return 2, [] # Conversion needed but forbidden info_loss = task.information_loss() message = task.convert() modification = True if info_loss: messages.append(message) lossy_modification = True # something have been done, write file if modification: im.write(dst_file) # Nothing done, ensure expected extension (.jpe > .jpeg; .tif > .tiff) elif input_file != dst_file: os.rename(input_file, dst_file) if lossy_modification: return 1, messages return 0, []
def convert_tiff_to_png(self, img): """ Converts the input TIFF to PNG. This is used by the web interface for visualization purposes """ data = {"status": "KO"} try: buf = base64.b64decode(img) # cv2.IMREAD_ANYCOLOR option try to convert to uint8, 7x faster than matrix conversion # but fails with some tiff formats (float) im = Image(buf=buf) im.convert_depth('8i') buf = im.encode('.png') data["img"] = binascii.b2a_base64(buf).decode() # re-encode bytes data["status"] = "OK" except Exception: message = "TIFF to PNG for client, conversion failure." self.logger.exception(message) return json.dumps(data, indent=4).encode()
def test_convert_change_image_ext(self): """ Tests extension conversion. """ status = None code = None try: dst_ext = '.bmp' dst_mime = 'image/bmp' input_dir = os.path.split(self.blob_path)[0] src_im = Image(src=self.blob_path ) # image in resource folder should be not jpeg input_desc = [{ 'description': 'input', 'max_pixels': '1024 * 2000', 'dtype': '3x8i', 'ext': dst_ext, 'type': 'image', 'max_weight': 5242880 }] crop_info = None response = self.convert(input_dir, input_desc, crop_info) status = response.get('status') code = response.get('info').get('0').get('code') dst_file = os.path.split(self.blob_path)[0] + '/input_0' + dst_ext good_mime = (magic.from_file(dst_file, mime=True) == dst_mime) dst_im = Image(src=dst_file) os.remove(dst_file) finally: self.assertEqual(status, 'OK') self.assertEqual(str(code), '0') self.assertTrue(good_mime, msg="Bad file encoding, {} is not {}".format( dst_file, dst_mime)) self.assertTrue( (src_im.data == dst_im.data).all(), msg="Changing image extension has change the data.")
def test_8i_extensions(self): """ Tests the conversions between 8 bits file formats. """ data = self.data_matrix('8i') # gif is not supported by OpenCV, .jpg do not keep exact colors exts = { '.bmp': 'image/bmp', '.png': 'image/png', '.tif': 'image/tiff', '.TIFF': 'image/tiff', } for src_ext, src_mime in list(exts.items()): src_file = tempfile.NamedTemporaryFile(suffix=src_ext, prefix="ipol_", delete=True) src_im = Image(data=data) src_im.write(src_file.name) self.assertTrue(magic.from_file(src_file.name, mime=True) == src_mime, msg="Bad file encoding, {} is not {}".format( src_file.name, src_mime)) src_im = Image(src=src_file.name) for dst_ext, dst_mime in list(exts.items()): dst_file = tempfile.NamedTemporaryFile(suffix=dst_ext, prefix="ipol_", delete=True) src_im.write( dst_file.name) # write to dest should encoding conversion self.assertTrue(magic.from_file(dst_file.name, mime=True) == dst_mime, msg="Bad file encoding, {} is not {}".format( dst_file.name, dst_mime)) dst_im = Image(src=dst_file.name) self.assertTrue((src_im.data == dst_im.data).all(), msg="{} > {}".format(src_ext, dst_ext)) dst_file.close() src_file.close()
def test_convert_resize_image_with_crop(self): """ Tests conversion with crop. """ status = None code = None try: ext = '.png' input_dir = os.path.split(self.blob_path)[0] input_desc = [{ 'description': 'input', 'max_pixels': '1024 * 2000', 'dtype': '3x8i', 'ext': ext, 'type': 'image', 'max_weight': 5242880 }] width = 105 height = 79.6 crop_info = json.dumps({ "x": 81, "y": 9.2, "width": width, "height": height, "rotate": 0, "scaleX": 1, "scaleY": 1 }) response = self.convert(input_dir, input_desc, crop_info) status = response.get('status') code = response.get('info').get('0').get('code') dst_file = os.path.split(self.blob_path)[0] + '/input_0' + ext dst_im = Image(src=dst_file) os.remove(dst_file) finally: self.assertEqual(status, 'OK') self.assertEqual(str(code), '1') self.assertTrue( dst_im.width() == round(width) and dst_im.height() == round(height), msg="Input image {}x{} has not be cropped to {}x{}".format( dst_im.width(), dst_im.height(), width, height))