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 _get_default_image(self, partner_type, is_company, parent_id): if getattr(threading.currentThread(), 'testing', False) or self._context.get('install_mode'): return False colorize, img_path, image_base64 = False, False, False if partner_type in ['other'] and parent_id: parent_image = self.browse(parent_id).image image_base64 = parent_image or None if not image_base64 and partner_type == 'invoice': img_path = get_module_resource('base', 'static/img', 'money.png') elif not image_base64 and partner_type == 'delivery': img_path = get_module_resource('base', 'static/img', 'truck.png') elif not image_base64 and is_company: img_path = get_module_resource('base', 'static/img', 'company_image.png') elif not image_base64: img_path = get_module_resource('base', 'static/img', 'avatar.png') colorize = True if img_path: with open(img_path, 'rb') as f: image_base64 = base64.b64encode(f.read()) if image_base64 and colorize: image_base64 = tools.image_process(image_base64, colorize=True) return tools.image_process(image_base64, size=tools.IMAGE_BIG_SIZE)
def _get_default_image(self, partner_type, is_company, parent_id): if getattr(threading.currentThread(), 'testing', False) or self._context.get('install_mode'): return False colorize, img_path, image_base64 = False, False, False if partner_type in ['other'] and parent_id: parent_image = self.browse(parent_id).image image_base64 = parent_image or None if not image_base64 and partner_type == 'invoice': img_path = get_module_resource('base', 'static/img', 'money.png') elif not image_base64 and partner_type == 'delivery': img_path = get_module_resource('base', 'static/img', 'truck.png') elif not image_base64 and is_company: img_path = get_module_resource('base', 'static/img', 'company_image.png') elif not image_base64: img_path = get_module_resource('base', 'static/img', 'avatar.png') colorize = True if img_path: with open(img_path, 'rb') as f: image_base64 = base64.b64encode(f.read()) if image_base64 and colorize: image_base64 = tools.image_process(image_base64, colorize=True) return tools.image_process(image_base64, size=tools.IMAGE_BIG_SIZE)
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 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_10_image_process_base64_source(self): """Test the base64_source parameter of image_process.""" wrong_base64 = b'oazdazpodazdpok' self.assertFalse(tools.image_process(False), "return False if base64_source is falsy") self.assertEqual(tools.image_process(self.base64_svg), self.base64_svg, "return base64_source if format is SVG") # in the following tests, pass `quality` to force the processing with self.assertRaises( UserError, msg= "This file could not be decoded as an image file. Please try with a different file." ): tools.image_process(wrong_base64, quality=95) with self.assertRaises( UserError, msg= "This file could not be decoded as an image file. Please try with a different file." ): tools.image_process(b'oazdazpodazdpokd', quality=95) image = tools.base64_to_image( tools.image_process(self.base64_1920x1080_jpeg, quality=95)) self.assertEqual(image.size, (1920, 1080), "OK return the image") # test that nothing happens if no operation has been requested # (otherwise those would raise because of wrong base64) self.assertEqual(tools.image_process(wrong_base64), wrong_base64) self.assertEqual(tools.image_process(wrong_base64, size=False), wrong_base64)
def test_10_image_process_base64_source(self): """Test the base64_source parameter of image_process.""" wrong_base64 = b'oazdazpodazdpok' self.assertFalse(tools.image_process(False), "return False if base64_source is falsy") self.assertEqual(tools.image_process(self.base64_svg), self.base64_svg, "return base64_source if format is SVG") # in the following tests, pass `quality` to force the processing with self.assertRaises( binascii.Error, msg="wrong base64: binascii.Error: Incorrect padding"): tools.image_process(wrong_base64, quality=95) with self.assertRaises( OSError, msg="wrong base64: OSError: cannot identify image file"): tools.image_process(b'oazdazpodazdpokd', quality=95) image = tools.base64_to_image( tools.image_process(self.base64_1920x1080_jpeg, quality=95)) self.assertEqual(image.size, (1920, 1080), "OK return the image") # test that nothing happens if no operation has been requested # (otherwise those would raise because of wrong base64) self.assertEqual(tools.image_process(wrong_base64), wrong_base64) self.assertEqual(tools.image_process(wrong_base64, size=False), wrong_base64)
def slide_get_image(self, slide_id, field='image_128', width=0, height=0, crop=False): # Protect infographics by limiting access to 256px (large) images if field not in ('image_128', 'image_256', 'image_512', 'image_1024', 'image_1920'): return werkzeug.exceptions.Forbidden() slide = request.env['slide.slide'].sudo().browse(slide_id).exists() if not slide: raise werkzeug.exceptions.NotFound() status, headers, image_base64 = request.env['ir.http'].sudo().binary_content( model='slide.slide', id=slide.id, field=field, default_mimetype='image/png') if status == 301: return request.env['ir.http']._response_by_status(status, headers, image_base64) if status == 304: return werkzeug.wrappers.Response(status=304) if not image_base64: image_base64 = self._get_default_avatar() if not (width or height): width, height = tools.image_guess_size_from_field_name(field) image_base64 = tools.image_process(image_base64, size=(int(width), int(height)), crop=crop) content = base64.b64decode(image_base64) headers = http.set_safe_image_headers(headers, content) response = request.make_response(content, headers) response.status_code = status return response
def slide_get_image(self, slide_id, field='image_medium', width=0, height=0, crop=False): # Protect infographics by limiting access to 256px (large) images if field not in ('image_small', 'image_medium', 'image_large'): return werkzeug.exceptions.Forbidden() slide = request.env['slide.slide'].sudo().browse(slide_id).exists() if not slide: raise werkzeug.exceptions.NotFound() status, headers, image_base64 = request.env['ir.http'].sudo().binary_content( model='slide.slide', id=slide.id, field=field, default_mimetype='image/png') if status == 301: return request.env['ir.http']._response_by_status(status, headers, image_base64) if status == 304: return werkzeug.wrappers.Response(status=304) if not image_base64: image_base64 = self._get_default_avatar() if not (width or height): width, height = tools.image_guess_size_from_field_name(field) image_base64 = tools.image_process(image_base64, (width, height), crop=crop) content = base64.b64decode(image_base64) headers = http.set_safe_image_headers(headers, content) response = request.make_response(content, headers) response.status_code = status return response
def _default_image(self): image_path = modules.get_module_resource('im_livechat', 'static/src/img', 'default.png') return tools.image_process(base64.b64encode( open(image_path, 'rb').read()), size=tools.IMAGE_BIG_SIZE)
def attachment_update(self, attachment, name=None, width=0, height=0, quality=0, copy=False, **kwargs): if attachment.type == 'url': raise UserError( _("You cannot change the quality, the width or the name of an URL attachment." )) if copy: attachment = attachment.copy() data = {} if name: data['name'] = name try: data['datas'] = tools.image_process(attachment.datas, size=(width, height), quality=quality) except UserError: pass # not an image attachment.write(data) return attachment._get_media_info()
def add_data(self, name, data, quality=0, width=0, height=0, res_id=False, res_model='ir.ui.view', filters=False, **kwargs): try: data = tools.image_process(data, size=(width, height), quality=quality, verify_resolution=True) except OSError: pass # not an image attachment = self._attachment_create(name=name, data=data, res_id=res_id, res_model=res_model, filters=filters) return attachment._get_media_info()
def get_video_thumbnail(video_url): """ Computes the valid thumbnail image from given URL (or None in case of invalid URL). """ source = get_video_source_data(video_url) if source is None: return None response = None platform, video_id = source[:2] if platform == 'youtube': response = requests.get(f'https://img.youtube.com/vi/{video_id}/0.jpg', timeout=10) elif platform == 'vimeo': res = requests.get(f'http://vimeo.com/api/oembed.json?url={video_url}', timeout=10) if res.ok: data = res.json() response = requests.get(data['thumbnail_url'], timeout=10) elif platform == 'dailymotion': response = requests.get(f'https://www.dailymotion.com/thumbnail/video/{video_id}', timeout=10) elif platform == 'instagram': response = requests.get(f'https://www.instagram.com/p/{video_id}/media/?size=t', timeout=10) if response and response.ok: return image_process(response.content) return None
def _content_image( self, xmlid=None, model="ir.attachment", id=None, field="datas", filename_field="name", unique=None, filename=None, mimetype=None, download=None, width=0, height=0, crop=False, quality=0, access_token=None, placeholder="placeholder.png", **kwargs ): status, headers, image_base64 = request.env["ir.http"].binary_content( xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename, filename_field=filename_field, download=download, mimetype=mimetype, default_mimetype="image/png", access_token=access_token, ) if status in [301, 302, 304] or ( status != 200 and download ): # em230418: added 302 only return request.env["ir.http"]._response_by_status( status, headers, image_base64 ) if not image_base64: # Since we set a placeholder for any missing image, the status must be 200. In case one # wants to configure a specific 404 page (e.g. though nginx), a 404 status will cause # troubles. status = 200 image_base64 = base64.b64encode(self.placeholder(image=placeholder)) if not (width or height): width, height = odoo.tools.image_guess_size_from_field_name(field) image_base64 = image_process( image_base64, size=(int(width), int(height)), crop=crop, quality=int(quality), ) content = base64.b64decode(image_base64) headers = http.set_safe_image_headers(headers, content) response = request.make_response(content, headers) response.status_code = status return response
def get_user_profile_avatar(self, user_id, field='image_256', width=0, height=0, crop=False, **post): if field not in ('image_64', 'image_128', 'image_256'): return werkzeug.exceptions.Forbidden() can_sudo = self._check_avatar_access(user_id, **post) if can_sudo: status, headers, image_base64 = request.env['ir.http'].sudo().binary_content( model='res.users', id=user_id, field=field, default_mimetype='image/png') else: status, headers, image_base64 = request.env['ir.http'].binary_content( model='res.users', id=user_id, field=field, default_mimetype='image/png') if status == 301: return request.env['ir.http']._response_by_status(status, headers, image_base64) if status == 304: return werkzeug.wrappers.Response(status=304) if not image_base64: image_base64 = self._get_default_avatar() if not (width or height): width, height = tools.image_guess_size_from_field_name(field) image_base64 = tools.image_process(image_base64, size=(int(width), int(height)), crop=crop) content = base64.b64decode(image_base64) headers = http.set_safe_image_headers(headers, content) response = request.make_response(content, headers) response.status_code = status return response
def add_data(self, name, data, is_image, quality=0, width=0, height=0, res_id=False, res_model='ir.ui.view', **kwargs): if is_image: format_error_msg = _( "Uploaded image's format is not supported. Try with: %s", ', '.join(SUPPORTED_IMAGE_EXTENSIONS)) try: data = tools.image_process(b64decode(data), size=(width, height), quality=quality, verify_resolution=True) mimetype = guess_mimetype(data) if mimetype not in SUPPORTED_IMAGE_MIMETYPES: return {'error': format_error_msg} except UserError: # considered as an image by the browser file input, but not # recognized as such by PIL, eg .webp return {'error': format_error_msg} except ValueError as e: return {'error': e.args[0]} self._clean_context() attachment = self._attachment_create(name=name, data=data, res_id=res_id, res_model=res_model) return attachment._get_media_info()
def content_image(self, id=None, field='datas', share_id=None, width=0, height=0, crop=False, share_token=None, unique=False, **kwargs): status, headers, image_base64 = self.binary_content( id=id, field=field, share_id=share_id, share_token=share_token, unique=unique) if status != 200: return request.env['ir.http']._response_by_status( status, headers, image_base64) try: image_base64 = image_process(image_base64, size=(int(width), int(height)), crop=crop) except Exception: return request.not_found() if not image_base64: return request.not_found() content = base64.b64decode(image_base64) headers = http.set_safe_image_headers(headers, content) response = request.make_response(content, headers) response.status_code = status return response
def get_user_profile_avatar(self, user_id, field='image_large', width=0, height=0, crop=False, **post): if field not in ('image_small', 'image_medium', 'image_large'): return werkzeug.exceptions.Forbidden() can_sudo = self._check_avatar_access(user_id, **post) if can_sudo: status, headers, image_base64 = request.env['ir.http'].sudo().binary_content( model='res.users', id=user_id, field=field, default_mimetype='image/png') else: status, headers, image_base64 = request.env['ir.http'].binary_content( model='res.users', id=user_id, field=field, default_mimetype='image/png') if status == 301: return request.env['ir.http']._response_by_status(status, headers, image_base64) if status == 304: return werkzeug.wrappers.Response(status=304) if not image_base64: image_base64 = self._get_default_avatar() if not (width or height): width, height = tools.image_guess_size_from_field_name(field) image_base64 = tools.image_process(image_base64, (width, height), crop=crop) content = base64.b64decode(image_base64) headers = http.set_safe_image_headers(headers, content) response = request.make_response(content, headers) response.status_code = status return response
def attachment_update(self, attachment, name=None, width=0, height=0, quality=0, copy=False, **kwargs): if attachment.type == 'url': raise UserError( _("You cannot change the quality, the width or the name of an URL attachment." )) if copy: original = attachment attachment = attachment.copy() attachment.original_id = original # Uniquify url by adding a path segment with the id before the name if attachment.url: url_fragments = attachment.url.split('/') url_fragments.insert(-1, str(attachment.id)) attachment.url = '/'.join(url_fragments) elif attachment.original_id: attachment.datas = attachment.original_id.datas data = {} if name: data['name'] = name try: data['datas'] = tools.image_process(attachment.datas, size=(width, height), quality=quality) except UserError: pass # not an image attachment.write(data) return attachment._get_media_info()
def _content_image_get_response(self, status, headers, image_base64, model='ir.attachment', field='datas', download=None, width=0, height=0, crop=False, quality=0): if status in [301, 304] or (status != 200 and download): return self._response_by_status(status, headers, image_base64) if not image_base64: placeholder_filename = False if model in self.env: placeholder_filename = self.env[model]._get_placeholder_filename(field) placeholder_content = self._placeholder(image=placeholder_filename) # Since we set a placeholder for any missing image, the status must be 200. In case one # wants to configure a specific 404 page (e.g. though nginx), a 404 status will cause # troubles. status = 200 image_base64 = base64.b64encode(placeholder_content) if not (width or height): width, height = odoo.tools.image_guess_size_from_field_name(field) try: image_base64 = image_process(image_base64, size=(int(width), int(height)), crop=crop, quality=int(quality)) except Exception: return request.not_found() content = base64.b64decode(image_base64) headers = http.set_safe_image_headers(headers, content) response = request.make_response(content, headers) response.status_code = status return response
def test_11_image_process_size(self): """Test the size parameter of image_process.""" # Format of `tests`: (original base64 image, size parameter, expected result, text) tests = [ (self.base64_1920x1080_jpeg, (192, 108), (192, 108), "resize to given size"), (self.base64_1920x1080_jpeg, (1920, 1080), (1920, 1080), "same size, no change"), (self.base64_1920x1080_jpeg, (192, None), (192, 108), "set height from ratio"), (self.base64_1920x1080_jpeg, (0, 108), (192, 108), "set width from ratio"), (self.base64_1920x1080_jpeg, (192, 200), (192, 108), "adapt to width"), (self.base64_1920x1080_jpeg, (400, 108), (192, 108), "adapt to height"), (self.base64_1920x1080_jpeg, (3000, 2000), (1920, 1080), "don't resize above original, both set"), (self.base64_1920x1080_jpeg, (3000, False), (1920, 1080), "don't resize above original, width set"), (self.base64_1920x1080_jpeg, (None, 2000), (1920, 1080), "don't resize above original, height set"), (self.base64_1080x1920_png, (3000, 192), (108, 192), "vertical image, resize if below"), ] count = 0 for test in tests: image = tools.base64_to_image( tools.image_process(test[0], size=test[1])) self.assertEqual(image.size, test[2], test[3]) count = count + 1 self.assertEqual(count, 10, "ensure the loop is ran")
def attachment_update(self, attachment, name=None, width=0, height=0, quality=0, copy=False, **kwargs): self._clean_context() # avoid error on dispatch (caused by slug computation in route) by prioritized int route if isinstance(attachment, int): attachment = request.env['ir.attachment'].browse(attachment) if attachment.type == 'url': raise UserError( _("You cannot change the quality, the width or the name of an URL attachment." )) if copy: attachment = attachment.copy() data = {} if name: data['name'] = name try: data['datas'] = tools.image_process(attachment.datas, size=(width, height), quality=quality) except UserError: pass # not an image attachment.write(data) return attachment._get_media_info()
def _compute_thumbnail(self): for record in self: try: record.thumbnail = image_process(record.datas, size=(80, 80), crop='center') except UserError: record.thumbnail = False
def test_10_image_process_source(self): """Test the source parameter of image_process.""" self.assertFalse(tools.image_process(False), "return False if source is falsy") self.assertEqual(tools.image_process(self.img_svg), self.img_svg, "return source if format is SVG") # in the following tests, pass `quality` to force the processing with self.assertRaises( UserError, msg= "This file could not be decoded as an image file. Please try with a different file." ): tools.image_process(b'oazdazpodazdpokd', quality=95) image = img_open( tools.image_process(self.img_1920x1080_jpeg, quality=95)) self.assertEqual(image.size, (1920, 1080), "OK return the image")
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") 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)) self.assertEqual(image.format, 'JPEG', "unsupported format to JPEG")
def image_resize(self, img, width, height): """ This function is used for resize the image with specific height and width and return the resizable image. :param img: image url :param width: image width :param height: image height :return: resizable image url """ return image_process(img, size=(width, height))
def test_14_image_process_crop(self): """Test the crop parameter of image_process.""" # Optimized PNG use palette, getpixel below will return palette value. fill = 0 bg = 1 # Format of `tests`: (original base64 image, size parameter, crop parameter, res size, res color (top, bottom, left, right), text) tests = [ (self.base64_1920x1080_png, None, None, (1920, 1080), (fill, fill, bg, bg), "horizontal, verify initial"), (self.base64_1920x1080_png, (2000, 2000), 'center', (1080, 1080), (fill, fill, fill, fill), "horizontal, crop biggest possible"), (self.base64_1920x1080_png, (2000, 4000), 'center', (540, 1080), (fill, fill, fill, fill), "horizontal, size vertical, limit height"), (self.base64_1920x1080_png, (4000, 2000), 'center', (1920, 960), (fill, fill, bg, bg), "horizontal, size horizontal, limit width"), (self.base64_1920x1080_png, (512, 512), 'center', (512, 512), (fill, fill, fill, fill), "horizontal, type center"), (self.base64_1920x1080_png, (512, 512), 'top', (512, 512), (fill, fill, fill, fill), "horizontal, type top"), (self.base64_1920x1080_png, (512, 512), 'bottom', (512, 512), (fill, fill, fill, fill), "horizontal, type bottom"), (self.base64_1920x1080_png, (512, 512), 'wrong', (512, 512), (fill, fill, fill, fill), "horizontal, wrong crop value, use center"), (self.base64_1920x1080_png, (192, 0), None, (192, 108), (fill, fill, bg, bg), "horizontal, not cropped, just do resize"), (self.base64_1080x1920_png, None, None, (1080, 1920), (bg, bg, fill, fill), "vertical, verify initial"), (self.base64_1080x1920_png, (2000, 2000), 'center', (1080, 1080), (fill, fill, fill, fill), "vertical, crop biggest possible"), (self.base64_1080x1920_png, (2000, 4000), 'center', (960, 1920), (bg, bg, fill, fill), "vertical, size vertical, limit height"), (self.base64_1080x1920_png, (4000, 2000), 'center', (1080, 540), (fill, fill, fill, fill), "vertical, size horizontal, limit width"), (self.base64_1080x1920_png, (512, 512), 'center', (512, 512), (fill, fill, fill, fill), "vertical, type center"), (self.base64_1080x1920_png, (512, 512), 'top', (512, 512), (bg, fill, fill, fill), "vertical, type top"), (self.base64_1080x1920_png, (512, 512), 'bottom', (512, 512), (fill, bg, fill, fill), "vertical, type bottom"), (self.base64_1080x1920_png, (512, 512), 'wrong', (512, 512), (fill, fill, fill, fill), "vertical, wrong crop value, use center"), (self.base64_1080x1920_png, (108, 0), None, (108, 192), (bg, bg, fill, fill), "vertical, not cropped, just do resize"), ] count = 0 for test in tests: count = count + 1 # process the image image = tools.base64_to_image(tools.image_process(test[0], size=test[1], crop=test[2])) # verify size self.assertEqual(image.size, test[3], "%s - correct size" % test[5]) half_width, half_height = image.size[0] / 2, image.size[1] / 2 top, bottom, left, right = 0, image.size[1] - 1, 0, image.size[0] - 1 # verify top px = (half_width, top) self.assertEqual(image.getpixel(px), test[4][0], "%s - color top (%s, %s)" % (test[5], px[0], px[1])) # verify bottom px = (half_width, bottom) self.assertEqual(image.getpixel(px), test[4][1], "%s - color bottom (%s, %s)" % (test[5], px[0], px[1])) # verify left px = (left, half_height) self.assertEqual(image.getpixel(px), test[4][2], "%s - color left (%s, %s)" % (test[5], px[0], px[1])) # verify right px = (right, half_height) self.assertEqual(image.getpixel(px), test[4][3], "%s - color right (%s, %s)" % (test[5], px[0], px[1])) self.assertEqual(count, 2 * 9, "ensure the loop is ran")
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_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 image2jpg(env, content): if not content: return False if isinstance(content, str): content = content.encode('ascii') config_size = env['ir.config_parameter'].sudo().get_param( 'acrux_image_resize', 500) if config_size == 'original': size = (0, 0) else: size = (min(int(config_size), 1024), min(int(config_size), 1024)) try: ret = image_process(content, size=size, quality=80, output_format='JPEG') except IOError as _e: image_stream = io.BytesIO(codecs.decode(content, 'base64')) image = Image.open(image_stream) if image.mode == 'P': if 'transparency' in image.info: alpha = image.convert('RGBA').split()[-1] bg = Image.new("RGBA", image.size, (255, 255, 255, 255)) bg.paste(image, mask=alpha) image = image.convert('RGB') opt = {'format': 'JPEG', 'optimize': True, 'quality': 80} # stream = io.BytesIO() # image.save(stream, **opt) to_base64 = image_to_base64(image, **opt) ret = image_process(to_base64, size=size, quality=80, output_format='JPEG') except Exception as _e: ret = False _logger.error('Could not convert image to JPG.') return ret
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, 'P') self.assertNotEqual(image.getpixel((0, 0)), (0, 0, 0))
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)) rgba = tools.image_apply_opt(image_rgba, 'PNG') # CASE: color random, color has changed image = img_open(tools.image_process(rgba, colorize=True)) self.assertEqual(image.mode, 'RGB') self.assertNotEqual(image.getpixel((0, 0)), (0, 0, 0))
def _image_to_attachment(self, res_model, res_id, image_base64, name, datas_fname, disable_optimization=None): Attachments = request.env['ir.attachment'] if not disable_optimization: image_base64 = tools.image_process(image_base64, verify_resolution=True) attachment = Attachments.create({ 'name': name, 'datas_fname': datas_fname, 'datas': image_base64, 'public': res_model == 'ir.ui.view', 'res_id': res_id, 'res_model': res_model, }) attachment.generate_access_token() return attachment
def test_10_image_process_base64_source(self): """Test the base64_source parameter of image_process.""" self.assertFalse(tools.image_process(False), "return False if base64_source is falsy") self.assertEqual(tools.image_process(self.base64_svg), self.base64_svg, "return base64_source if format is SVG") with self.assertRaises(binascii.Error, msg="wrong base64: binascii.Error: Incorrect padding"): tools.image_process(b'oazdazpodazdpok') with self.assertRaises(OSError, msg="wrong base64: OSError: cannot identify image file"): tools.image_process(b'oazdazpodazdpokd') image = tools.base64_to_image(tools.image_process(self.base64_1920x1080_jpeg)) self.assertEqual(image.size, (1920, 1080), "OK return the image")
def create(self, vals_list): default_folder = self.env.ref( 'documents_spreadsheet.documents_spreadsheet_folder', raise_if_not_found=False) if not default_folder: default_folder = self.env['documents.folder'].search( [], limit=1, order="sequence asc") for vals in vals_list: if vals.get('handler') == 'spreadsheet': vals['folder_id'] = vals.get('folder_id', default_folder.id) if 'thumbnail' in vals: vals['thumbnail'] = image_process(vals['thumbnail'], size=(80, 80), crop='center') documents = super().create(vals_list) for document in documents: if document.handler == 'spreadsheet': self.env['spreadsheet.contributor']._update( self.env.user, document) return documents
def _image_to_attachment(self, res_model, res_id, image_base64, name, datas_fname, disable_optimization=None): Attachments = request.env['ir.attachment'] if not disable_optimization: image_base64 = tools.image_process(image_base64, verify_resolution=True) attachment = Attachments.create({ 'name': name, 'datas_fname': datas_fname, 'datas': image_base64, 'public': res_model == 'ir.ui.view', 'res_id': res_id, 'res_model': res_model, }) attachment.generate_access_token() return attachment
def test_10_image_process_base64_source(self): """Test the base64_source parameter of image_process.""" self.assertFalse(tools.image_process(False), "return False if base64_source is falsy") self.assertEqual(tools.image_process(self.base64_svg), self.base64_svg, "return base64_source if format is SVG") with self.assertRaises( binascii.Error, msg="wrong base64: binascii.Error: Incorrect padding"): tools.image_process(b'oazdazpodazdpok') with self.assertRaises( OSError, msg="wrong base64: OSError: cannot identify image file"): tools.image_process(b'oazdazpodazdpokd') image = tools.base64_to_image( tools.image_process(self.base64_1920x1080_jpeg)) self.assertEqual(image.size, (1920, 1080), "OK return the image")
def test_11_image_process_size(self): """Test the size parameter of image_process.""" # Format of `tests`: (original base64 image, size parameter, expected result, text) tests = [ (self.base64_1920x1080_jpeg, (192, 108), (192, 108), "resize to given size"), (self.base64_1920x1080_jpeg, (1920, 1080), (1920, 1080), "same size, no change"), (self.base64_1920x1080_jpeg, (192, None), (192, 108), "set height from ratio"), (self.base64_1920x1080_jpeg, (0, 108), (192, 108), "set width from ratio"), (self.base64_1920x1080_jpeg, (192, 200), (192, 108), "adapt to width"), (self.base64_1920x1080_jpeg, (400, 108), (192, 108), "adapt to height"), (self.base64_1920x1080_jpeg, (3000, 2000), (1920, 1080), "don't resize above original, both set"), (self.base64_1920x1080_jpeg, (3000, False), (1920, 1080), "don't resize above original, width set"), (self.base64_1920x1080_jpeg, (None, 2000), (1920, 1080), "don't resize above original, height set"), (self.base64_1080x1920_png, (3000, 192), (108, 192), "vertical image, resize if below"), ] count = 0 for test in tests: image = tools.base64_to_image(tools.image_process(test[0], size=test[1])) self.assertEqual(image.size, test[2], test[3]) count = count + 1 self.assertEqual(count, 10, "ensure the loop is ran")
def _handle_favicon(self, vals): if 'favicon' in vals: vals['favicon'] = tools.image_process(vals['favicon'], size=(256, 256), crop='center', output_format='ICO')
def _compute_logo_web(self): for company in self: company.logo_web = tools.image_process(company.partner_id.image, size=(180, 0))
def resize_to_48(b64source): if not b64source: b64source = base64.b64encode(Binary.placeholder()) return image_process(b64source, size=(48, 48))
def _compute_logo_web(self): for company in self: company.logo_web = tools.image_process(company.partner_id.image, size=(180, 0))
def _default_image(self): image_path = get_module_resource('hr', 'static/src/img', 'default_image.png') return tools.image_process(base64.b64encode(open(image_path, 'rb').read()), size=tools.IMAGE_BIG_SIZE)
def _handle_favicon(self, vals): if 'favicon' in vals: vals['favicon'] = tools.image_process(vals['favicon'], size=(256, 256), crop='center', output_format='ICO')