def optimize_from_buffer(data): """Optimize an image that has not been saved to a file.""" # NOTE: this optional setting defines image file extensions that should # be ignored during optimization. If it is not set or is set to an # empty list, all file types will be optimized. IGNORED_EXTENSIONS = getattr(settings, 'OPTIMIZED_IMAGE_IGNORE_EXTENSIONS', []) if not is_testing_mode(): base_extension = data.name.split('.')[-1] # If this file's extension is in the list of file extensions # that should be ignored, just return the data unmodified, # the same as we do if ``is_testing_mode()`` is True. if base_extension.lower() in [ext.lower() for ext in IGNORED_EXTENSIONS]: return data if settings.OPTIMIZED_IMAGE_METHOD == 'pillow': image = Image.open(data) bytes_io = BytesIO() if base_extension.lower() != 'jpg': extension = base_extension.upper() else: extension = 'JPEG' image.save(bytes_io, format=extension, optimize=True) data.seek(0) data.file.write(bytes_io.getvalue()) data.file.truncate() elif settings.OPTIMIZED_IMAGE_METHOD == 'tinypng': tinify.key = settings.TINYPNG_KEY optimized_buffer = tinify.from_buffer(data.file.read()).to_buffer() data.seek(0) data.file.write(optimized_buffer) data.file.truncate() return data
def save_image(): if "image" not in request.files: return jsonify({"error": "No file passed to server"}), 400 file = request.files["image"] if not file.filename: return jsonify({"error": "File must have a filename"}), 400 # Validate account try: account_id = request.form.get("account") account = PostAccount.get_account(account_id) except ValueError as e: return jsonify({"error": str(e)}), 400 # if request.args.original: # s3.upload_fileobj(file, "penn.mobile.portal/images/{}".format(account.name), file.filename) source_data = file.read() resized_image = tinify.from_buffer(source_data).resize(method="cover", width=600, height=300) aws_url = resized_image.store( service="s3", aws_access_key_id=os.environ.get("AWS_KEY"), aws_secret_access_key=os.environ.get("AWS_SECRET"), region="us-east-1", path="penn.mobile.portal/images/{}/{}".format(account.name, file.filename) ).location return jsonify({"image_url": aws_url})
def buffer_tinyfy(source_data): """source_data=source.read()""" try: # Use the Tinify API client. result_data = tinify.from_buffer(source_data).to_buffer() except tinify.AccountError as e: # print("The error message is: %s" % e.message) # Verify your API key and account limit. logging.warning(traceback.format_exc()) except tinify.ClientError as e: # Check your source image and request options. logging.warning(traceback.format_exc()) except tinify.ServerError as e: # Temporary issue with the Tinify API. logging.warning(traceback.format_exc()) except tinify.ConnectionError as e: # A network connection error occurred. logging.warning(traceback.format_exc()) except Exception as e: # Something else went wrong, unrelated to the Tinify API. logging.warning(traceback.format_exc()) else: compressions_this_month = tinify.compression_count logging.info("this month tinyfy: %s, left: %s", compressions_this_month, 500 - compressions_this_month) if compressions_this_month < 100: logging.warning("this month tinyfy: %s, left: %s", compressions_this_month, 500 - compressions_this_month) return result_data return source_data
def shrinkImageFromData(data, filename, settings={}): _, extension = os.path.splitext(filename) extension = extension.lower() api_key = getattr(django_settings, 'TINYPNG_API_KEY', None) if not api_key or extension not in ['.png', '.jpg', '.jpeg']: return dataToImageFile(data) tinify.key = api_key source = tinify.from_buffer(data) if settings.get('resize', None) == 'fit': image = Image.open(cStringIO.StringIO(data)) max_width = settings.get('max_width', django_settings.MAX_WIDTH) max_height = settings.get('max_height', django_settings.MAX_HEIGHT) min_width = settings.get('min_width', django_settings.MIN_WIDTH) min_height = settings.get('min_height', django_settings.MIN_HEIGHT) width, height = image.size if width > max_width: height = (max_width / width) * height width = max_width if height > max_height: width = (max_height / height) * width height = max_height if height < min_height: height = min_height if width < min_width: width = min_width source = source.resize( method='fit', width=int(width), height=int(height), ) elif settings.get('resize', None) == 'cover': source = source.resize( method='cover', width=settings.get('width', 300), height=settings.get('height', 300), ) try: data = source.to_buffer() except: # Retry without resizing try: data = tinify.from_buffer(data).to_buffer() except: # Just return the original data pass return dataToImageFile(data)
def shrinkImageFromData(data, filename, resize=None): _, extension = os.path.splitext(filename) extension = extension.lower() api_key = getattr(django_settings, 'TINYPNG_API_KEY', None) if not api_key or extension not in ['.png', '.jpg', '.jpeg']: return dataToImageFile(data) tinify.key = api_key source = tinify.from_buffer(data) if resize == 'fit': image = Image.open(cStringIO.StringIO(data)) width, height = image.size if width > django_settings.MAX_WIDTH: height = (django_settings.MAX_WIDTH / width) * height width = django_settings.MAX_WIDTH if height > django_settings.MAX_HEIGHT: width = (django_settings.MAX_HEIGHT / height) * width height = django_settings.MAX_HEIGHT if height < django_settings.MIN_HEIGHT: height = django_settings.MIN_HEIGHT if width < django_settings.MIN_WIDTH: width = django_settings.MIN_WIDTH source = source.resize( method='fit', width=int(width), height=int(height), ) elif resize == 'cover': print 'resize cover' source = source.resize( method='cover', width=300, height=300, ) try: data = source.to_buffer() except: # Retry without resizing try: data = tinify.from_buffer(data).to_buffer() except: # Just return the original data pass return dataToImageFile(data)
def optimize(data): """ Compress an image using the API offered by TinyPNG """ try: optimized_data = tinify.from_buffer(data).to_buffer() return optimized_data except tinify.AccountError as e: # This exception may rise, since a Free account is being used (only 500 requests/month) logger.error("There is a problem with the TinyPNG Account: {0}".format(e)) except tinify.ServerError as e: logger.error("There seem to be problems in the compression server: {0}".format(e)) except Exception as e: logger.error("The image could not be compressed: {0}".format(e)) finally: return data
def optimize_from_buffer(data): """Optimize an image that has not been saved to a file.""" # NOTE: this optional setting defines image file extensions that should # be ignored during optimization. If it is not set or is set to an # empty list, all file types will be optimized. IGNORED_EXTENSIONS = getattr(settings, 'OPTIMIZED_IMAGE_IGNORE_EXTENSIONS', []) if not is_testing_mode(): base_extension = data.name.split('.')[-1] # If this file's extension is in the list of file extensions # that should be ignored, just return the data unmodified, # the same as we do if ``is_testing_mode()`` is True. if base_extension.lower() in [ ext.lower() for ext in IGNORED_EXTENSIONS ]: return data if settings.OPTIMIZED_IMAGE_METHOD == 'pillow': image = Image.open(data) bytes_io = BytesIO() if base_extension.lower() != 'jpg': extension = base_extension.upper() else: extension = 'JPEG' image.save(bytes_io, format=extension, optimize=True) data.seek(0) data.file.write(bytes_io.getvalue()) data.file.truncate() elif settings.OPTIMIZED_IMAGE_METHOD == 'tinypng': tinify.key = settings.TINYPNG_KEY optimized_buffer = tinify.from_buffer(data.file.read()).to_buffer() data.seek(0) data.file.write(optimized_buffer) data.file.truncate() elif settings.OPTIMIZED_IMAGE_METHOD == 'justtesting': # Make a tiny image and use that instead of the input image. # (justtesting is NOT a publicly allowed value, it's just for internal testing.) bytes_io = BytesIO() Image.new('RGB', (10, 10), "blue").save(bytes_io, format="JPEG") data.seek(0) data.file.write(bytes_io.getvalue()) data.file.truncate() # Else - just don't change it else: return data # We optimized it - fix the computed size data.size = data.file.tell() return data
def post_tinyjpg(source, db): try: get_key = api_keys.query.filter(api_keys.counter < 500).first() tinify.key = get_key.key except Exception: new_api_key(db) get_key = api_keys.query.filter(api_keys.counter == 0).first() tinify.key = get_key.key source_data = source.read() result_data = tinify.from_buffer(source_data).to_buffer() get_key.counter = get_key.counter + 1 db.session.commit() response = io.BytesIO(result_data) response.filename = source.filename return response
def compressTinypng(cls, filePath): """ 使用tinypng对图片进行压缩 :param filePath 待压缩的文件路径 :rtype: 压缩后的文件内容 """ try: import tinify tinify.key = 'J2N7fcrkRwEdPe2LEjfOS6dINwTOeLJj' with open(filePath, 'rb') as f: buffer = f.read() result = tinify.from_buffer(buffer).to_buffer() print('成功压缩图片: ' + filePath) return result except Exception as e: return False
def compress_tiny_png(cls, file_path): """ 使用tinypng对图片进行压缩 :param file_path 待压缩的文件路径 :rtype: 压缩后的文件内容 """ try: import tinify key = Config.get_compress_config(ConfigName.COMPRESS_TINIFY_KEY) if not key: return False tinify.key = key with open(file_path, 'rb') as f: buffer = f.read() result = tinify.from_buffer(buffer).to_buffer() return result except Exception as e: return False
def compressing_image_overwrite_source_file(source_picture_file_location): ''' 传入一个图片的地址,图片经过压缩后,覆盖原来的图片文件 ''' tinify.key = _load_tinyPNG_api_key() try: with open(source_picture_file_location, 'rb') as source: source_data = source.read() result_data = tinify.from_buffer(source_data).to_buffer() with open(source_picture_file_location, "wb") as source: source.write(result_data) except: try: compressing_image_overwrite_source_file( source_picture_file_location) except: return
def image_optimizer(image_data): """Optimize an image that has not been saved to a file.""" if OPTIMIZED_IMAGE_METHOD == 'pillow': image = Image.open(image_data) bytes_io = BytesIO() extension = image.format image.save(bytes_io, format=extension, optimize=True) image_data.seek(0) image_data.file.write(bytes_io.getvalue()) image_data.file.truncate() elif OPTIMIZED_IMAGE_METHOD == 'tinypng': # disable warning info requests.packages.urllib3.disable_warnings() tinify.key = TINYPNG_KEY optimized_buffer = tinify.from_buffer( image_data.file.read()).to_buffer() image_data.seek(0) image_data.file.write(optimized_buffer) image_data.file.truncate() return image_data
def optimize_from_buffer(data): """Optimize an image that has not been saved to a file.""" if not is_testing_mode(): if settings.OPTIMIZED_IMAGE_METHOD == 'pillow': image = Image.open(data) bytes_io = BytesIO() if data.name.split('.')[-1].lower() != 'jpg': extension = data.name.split('.')[-1].upper() else: extension = 'JPEG' image.save(bytes_io, format=extension, optimize=True) data.seek(0) data.file.write(bytes_io.getvalue()) data.file.truncate() elif settings.OPTIMIZED_IMAGE_METHOD == 'tinypng': tinify.key = settings.TINYPNG_KEY optimized_buffer = tinify.from_buffer(data.file.read()).to_buffer() data.seek(0) data.file.write(optimized_buffer) data.file.truncate() return data
def convert_for_product(product, old): # has original if not product.image_original: product.image_compressed = None return # make sure image has been changed if product.image_original == old.image_original and old.image_compressed_with_tinypng: return img = Image.open(product.image_original) bg_color = int(IMAGE_BACKGROUND_COLOR[1:3], base=16), int(IMAGE_BACKGROUND_COLOR[3:5], base=16), int(IMAGE_BACKGROUND_COLOR[5:7], base=16) img = remove_transparency(img, bg_color=bg_color) try: img_io = StringIO.StringIO() img.save(img_io, format='PNG') source = tinify.from_buffer(img_io.getvalue()) data = source.to_buffer() img_content = ContentFile(data, product.image_original.name) product.image_compressed = img_content product.image_compressed_with_tinypng = True except tinify.Error: log.exception("Unable to use TinyPNG for image, fallback to server's algorithm") # This gives much more coarse results then TinyPNG # See API https://tinypng.com/developers/reference/python img_8bit = img.convert( mode='P', palette=Image.ADAPTIVE, colors=256, ) img_io = StringIO.StringIO() img_8bit.save( img_io, format='PNG', optimize=True, ) img_content = ContentFile(img_io.getvalue(), product.image_original.name) product.image_compressed = img_content product.image_compressed_with_tinypng = False
import tinify import os import os.path tinify.key = "your AppKey" # AppKey fromFilePath = "/Users/tangjr/Desktop/test1" # 源路径 toFilePath = "/Users/tangjr/Desktop/test2" # 输出路径 for root, dirs, files in os.walk(fromFilePath): for name in files: fileName, fileSuffix = os.path.splitext(name) if fileSuffix == '.png' or fileSuffix == '.jpg': toFullPath = toFilePath + root[len(fromFilePath):] toFullName = toFullPath + '/' + name if os.path.isdir(toFullPath): pass else: os.mkdir(toFullPath) with open(toFullName, 'rb') as source: source_data = source.read() result_data = tinify.from_buffer(source_data).to_buffer()
def optimize_legacy_images_in_model_fields(list_of_models, verbosity=0): """ Call this function to go through models and optimize images. This is best done after changing your model fields from ImageField to OptimizedImageField, and migrating the models. This function goes through the list_of_models in the params, finds all of their OptimizedImageFields, and optimizes the images in those fields. Note: there is a 500 image/month limit on a free TinyPNG API key, so use this function wisely. """ for model in list_of_models: if verbosity == 1: sys.stdout.write('\nOptimizing for model: {}'.format(model)) field_names_to_optimize = [] for field in model._meta.get_fields(): if type(field) == OptimizedImageField: field_names_to_optimize.append(field.attname) if verbosity == 1: sys.stdout.write('\nWill check the following fields: {}'.format( field_names_to_optimize)) model_instances = model.objects.all() for model_instance in model_instances: for field_name in field_names_to_optimize: if verbosity == 1: sys.stdout.write( '\nChecking for instance id {} field {}'.format( model_instance.pk, field_name)) # If the instance's field has an image, optimize it image_file = getattr(model_instance, field_name) if image_file.name not in [None, '']: if verbosity == 1: sys.stdout.write('\nImage found. Optimizing.') try: # Use the OPTIMIZED_IMAGE_METHOD from settings to determine # which way to optimize the image file. if settings.OPTIMIZED_IMAGE_METHOD == 'pillow': # Open the image input_file = BytesIO(image_file.read()) image = Image.open(input_file) output_file = BytesIO() # Find the extension of the file to pass to PIL.Image.save() if image_file.name.split('.')[-1].lower() != 'jpg': extension = image_file.name.split( '.')[-1].upper() else: extension = 'JPEG' # Optimize the image image.save(output_file, format=extension, optimize=True) # Save the image in place of the unoptimized one content_file = ContentFile(output_file.getvalue()) image_name = os.path.relpath( image_file.name, image_file.field.upload_to) image_file.save(image_name, content_file) elif settings.OPTIMIZED_IMAGE_METHOD == 'tinypng': tinify.key = settings.TINYPNG_KEY # Use TinyPNG to optimize the file from a buffer optimized_buffer = tinify.from_buffer( image_file.read()).to_buffer() # Save the image in place of the unoptimized one content_file = ContentFile(optimized_buffer) image_name = os.path.relpath( image_file.name, image_file.field.upload_to) image_file.save(image_name, content_file) except: # If the optimization failed for any reason, write this # to stdout. sys.stdout.write( '\nOptimization failed for {}.'.format( image_file.name)) if verbosity == 1: sys.stdout.write('\nOptimized and saved image.')
def test_should_return_source(self): httpretty.register_uri(httpretty.POST, 'https://api.tinify.com/shrink', location='https://api.tinify.com/some/location') tinify.key = 'valid' self.assertIsInstance(tinify.from_buffer('png file'), tinify.Source)
def make_compress_img(self, buffer_img, imgp): """压缩图片文件事件处理函数""" global APIKEY tinify.key = APIKEY tinify.from_buffer(buffer_img).to_file(imgp)
def load_buffer(self, buffer): self._tiny_ref = tinify.from_buffer(buffer.read())
import tinify import base64 with open("real.jpg", "rb") as imageFile: str = base64.b64encode(imageFile.read()) print(str) with open("real.jpg", 'rb') as source: source_data = source.read() result_data = tinify.from_buffer(source_data).to_buffer() print(result_data)
def tinify_bake_io(img: bytes, resolution: int) -> bytes: source = tinify.from_buffer(img) if resolution > 0: return source.resize(method='scale', width=resolution).to_buffer() else: return source.to_buffer()
def image_optimizer(image_data, output_size=None, resize_method=None): """Optimize an image that has not been saved to a file.""" if OPTIMIZED_IMAGE_METHOD == 'pillow': image = Image.open(image_data) bytes_io = BytesIO() file_name = image_data.name extension = get_file_extension(file_name) # If output_size is set, resize the image with the selected # resize_method. 'thumbnail' is used by default if output_size is not None: if resize_method is None: pass elif resize_method is 'thumbnail': image = resizeimage.resize_thumbnail(image, output_size, resample=Image.LANCZOS) elif resize_method is 'cover': image = resizeimage.resize_cover(image, output_size, validate=False) else: raise Exception( 'optimized_image_resize_method misconfigured, it\'s value must be \'thumbnail\', \'cover\' or None' ) output_image = Image.new('RGBA', output_size, BACKGROUND_TRANSPARENT) output_image_center = (int((output_size[0] - image.size[0]) / 2), int((output_size[1] - image.size[1]) / 2)) output_image.paste(image, output_image_center) # If output_size is None the output_image would be the same as source else: output_image = image # If the file extension is JPEG, convert the output_image to RGB if extension == 'JPEG': output_image = output_image.convert("RGB") output_image.save(bytes_io, format=extension, optimize=True) image_data.seek(0) image_data.file.write(bytes_io.getvalue()) image_data.file.truncate() elif OPTIMIZED_IMAGE_METHOD == 'tinypng': # disable warning info requests.packages.urllib3.disable_warnings() tinify.key = TINYPNG_KEY optimized_buffer = tinify.from_buffer( image_data.file.read()).to_buffer() image_data.seek(0) image_data.file.write(optimized_buffer) image_data.file.truncate() return image_data
def optimize_legacy_images_in_model_fields(list_of_models, verbosity=0): """ Call this function to go through models and optimize images. This is best done after changing your model fields from ImageField to OptimizedImageField, and migrating the models. This function goes through the list_of_models in the params, finds all of their OptimizedImageFields, and optimizes the images in those fields. Note: there is a 500 image/month limit on a free TinyPNG API key, so use this function wisely. """ # NOTE: this optional setting defines image file extensions that should # be ignored during optimization. If it is not set or is set to an # empty list, all file types will be optimized. IGNORED_EXTENSIONS = getattr(settings, 'OPTIMIZED_IMAGE_IGNORE_EXTENSIONS', []) for model in list_of_models: if verbosity == 1: sys.stdout.write('\nOptimizing for model: {}'.format(model)) field_names_to_optimize = [] for field in model._meta.get_fields(): if type(field) == OptimizedImageField: field_names_to_optimize.append(field.attname) if verbosity == 1: sys.stdout.write('\nWill check the following fields: {}'.format(field_names_to_optimize)) model_instances = model.objects.all() for model_instance in model_instances: for field_name in field_names_to_optimize: if verbosity == 1: sys.stdout.write('\nChecking for instance id {} field {}'.format(model_instance.pk, field_name)) # If the instance's field has an image, optimize it image_file = getattr(model_instance, field_name) image_file_extension = image_file.name.split('.')[-1] # If the file extension is in the list of file extensions # that should be ignored for optimization, exit this iteration # of the inner ``for`` loop, skipping the file. if image_file_extension.lower() in [ext.lower() for ext in IGNORED_EXTENSIONS]: sys.stdout.write( '\nImage has extension {ext}. Ignoring.'.format(ext=image_file_extension) ) continue if image_file.name not in [None, '']: if verbosity == 1: sys.stdout.write('\nImage found. Optimizing.') try: # Use the OPTIMIZED_IMAGE_METHOD from settings to determine # which way to optimize the image file. if settings.OPTIMIZED_IMAGE_METHOD == 'pillow': # Open the image input_file = BytesIO(image_file.read()) image = Image.open(input_file) output_file = BytesIO() # Find the extension of the file to pass to PIL.Image.save() if image_file_extension.lower() != 'jpg': extension = image_file_extension.upper() else: extension = 'JPEG' # Optimize the image image.save(output_file, format=extension, optimize=True) # Save the image in place of the unoptimized one content_file = ContentFile(output_file.getvalue()) image_name = os.path.relpath(image_file.name, image_file.field.upload_to) image_file.save(image_name, content_file) elif settings.OPTIMIZED_IMAGE_METHOD == 'tinypng': tinify.key = settings.TINYPNG_KEY # Use TinyPNG to optimize the file from a buffer optimized_buffer = tinify.from_buffer(image_file.read()).to_buffer() # Save the image in place of the unoptimized one content_file = ContentFile(optimized_buffer) image_name = os.path.relpath(image_file.name, image_file.field.upload_to) image_file.save(image_name, content_file) except: # If the optimization failed for any reason, write this # to stdout. sys.stdout.write('\nOptimization failed for {}.'.format(image_file.name)) if verbosity == 1: sys.stdout.write('\nOptimized and saved image.')
def shrinkImageFromData(data, filename, settings={}): """ Optimize images with TinyPNG """ _, extension = os.path.splitext(filename) extension = extension.lower() api_key = getattr(django_settings, 'TINYPNG_API_KEY', None) if not api_key or extension not in ['.png', '.jpg', '.jpeg']: return dataToImageFile(data) tinify.key = api_key source = tinify.from_buffer(data) if settings.get('resize', None) == 'fit': image = Image.open(cStringIO.StringIO(data)) max_width = settings.get('max_width', django_settings.MAX_WIDTH) max_height = settings.get('max_height', django_settings.MAX_HEIGHT) min_width = settings.get('min_width', django_settings.MIN_WIDTH) min_height = settings.get('min_height', django_settings.MIN_HEIGHT) width, height = image.size if width > max_width: height = (max_width / width) * height width = max_width if height > max_height: width = (max_height / height) * width height = max_height if height < min_height: height = min_height if width < min_width: width = min_width source = source.resize( method='fit', width=int(width), height=int(height), ) elif settings.get('resize', None) == 'cover': source = source.resize( method='cover', width=settings.get('width', 300), height=settings.get('height', 300), ) elif settings.get('resize', None) == 'scale': if settings.get('width', None): source = source.resize( method='scale', width=settings['width'], ) if settings.get('height', None): source = source.resize( method='scale', height=settings['height'], ) elif settings.get('resize', None) == 'thumb': source = source.resize( method='thumb', width=settings.get('width', 300), height=settings.get('height', 300), ) try: data = source.to_buffer() except: # Retry without resizing try: data = tinify.from_buffer(data).to_buffer() except: # Just return the original data pass return dataToImageFile(data)
def image_optimizer(image_data, output_size=None, resize_method=None): """ Optimize an image that has not been saved to a file. :param `image_data` is image data, e.g from request.FILES['image'] :param `output_size` is float pixel scale of image (width, height) or None, e.g: (400, 300) :param `resize_method` is string resize method, choices are: None, "thumbnail", or "cover". :return optimized image data. """ if OPTIMIZED_IMAGE_METHOD == 'pillow': image = Image.open(image_data) bytes_io = BytesIO() extension = get_image_extension(image) # If output_size is set, resize the image with the selected # resize_method. 'thumbnail' is used by default if output_size is not None: if resize_method not in ('thumbnail', 'cover', None): message = 'optimized_image_resize_method misconfigured, it\'s value must be \'thumbnail\', \'cover\' or None' raise Exception(message) elif resize_method is 'thumbnail': image = resizeimage.resize_thumbnail(image, output_size, resample=Image.LANCZOS) elif resize_method is 'cover': image = resizeimage.resize_cover(image, output_size, validate=False) output_image = Image.new('RGBA', output_size, BACKGROUND_TRANSPARENT) output_image_center = (int((output_size[0] - image.size[0]) / 2), int((output_size[1] - image.size[1]) / 2)) output_image.paste(image, output_image_center) else: # If output_size is None the output_image would be the same as source output_image = image # If the file extension is JPEG, convert the output_image to RGB if extension == 'JPEG': output_image = output_image.convert('RGB') output_image.save(bytes_io, format=extension, optimize=True) image_data.seek(0) image_data.file.write(bytes_io.getvalue()) image_data.file.truncate() elif OPTIMIZED_IMAGE_METHOD == 'tinypng': # disable warning info requests.packages.urllib3.disable_warnings() # just info for people if any([output_size, resize_method]): message = '[django-image-optimizer] "output_size" and "resize_method" only for OPTIMIZED_IMAGE_METHOD="pillow"' logging.info(message) tinify.key = TINYPNG_KEY optimized_buffer = tinify.from_buffer( image_data.file.read()).to_buffer() image_data.seek(0) image_data.file.write(optimized_buffer) image_data.file.truncate() return image_data
def optimize_legacy_images_in_model_fields(list_of_models, verbosity=0): """ Call this function to go through models and optimize images. This is best done after changing your model fields from ImageField to OptimizedImageField, and migrating the models. This function goes through the list_of_models in the params, finds all of their OptimizedImageFields, and optimizes the images in those fields. Note: there is a 500 image/month limit on a free TinyPNG API key, so use this function wisely. """ # NOTE: this optional setting defines image file extensions that should # be ignored during optimization. If it is not set or is set to an # empty list, all file types will be optimized. IGNORED_EXTENSIONS = getattr(settings, 'OPTIMIZED_IMAGE_IGNORE_EXTENSIONS', []) for model in list_of_models: if verbosity == 1: sys.stdout.write('\nOptimizing for model: {}'.format(model)) field_names_to_optimize = [] for field in model._meta.get_fields(): if type(field) == OptimizedImageField: field_names_to_optimize.append(field.attname) if verbosity == 1: sys.stdout.write('\nWill check the following fields: {}'.format( field_names_to_optimize)) model_instances = model.objects.all() for model_instance in model_instances: for field_name in field_names_to_optimize: if verbosity == 1: sys.stdout.write( '\nChecking for instance id {} field {}'.format( model_instance.pk, field_name)) # If the instance's field has an image, optimize it image_file = getattr(model_instance, field_name) if not image_file or not image_file.name: continue image_file_extension = image_file.name.split('.')[-1] if not image_file_extension: image_file_extension = "png" # If the file extension is in the list of file extensions # that should be ignored for optimization, exit this iteration # of the inner ``for`` loop, skipping the file. if image_file_extension.lower() in [ ext.lower() for ext in IGNORED_EXTENSIONS ]: sys.stdout.write( '\nImage has extension {ext}. Ignoring.'.format( ext=image_file_extension)) continue if image_file.name not in [None, '']: if verbosity == 1: sys.stdout.write('\nImage found. Optimizing.') try: # Use the OPTIMIZED_IMAGE_METHOD from settings to determine # which way to optimize the image file. if settings.OPTIMIZED_IMAGE_METHOD == 'pillow': # Open the image input_file = BytesIO(image_file.read()) image = Image.open(input_file) output_file = BytesIO() # Find the extension of the file to pass to PIL.Image.save() if image_file_extension.lower() != 'jpg': extension = image_file_extension.upper() else: extension = 'JPEG' # Optimize the image image.save(output_file, format=extension, optimize=True) # Save the image in place of the unoptimized one content_file = ContentFile(output_file.getvalue()) image_name = os.path.relpath(image_file.name) image_file.save(image_name, content_file) elif settings.OPTIMIZED_IMAGE_METHOD == 'tinypng': tinify.key = settings.TINYPNG_KEY # Use TinyPNG to optimize the file from a buffer optimized_buffer = tinify.from_buffer( image_file.read()).to_buffer() # Save the image in place of the unoptimized one content_file = ContentFile(optimized_buffer) image_name = os.path.relpath(image_file.name) image_file.save(image_name, content_file) except: if is_testing_mode(): # This shouldn't actually happen, so if testing, let the exception continue # up the call chain so it makes the test fail. raise # If the optimization failed for any reason, write this # to stdout. sys.stdout.write( '\nOptimization failed for {}.'.format( image_file.name)) sys.stdout.write(traceback.format_exc()) if verbosity == 1: sys.stdout.write('\nOptimized and saved image.')