def generate_image(inpath, outpath, width=None, height=None, format=JPEG, fill=False, upscale=True, anchor=None, quality=80, progressive=True, placeholder_reason=None): mkdir_p(outpath.rpartition('/')[0]) if not os.path.isfile(inpath): if placeholder_reason: img = get_placeholder(width, height, placeholder_reason) else: raise TypeError(u'No such file {}'.format(inpath)) else: img = Image.open(inpath) processor_kwargs = dict(width=width, height=height, upscale=upscale) if fill: processor_kwargs['anchor'] = anchor ResizeMethod = ResizeToFill if fill else ResizeToFit processor = ResizeMethod(**processor_kwargs) new_img = processor.process(img) assert (not os.path.exists(outpath), 'Path to save to already exists') options = {} if format == JPEG: options.update({'quality': int(quality), 'progressive': progressive}) with open(outpath, 'w') as outfile: save_image(new_img, outfile, format=format, options=options)
def create_resizes_of_image(image): """ Create the web and thumb, and return a list of (source, dest) images to be transferred to the fileserver, including the original. """ event = image.event year = event.startdate.split('-')[0] dest_media_folder = os.path.join('archive', year, slugify(event.name)) # Add original to files to be transferred files_to_transfer = [(image.original.path, os.path.join(dest_media_folder, '%d-original.jpg' % image.id))] # Do the actual conversion pil_img = PILImage.open(image.original) thumb = ImageOps.fit(pil_img, (75, 75), PILImage.ANTIALIAS) #thumb = ResizeToFit(75, 75).process(pil_img) websize = ResizeToFit(1500, 800, upscale=False).process(pil_img) for size, appendix in [(thumb, 'thumb'), (websize, 'web')]: filename = '%s-%s.jpg' % (image.id, appendix) local_path = os.path.join(settings.MEDIA_ROOT, 'local', 'raw-archive-images', filename) if not os.path.exists(os.path.dirname(local_path)): os.mkdir(os.path.dirname(local_path)) save_image(size, local_path, 'jpeg') files_to_transfer.append( (local_path, os.path.join(dest_media_folder, filename))) # Set the new URL to the original image image.original = None image.original = dest_media_folder + '/%d-original.jpg' % image.id return files_to_transfer
def create_resizes_of_image(image): """ Create the web and thumb, and return a list of (source, dest) images to be transferred to the fileserver, including the original. """ event = image.event year = event.startdate.split('-')[0] dest_media_folder = os.path.join('archive', year, slugify(event.name)) # Add original to files to be transferred files_to_transfer = [ (image.original.path, os.path.join(dest_media_folder, '%d-original.jpg' % image.id)) ] # Do the actual conversion pil_img = PILImage.open(image.original) thumb = ImageOps.fit(pil_img, (75, 75), PILImage.ANTIALIAS) #thumb = ResizeToFit(75, 75).process(pil_img) websize = ResizeToFit(1500, 800, upscale=False).process(pil_img) for size, appendix in [(thumb, 'thumb'), (websize, 'web')]: filename = '%s-%s.jpg' % (image.id, appendix) local_path = os.path.join(settings.MEDIA_ROOT, 'local', 'raw-archive-images', filename) if not os.path.exists(os.path.dirname(local_path)): os.mkdir(os.path.dirname(local_path)) save_image(size, local_path, 'jpeg') files_to_transfer.append( (local_path, os.path.join(dest_media_folder, filename)) ) # Set the new URL to the original image image.original = None image.original = dest_media_folder + '/%d-original.jpg' % image.id return files_to_transfer
def generate_thumbnail( text, outname, box, bg_color=DEFAULT_CONFIG['thumb_bg_color'], font=DEFAULT_CONFIG['thumb_font'], font_color=DEFAULT_CONFIG['thumb_font_color'], font_size=DEFAULT_CONFIG['thumb_font_size'], options=None, ): """Create a thumbnail image.""" kwargs = {} if font: kwargs['font'] = ImageFont.truetype(font, font_size) if font_color: kwargs['fill'] = font_color img = PILImage.new("RGB", box, bg_color) anchor = (box[0] // 2, box[1] // 2) d = ImageDraw.Draw(img) logger.info(f"kwargs: {kwargs}") d.text(anchor, text, anchor='mm', **kwargs) outformat = 'JPEG' logger.info('Save thumnail image: %s (%s)', outname, outformat) save_image(img, outname, outformat, options=options, autoconvert=True)
def generate_image(source, outname, settings, options=None): """Image processor, rotate and resize the image. :param source: path to an image :param outname: output filename :param settings: settings dict :param options: dict with PIL options (quality, optimize, progressive) """ logger = logging.getLogger(__name__) if settings['use_orig']: utils.copy(source, outname, symlink=settings['orig_link']) return img = PILImage.open(source) original_format = img.format if settings['copy_exif_data'] and settings['autorotate_images']: logger.warning("The 'autorotate_images' and 'copy_exif_data' settings " "are not compatible because Sigal can't save the " "modified Orientation tag.") # Preserve EXIF data if settings['copy_exif_data'] and _has_exif_tags(img): if options is not None: options = deepcopy(options) else: options = {} options['exif'] = img.info['exif'] # Rotate the img, and catch IOError when PIL fails to read EXIF if settings['autorotate_images']: try: img = Transpose().process(img) except (IOError, IndexError): pass # Resize the image if settings['img_processor']: try: logger.debug('Processor: %s', settings['img_processor']) processor_cls = getattr(pilkit.processors, settings['img_processor']) except AttributeError: logger.error('Wrong processor name: %s', settings['img_processor']) sys.exit() processor = processor_cls(*settings['img_size'], upscale=False) img = processor.process(img) # signal.send() does not work here as plugins can modify the image, so we # iterate other the receivers to call them with the image. for receiver in signals.img_resized.receivers_for(img): img = receiver(img, settings=settings) outformat = img.format or original_format or 'JPEG' logger.debug(u'Save resized image to {0} ({1})'.format(outname, outformat)) save_image(img, outname, outformat, options=options, autoconvert=True)
def generate_image(inpath, outpath, width=None, height=None, format=JPEG, fill=False, upscale=True, anchor=None, quality=80, progressive=True, placeholder_reason=None): mkdir_p(outpath.rpartition('/')[0]) if not os.path.isfile(inpath): if placeholder_reason: img = get_placeholder(width, height, placeholder_reason) else: raise TypeError(u'No such file {}'.format(inpath)) else: img = Image.open(inpath) processor_kwargs = dict(width=width, height=height, upscale=upscale) if fill: processor_kwargs['anchor'] = anchor ResizeMethod = ResizeToFill if fill else ResizeToFit processor = ResizeMethod(**processor_kwargs) new_img = processor.process(img) assert (not os.path.exists(outpath), 'Path to save to already exists') options = {} if format == JPEG: options.update({'quality': int(quality), 'progressive': progressive}) with open(outpath, 'wb') as outfile: save_image(new_img, outfile, format=format, options=options)
def url(self): """ Returns the final url for this version of the image. If it doesn't exists, it generates it""" uploads_dir = self.get_uploads_dir() img = Image.open(os.path.join(uploads_dir, self.source)) new_image_filename = self.generate_filename(img) # generate the full names and create directories if necesary base_cache_dir = os.path.join('cache', self.model, str(self.id)) cache_dir = os.path.join( uploads_dir, base_cache_dir) cache_filename = os.path.join( cache_dir, new_image_filename) if not os.path.exists(cache_dir): mkdir_p(cache_dir) # Check if the generated image already existed if os.path.exists(cache_filename): return "/cache/" + self.model + "/" + str(self.id) + "/" + new_image_filename else: # we process the image and save it on the cache folder processor = ProcessorPipeline(self.processors) new_image = processor.process(img) utils.save_image(new_image, cache_filename, self.format, self.options) return os.path.join(base_cache_dir, new_image_filename)
def generate_image(source, outname, settings, options=None): """Image processor, rotate and resize the image. :param source: path to an image :param outname: output filename :param settings: settings dict :param options: dict with PIL options (quality, optimize, progressive) """ logger = logging.getLogger(__name__) img = PILImage.open(source) original_format = img.format if settings["copy_exif_data"] and settings["autorotate_images"]: logger.warning( "The 'autorotate_images' and 'copy_exif_data' settings " "are not compatible because Sigal can't save the " "modified Orientation tag." ) # Preserve EXIF data if settings["copy_exif_data"] and _has_exif_tags(img): if options is not None: options = deepcopy(options) else: options = {} options["exif"] = img.info["exif"] # Rotate the img, and catch IOError when PIL fails to read EXIF if settings["autorotate_images"]: try: img = Transpose().process(img) except (IOError, IndexError): pass # Resize the image if settings["img_processor"]: try: logger.debug("Processor: %s", settings["img_processor"]) processor_cls = getattr(pilkit.processors, settings["img_processor"]) except AttributeError: logger.error("Wrong processor name: %s", settings["img_processor"]) sys.exit() processor = processor_cls(*settings["img_size"], upscale=False) img = processor.process(img) # Adjust the image after resizing img = Adjust(**settings["adjust_options"]).process(img) if settings["copyright"]: add_copyright(img, settings["copyright"]) outformat = img.format or original_format or "JPEG" logger.debug(u"Save resized image to {0} ({1})".format(outname, outformat)) save_image(img, outname, outformat, options=options, autoconvert=True)
def test_save_with_filename(): """ Test that ``save_image`` accepts filename strings (not just file objects). This is a test for GH-8. """ im = create_image() outfile = NamedTemporaryFile() save_image(im, outfile.name, 'JPEG') outfile.close()
def resize_image(path, output, side=360): w, h, img = calculate_size(path, side) if img.format.lower() == 'gif': resize_gif(path, output, w, h) return w, h processor = processors.SmartResize(w, h) new_img = processor.process(img) utils.save_image(new_img, output, img.format) return w, h
def generate_image(source, outname, settings, options=None): """Image processor, rotate and resize the image. :param source: path to an image :param outname: output filename :param settings: settings dict :param options: dict with PIL options (quality, optimize, progressive) """ logger = logging.getLogger(__name__) img = PILImage.open(source) original_format = img.format # Preserve EXIF data if settings['copy_exif_data'] and _has_exif_tags(img): if options is not None: options = deepcopy(options) else: options = {} options['exif'] = img.info['exif'] # Rotate the img, and catch IOError when PIL fails to read EXIF try: img = Transpose().process(img) except (IOError, IndexError): pass # Resize the image if settings['img_processor']: try: logger.debug('Processor: %s', settings['img_processor']) processor_cls = getattr(pilkit.processors, settings['img_processor']) except AttributeError: logger.error('Wrong processor name: %s', settings['img_processor']) sys.exit() processor = processor_cls(*settings['img_size'], upscale=False) img = processor.process(img) # Adjust the image after resizing img = Adjust(**settings['adjust_options']).process(img) if settings['copyright']: add_copyright(img, settings['copyright']) outformat = img.format or original_format or 'JPEG' logger.debug(u'Save resized image to {0} ({1})'.format(outname, outformat)) save_image(img, outname, outformat, options=options, autoconvert=True)
def generate_thumbnail(source, outname, box, delay, fit=True, options=None): """Create a thumbnail image.""" logger = logging.getLogger(__name__) img = PILImage.open(source) original_format = img.format if fit: img = ImageOps.fit(img, box, PILImage.ANTIALIAS) else: img.thumbnail(box, PILImage.ANTIALIAS) outformat = img.format or original_format or 'JPEG' logger.debug(u'Save thumnail image: {0} ({1})'.format(outname, outformat)) save_image(img, outname, outformat, options=options, autoconvert=True)
def generate_thumbnail(source, outname, box, fit=True, options=None): """Create a thumbnail image.""" logger = logging.getLogger(__name__) img = PILImage.open(source) original_format = img.format if fit: img = ImageOps.fit(img, box, PILImage.ANTIALIAS) else: img.thumbnail(box, PILImage.ANTIALIAS) outformat = img.format or original_format or "JPEG" logger.debug(u"Save thumnail image: {0} ({1})".format(outname, outformat)) save_image(img, outname, outformat, options=options, autoconvert=True)
def generate_thumbnail(source, outname, box, fit=True, options=None): "Create a thumbnail image" logger = logging.getLogger(__name__) img = PILImage.open(source) original_format = img.format if fit: img = ImageOps.fit(img, box, PILImage.ANTIALIAS) else: img.thumbnail(box, PILImage.ANTIALIAS) outformat = img.format or original_format or 'JPEG' logger.debug(u'Save thumnail image to {0} ({1})'.format(outname, outformat)) with open(outname, 'w') as fp: save_image(img, fp, outformat, options=options, autoconvert=True)
def generate_image(source, outname, settings, options=None): """Image processor, rotate and resize the image. :param source: path to an image :param outname: output filename :param settings: settings dict :param options: dict with PIL options (quality, optimize, progressive) """ logger = logging.getLogger(__name__) img = PILImage.open(source) original_format = img.format # Preserve EXIF data if settings["copy_exif_data"] and _has_exif_tags(img): options = options or {} options["exif"] = img.info["exif"] # Rotate the img, and catch IOError when PIL fails to read EXIF try: img = Transpose().process(img) except IOError: pass # Resize the image if settings["img_processor"]: try: logger.debug("Processor: %s", settings["img_processor"]) processor_cls = getattr(pilkit.processors, settings["img_processor"]) except AttributeError: logger.error("Wrong processor name: %s", settings["img_processor"]) sys.exit() processor = processor_cls(*settings["img_size"], upscale=False) img = processor.process(img) # Adjust the image after resizing img = Adjust(**settings["adjust_options"]).process(img) if settings["copyright"]: add_copyright(img, settings["copyright"]) outformat = img.format or original_format or "JPEG" logger.debug(u"Save resized image to {0} ({1})".format(outname, outformat)) with open(outname, "w") as fp: save_image(img, fp, outformat, options=options, autoconvert=True)
def generate_thumbnail(source, outname, box, fit=True, options=None, thumb_fit_centering=(0.5, 0.5)): """Create a thumbnail image.""" logger = logging.getLogger(__name__) img = _read_image(source) original_format = img.format if fit: img = ImageOps.fit(img, box, PILImage.ANTIALIAS, centering=thumb_fit_centering) else: img.thumbnail(box, PILImage.ANTIALIAS) outformat = img.format or original_format or 'JPEG' logger.debug('Save thumnail image: %s (%s)', outname, outformat) save_image(img, outname, outformat, options=options, autoconvert=True)
def generate_image(source, outname, settings, options=None): """Image processor, rotate and resize the image. :param source: path to an image :param outname: output filename :param settings: settings dict :param options: dict with PIL options (quality, optimize, progressive) """ print(f'{source} => {outname}') logger = logging.getLogger(__name__) if settings['USE_ORIG'] or source.endswith('.gif'): utils.copy(source, outname, symlink=settings['ORIG_LINK']) return # print(f'read image {source}') img = _read_image(source) original_format = img.format if settings['COPY_EXIF_DATA'] and settings['autorotate_images']: logger.warning("The 'autorotate_images' and 'COPY_EXIF_DATA' settings " "are not compatible because Sigal can't save the " "modified Orientation tag.") # Preserve EXIF data if settings['COPY_EXIF_DATA'] and _has_exif_tags(img): if options is not None: options = deepcopy(options) else: options = {} options['exif'] = img.info['exif'] # signal.send() does not work here as plugins can modify the image, so we # iterate other the receivers to call them with the image. # for receiver in signals.img_resized.receivers_for(img): # img = receiver(img, settings=settings) # first, use hard-coded output format, or PIL format, or original image # format, or fall back to JPEG outformat = settings.get( 'IMG_FORMAT') or img.format or original_format or 'JPEG' logger.debug('Save resized image to %s (%s)', outname, outformat) save_image(img, outname, outformat, options=options, autoconvert=True)
def generate_thumbnail(source, outname, box, delay, fit=True, options=None): """Create a thumbnail image.""" logger = logging.getLogger(__name__) with warnings.catch_warnings(record = True) as caught_warnings: img = PILImage.open(source) original_format = img.format _handle_caught_warnings(caught_warnings, source) if fit: img = ImageOps.fit(img, box, PILImage.ANTIALIAS) else: img.thumbnail(box, PILImage.ANTIALIAS) outformat = img.format or original_format or 'JPEG' logger.debug(u'Save thumnail image: {0} ({1})'.format(outname, outformat)) save_image(img, outname, outformat, options=options, autoconvert=True)
def resize_image(path, output, side=360): img = Image.open(path) ow, oh = img.size if ow > oh: h = int(float(side) / float(ow) * float(oh)) w = side else: h = side w = int(float(side) / float(oh) * float(ow)) if img.format.lower() == 'gif': resize_gif(path, output, w, h) return processor = processors.SmartResize(w, h) new_img = processor.process(img) utils.save_image(new_img, output, img.format)
def save(self, name, content, save=True, *args, **kwargs): crop_size = getattr(self.field, 'crop_size', None) if crop_size: width, height = crop_size processor = SmartCrop(width=width, height=height) with PILImage.open(content.file) as image: cropped_image = processor.process(image) path, ext = os.path.splitext(name) save_image( cropped_image, outfile=content.file, format=get_format(ext), ) super(CropMixin, self).save(name=name, content=content, save=save, *args, **kwargs)
def compress_img(self, img, quality=70): """ Compress PIL image file to JPEG reducing quality :param img: PIL image file :param quality: :return: """ tmpfile = TemporaryFile() return Image.open( save_image(img, tmpfile, 'JPEG', options={'quality': quality}))
def generate_image(source, outname, size, format, options=None, autoconvert=True, copyright_text='', method='ResizeToFit', copy_exif_data=True): """Image processor, rotate and resize the image. :param source: path to an image :param options: dict with PIL options (quality, optimize, progressive) """ logger = logging.getLogger(__name__) img = PILImage.open(source) original_format = img.format # Preserve EXIF data if copy_exif_data and hasattr(img, 'info') and 'exif' in img.info: options = options or {} options['exif'] = img.info['exif'] # Rotate the img, and catch IOError when PIL fails to read EXIF try: img = Transpose().process(img) except IOError: pass # Resize the image try: logger.debug('Processor: %s', method) processor_cls = getattr(pilkit.processors, method) except AttributeError: logger.error('Wrong processor name: %s', method) sys.exit() processor = processor_cls(*size, upscale=False) img = processor.process(img) if copyright_text: add_copyright(img, copyright_text) format = format or img.format or original_format or 'JPEG' logger.debug(u'Save resized image to {0} ({1})'.format(outname, format)) save_image(img, outname, format, options=options, autoconvert=autoconvert)
def process(image_url, processor = None, width=None, height=None, resolution=None, quality=100): conn = S3Connection(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY) bucket = conn.get_bucket(settings.AWS_STORAGE_BUCKET_NAME) if image_url[0] =='/': image_url = image_url[1:] r = requests.get(image_url.replace('https', 'http')) img = Image.open(StringIO(r.content)) processor = ResizeToFit(width, height) new_img = processor.process(img) new_file = StringIO() save_image(new_img, new_file, 'JPEG') new_k = Key(bucket) parts = urlparse(image_url) img_name = os.path.splitext(os.path.basename(parts.path))[0] new_k.key = 'il/{}x{}/{}.jpeg'.format(width, height, img_name) new_k.content_type = 'image/jpeg' new_k.set_contents_from_file(new_file, policy='public-read') new_image_url = new_k.generate_url(0, query_auth=False, force_http=True) processed_image,_ = ProcessedImage.objects.update_or_create(source_image = image_url, processed_image = new_image_url) return processed_image
def save_pilimage(image, path, storage): """Save a pil image using django storage system. As a PIL image does not inherit from django file class it can not be saved using django storage system. So we have to load the image content to a django file and the save it using django storage. Args: image: a PIL image to be saved in the host. path: a string that indicates the file path where the image should be saved. storage: a django storage instance. Returns: A string with the path of the stored file. """ content = ContentFile(b'') save_image(image, outfile=content, format=get_format(path)) name = storage.save(path, content) content.close() return name
def generate_thumbnail(source, outname, box, skip, fit=False, options=None): """Create a thumbnail image.""" logger = logging.getLogger(__name__) extension = os.path.splitext(source)[1] if extension in ('.cr2'): raw = rawpy.imread(source) img = PILImage.fromarray(raw.postprocess()) original_format = "JPEG" else: img = PILImage.open(source) original_format = img.format if fit: img = ImageOps.fit(img, box, PILImage.ANTIALIAS) else: img.thumbnail(box, PILImage.ANTIALIAS) outformat = img.format or original_format or 'JPEG' logger.debug(u'Save thumnail image: {0} ({1})'.format(outname, outformat)) save_image(img, outname, outformat, options=options, autoconvert=True)
def generate_image(source, outname, settings, options=None): """Image processor, rotate and resize the image. :param source: path to an image :param outname: output filename :param settings: settings dict :param options: dict with PIL options (quality, optimize, progressive) """ logger = logging.getLogger(__name__) if settings['use_orig'] or source.endswith('.gif'): utils.copy(source, outname, symlink=settings['orig_link']) return img = _read_image(source) original_format = img.format if settings['copy_exif_data'] and settings['autorotate_images']: logger.warning("The 'autorotate_images' and 'copy_exif_data' settings " "are not compatible because Sigal can't save the " "modified Orientation tag.") # Preserve EXIF data if settings['copy_exif_data'] and _has_exif_tags(img): if options is not None: options = deepcopy(options) else: options = {} options['exif'] = img.info['exif'] # Rotate the img, and catch IOError when PIL fails to read EXIF if settings['autorotate_images']: try: img = Transpose().process(img) except (OSError, IndexError): pass # Resize the image if settings['img_processor']: try: logger.debug('Processor: %s', settings['img_processor']) processor_cls = getattr(pilkit.processors, settings['img_processor']) except AttributeError: logger.error('Wrong processor name: %s', settings['img_processor']) sys.exit() width, height = settings['img_size'] if img.size[0] < img.size[1]: # swap target size if image is in portrait mode height, width = width, height processor = processor_cls(width, height, upscale=False) img = processor.process(img) # signal.send() does not work here as plugins can modify the image, so we # iterate other the receivers to call them with the image. for receiver in signals.img_resized.receivers_for(img): img = receiver(img, settings=settings) # first, use hard-coded output format, or PIL format, or original image # format, or fall back to JPEG outformat = (settings.get('img_format') or img.format or original_format or 'JPEG') logger.debug('Save resized image to %s (%s)', outname, outformat) save_image(img, outname, outformat, options=options, autoconvert=True)
def _convert_to_jpg(self, image_path): base = os.path.splitext(image_path)[0] new_image_path = base + '.jpg' save_image(Image.open(image_path), new_image_path, 'JPEG') return new_image_path
def generate_image(inpath, outpath, width=None, height=None, format=JPEG, fill=False, upscale=True, anchor=None, quality=80, bgcolor=None, progressive=True, force_cache=False, placeholder_reason=None, placeholder_image_path=None): """Generate an image with the passed in settings This is used by :func:`resize` and is run outside of the Flask context. Args: inpath (str): Path to the image to generate a new image out of. outpath (str): Where the new image will end up. width (Optional[:class:`int`]): The width to use for the generated image. height (Optional[:class:`str`]): The height to use for the generated image. format (str): Format to convert into. Defaults to "JPEG". fill (bool): Fill the entire width and height that was specified if True, otherwise keep the original image dimensions. Defaults to False. upscale (bool): Whether or not to allow the image to become bigger than the original if the request width and/or height is bigger than its dimensions. Defaults to True. anchor (str): Deprecated since Flask-Resize 0.6. quality (int): Quality of the output image, if the format is JPEG. Defaults to 80. bgcolor (Optional[:class:`str`]): If specified this color will be used as background. progressive (bool): Whether to use progressive encoding or not when JPEG is the output format. force_cache (bool): Whether to force the function to always use the image cache. If false, will reaise a :class:`exc.StopImageGeneration` if the generated image would be the same as the original. Defaults to False. placeholder_reason (Optional[:class:`str`]): A text to show the user if the image path could not be found. placeholder_image_path (Optional[:class:`str`]): The path to the image to use as the background of the placeholder. Raises: :class:`exc.ImageNotFoundError`: If the source image cannot be found or is not a file. :class:`exc.StopImageGeneration`: If force_cache is False and if the image transformation would result in the same image as the original. Returns: PIL.Image: The generated image. """ if anchor: warnings.warn( "anchor has been deprecated in Flask-Resize 0.6 and doesn't do anything to the image. Will be removed in 1.0.", DeprecationWarning ) if not os.path.isfile(inpath): if placeholder_reason: img = create_placeholder_img(width, height, placeholder_reason, placeholder_image_path) else: raise exc.ImageNotFoundError(inpath) else: img = Image.open(inpath) original_width, original_height = img.size w = width or original_width h = height or original_height if not force_cache and format == _parse_format(inpath) and fill is False: if (w == original_width and h == original_height) or \ (upscale is False and \ (w >= original_width or h >= original_height)): if not placeholder_reason: raise exc.StopImageGeneration() processor_kwargs = dict(width=width, height=height, upscale=upscale) _mkdir_p(outpath.replace('\\','/').rpartition('/')[0]) if fill: if bgcolor: mat_color = ImageColor.getrgb(parse_rgb(bgcolor)) elif format == JPEG: mat_color = (255, 255, 255, 255) # White else: mat_color = (0, 0, 0, 0) # Transparent processor_kwargs['mat_color'] = mat_color # Transparent processor = ResizeToFit(**processor_kwargs) img = processor.process(img) assert (not os.path.exists(outpath)), 'Path to save to already exists' options = {} if format == JPEG: options.update({'quality': int(quality), 'progressive': progressive}) if bgcolor is not None: img = make_opaque(img, bgcolor) with open(outpath, 'wb') as outfile: save_image(img, outfile, format=format, options=options) return img
def make_derivatives(self, overwrite=False): """ create derivative images """ logger = logging.getLogger(sys._getframe().f_code.co_name) try: thumbnail = self.thumbnail except AttributeError: pass else: if not overwrite: return False master_path = os.path.join(self.path, 'master.tif') master_image = Image.open(master_path) master_profile = master_image.info.get('icc_profile') # make and save "maximum" image, a jpeg same resolution as the master maximum_image = master_image.copy() maximum_path = os.path.join(self.path, 'maximum.jpg') try: save_image(maximum_image, maximum_path, 'JPEG', options={'optimize':True, 'progressive':False, 'quality':95, 'icc_profile':master_profile}) except IOError: save_image(preview_image, preview_path, 'JPEG', options={'optimize':True, 'progressive':False, 'icc_profile':master_profile}) self.maximum = True maximum_hash = hash_of_file(maximum_path) self.__append_event__("Wrote derivative 'maximum' jpeg file on {0}".format(maximum_path)) self.manifest.set('maximum.jpg', maximum_hash) del maximum_image # save RAM # make and save preview image # Note: the resampling algorithm that gives the highest quality result (bicubic) # is expensive in terms of compute time, and that expense is proportional to the # size of the original image and the relative size of the target image. # Consequently, if the starting image is significantly larger than the desired # down-sampled image, we'll make a first pass with the much less expensive # "nearest neighbor" resampling algorithm to get an image that is only twice the # size of the target, then use "bicubic" on it to get the desired outcome. The # wisdom of the Internet seems to point to this as a time-saving step that # sacrifices little or nothing in quality. Caveat lector. Of course, if we # really wanted to do this fast, we'd write it in C. preview_image = master_image.copy() del master_image # save RAM size = preview_image.size logger.debug("master size: {0}, {1}".format(size[0], size[1])) if size[0] > 3* SIZEPREVIEW[0] or size[1] > 3* SIZEPREVIEW[1]: preview_image.thumbnail(tuple(s*2 for s in SIZEPREVIEW), Image.NEAREST) logger.debug("did nearest pre-shrink for preview, resulting size: {0}, {1}".format(preview_image.size[0], preview_image.size[1])) preview_image.thumbnail(SIZEPREVIEW) logger.debug("resulting preview size: {0}, {1}".format(preview_image.size[0], preview_image.size[1])) preview_path = os.path.join(self.path, 'preview.jpg') try: save_image(preview_image, preview_path, 'JPEG', options={'optimize':True, 'progressive':True, 'quality':80, 'icc_profile':master_profile}) except IOError: save_image(preview_image, preview_path, 'JPEG', options={'optimize':True, 'progressive':True, 'icc_profile':master_profile}) logger.warning("preview image could not be written at quality 80; using defaults") self.preview = True preview_hash = hash_of_file(preview_path) self.__append_event__("wrote derivative 'preview' jpeg file on {0}".format(preview_path)) self.manifest.set('preview.jpg', preview_hash) # make and save thumbnail image # Note: use the same approach as above, but start with the preview image, which # is surely much smaller than the master. thumbnail_image = preview_image.copy() del preview_image # save the RAMs! thumbnail_image.thumbnail(SIZETHUMB) thumbnail_path = os.path.join(self.path, 'thumb.jpg') try: save_image(thumbnail_image, thumbnail_path, 'JPEG', options={'optimize':True, 'progressive':True, 'quality':80, 'icc_profile':master_profile}) except IOError: save_image(thumbnail_image, thumbnail_path, 'JPEG', options={'optimize':True, 'progressive':True, 'icc_profile':master_profile}) logger.warning("preview image could not be written at quality 80; using defaults") self.thumbnail = True thumbnail_hash = hash_of_file(thumbnail_path) self.__append_event__("wrote derivative 'thumbnail' jpeg file on {0}".format(thumbnail_path)) self.manifest.set('thumb.jpg', thumbnail_hash) del thumbnail_image # probably not necessary to save the RAM here cuz gc will get it but anyway... return True
def make_derivatives(self, overwrite=False): """ create derivative images """ logger = logging.getLogger(sys._getframe().f_code.co_name) try: thumbnail = self.thumbnail except AttributeError: pass else: if not overwrite: return False master_path = os.path.join(self.path, 'master.tif') master_image = Image.open(master_path) master_profile = master_image.info.get('icc_profile') # make and save "maximum" image, a jpeg same resolution as the master maximum_image = master_image.copy() maximum_path = os.path.join(self.path, 'maximum.jpg') try: save_image(maximum_image, maximum_path, 'JPEG', options={ 'optimize': True, 'progressive': False, 'quality': 95, 'icc_profile': master_profile }) except IOError: save_image(preview_image, preview_path, 'JPEG', options={ 'optimize': True, 'progressive': False, 'icc_profile': master_profile }) self.maximum = True maximum_hash = hash_of_file(maximum_path) self.__append_event__( "Wrote derivative 'maximum' jpeg file on {0}".format(maximum_path)) self.manifest.set('maximum.jpg', maximum_hash) del maximum_image # save RAM # make and save preview image # Note: the resampling algorithm that gives the highest quality result (bicubic) # is expensive in terms of compute time, and that expense is proportional to the # size of the original image and the relative size of the target image. # Consequently, if the starting image is significantly larger than the desired # down-sampled image, we'll make a first pass with the much less expensive # "nearest neighbor" resampling algorithm to get an image that is only twice the # size of the target, then use "bicubic" on it to get the desired outcome. The # wisdom of the Internet seems to point to this as a time-saving step that # sacrifices little or nothing in quality. Caveat lector. Of course, if we # really wanted to do this fast, we'd write it in C. preview_image = master_image.copy() del master_image # save RAM size = preview_image.size logger.debug("master size: {0}, {1}".format(size[0], size[1])) if size[0] > 3 * SIZEPREVIEW[0] or size[1] > 3 * SIZEPREVIEW[1]: preview_image.thumbnail(tuple(s * 2 for s in SIZEPREVIEW), Image.NEAREST) logger.debug( "did nearest pre-shrink for preview, resulting size: {0}, {1}". format(preview_image.size[0], preview_image.size[1])) preview_image.thumbnail(SIZEPREVIEW) logger.debug("resulting preview size: {0}, {1}".format( preview_image.size[0], preview_image.size[1])) preview_path = os.path.join(self.path, 'preview.jpg') try: save_image(preview_image, preview_path, 'JPEG', options={ 'optimize': True, 'progressive': True, 'quality': 80, 'icc_profile': master_profile }) except IOError: save_image(preview_image, preview_path, 'JPEG', options={ 'optimize': True, 'progressive': True, 'icc_profile': master_profile }) logger.warning( "preview image could not be written at quality 80; using defaults" ) self.preview = True preview_hash = hash_of_file(preview_path) self.__append_event__( "wrote derivative 'preview' jpeg file on {0}".format(preview_path)) self.manifest.set('preview.jpg', preview_hash) # make and save thumbnail image # Note: use the same approach as above, but start with the preview image, which # is surely much smaller than the master. thumbnail_image = preview_image.copy() del preview_image # save the RAMs! thumbnail_image.thumbnail(SIZETHUMB) thumbnail_path = os.path.join(self.path, 'thumb.jpg') try: save_image(thumbnail_image, thumbnail_path, 'JPEG', options={ 'optimize': True, 'progressive': True, 'quality': 80, 'icc_profile': master_profile }) except IOError: save_image(thumbnail_image, thumbnail_path, 'JPEG', options={ 'optimize': True, 'progressive': True, 'icc_profile': master_profile }) logger.warning( "preview image could not be written at quality 80; using defaults" ) self.thumbnail = True thumbnail_hash = hash_of_file(thumbnail_path) self.__append_event__( "wrote derivative 'thumbnail' jpeg file on {0}".format( thumbnail_path)) self.manifest.set('thumb.jpg', thumbnail_hash) del thumbnail_image # probably not necessary to save the RAM here cuz gc will get it but anyway... return True