def test_geometry(self): g = parse_geometry('222x30') self.assertEqual(g, (222, 30)) g = parse_geometry('222') self.assertEqual(g, (222, None)) g = parse_geometry('x999') self.assertEqual(g, (None, 999))
def test_geometry(self): g = parse_geometry("222x30") self.assertEqual(g, (222, 30)) g = parse_geometry("222") self.assertEqual(g, (222, None)) g = parse_geometry("x999") self.assertEqual(g, (None, 999))
def avatar(user, geometry): return { 'user': user, 'geometry': geometry, 'geometry_width': parse_geometry(geometry)[0], 'geometry_height': parse_geometry(geometry)[1], }
def _create_alternative_resolutions(self, source_image, geometry_string, options, name): """ Creates the thumbnail by using default.engine with multiple output sizes. Appends @<ratio>x to the file name. """ if not options['alternative_resolutions']: return ratio = default.engine.get_image_ratio(source_image) geometry = parse_geometry(geometry_string, ratio) file_type = name.split('.')[len(name.split('.')) - 1] for resolution in options['alternative_resolutions']: resolution_geometry = (int(geometry[0] * resolution), int(geometry[1] * resolution)) resolution_options = options.copy() if 'crop' in options and isinstance(options['crop'], basestring): crop = options['crop'].split(" ") for i in xrange(len(crop)): s = re.match("(\d+)px", crop[i]) if s: crop[i] = "%spx" % int(int(s.group(1)) * resolution) resolution_options['crop'] = " ".join(crop) thumbnail_name = name.replace(".%s" % file_type, "@%sx.%s" % (resolution, file_type)) image = default.engine.create(source_image, resolution_geometry, resolution_options) thumbnail = ImageFile(thumbnail_name, default.storage) default.engine.write(image, resolution_options, thumbnail) size = default.engine.get_image_size(image) thumbnail.set_size(size)
def _create_alternative_resolutions(self, source_image, geometry_string, options, name): """ Creates the thumbnail by using default.engine with multiple output sizes. Appends @<ratio>x to the file name. """ ratio = default.engine.get_image_ratio(source_image, options) geometry = parse_geometry(geometry_string, ratio) file_name, dot_file_ext = os.path.splitext(name) for resolution in settings.THUMBNAIL_ALTERNATIVE_RESOLUTIONS: resolution_geometry = (int(geometry[0] * resolution), int(geometry[1] * resolution)) resolution_options = options.copy() if 'crop' in options and isinstance(options['crop'], string_types): crop = options['crop'].split(" ") for i in range(len(crop)): s = re.match("(\d+)px", crop[i]) if s: crop[i] = "%spx" % int(int(s.group(1)) * resolution) resolution_options['crop'] = " ".join(crop) image = default.engine.create(source_image, resolution_geometry, options) thumbnail_name = '%(file_name)s%(suffix)s%(file_ext)s' % { 'file_name': file_name, 'suffix': '@%sx' % resolution, 'file_ext': dot_file_ext } thumbnail = ImageFile(thumbnail_name, default.storage) default.engine.write(image, resolution_options, thumbnail) size = default.engine.get_image_size(image) thumbnail.set_size(size)
def margin(file_, geometry_string): """ Returns the calculated margin for an image and geometry """ if not file_ or (sorl_settings.THUMBNAIL_DUMMY or isinstance(file_, DummyImageFile)): return 'auto' margin = [0, 0, 0, 0] image_file = default.kvstore.get_or_set(ImageFile(file_)) x, y = parse_geometry(geometry_string, image_file.ratio) ex = x - image_file.x margin[3] = ex / 2 margin[1] = ex / 2 if ex % 2: margin[1] += 1 ey = y - image_file.y margin[0] = ey / 2 margin[2] = ey / 2 if ey % 2: margin[2] += 1 return ' '.join(['%dpx' % n for n in margin])
def _create_thumbnail(self, source_image, geometry_string, options, thumbnail): """ Creates the thumbnail by using default.engine """ ratio = default.engine.get_image_ratio(source_image) geometry = parse_geometry(geometry_string, ratio) image = default.engine.create(source_image, geometry, options) # To RGBA! image = image.convert(mode="RGBA") # Per pixel calculations. # # This is slow and could be optimized.. but it works in any case. new_data = [] for item in image.getdata(): # If px is white, make transparent if item[:3] == (255, 255, 255): new_data.append((255, 255, 255, 0)) continue # All other pixels are "whitened" by TO_GRAY_INTENSITY # (given that 0 is white and 1 is original intensity) converted_pixel = self.__calc_new_intensity(item) new_data.append(converted_pixel) image.putdata(new_data) default.engine.write(image, options, thumbnail) # It's much cheaper to set the size here size = default.engine.get_image_size(image) thumbnail.set_size(size)
def _create_thumbnail(self, source_image, geometry_string, options, thumbnail): """ Creates the thumbnail by using default.engine """ ratio = default.engine.get_image_ratio(source_image) geometry = parse_geometry(geometry_string, ratio) image = default.engine.create(source_image, geometry, options) # To RGBA! image = image.convert(mode='RGBA') # Per pixel calculations. # # This is slow and could be optimized.. but it works in any case. new_data = [] for item in image.getdata(): # If px is white, make transparent if item[:3] == (255, 255, 255): new_data.append((255, 255, 255, 0)) continue # All other pixels are "whitened" by TO_GRAY_INTENSITY # (given that 0 is white and 1 is original intensity) converted_pixel = self.__calc_new_intensity(item) new_data.append(converted_pixel) image.putdata(new_data) default.engine.write(image, options, thumbnail) # It's much cheaper to set the size here size = default.engine.get_image_size(image) thumbnail.set_size(size)
def __init__(self, geometry_string, ratio, name, url): ''' Pass ImageFile as source ''' self.name = name self._url = url self.size = parse_geometry(geometry_string, ratio)
def get_thumbnail_attributes(self, image_thm, size_str): if image_thm: margin = [0, 0, 0, 0] image_file = default.kvstore.get_or_set(ImageFile(image_thm)) x, y = parse_geometry(size_str, image_file.ratio) ex = x - image_file.x margin[3] = ex / 2 margin[1] = ex / 2 if ex % 2: margin[1] += 1 ey = y - image_file.y margin[0] = ey / 2 margin[2] = ey / 2 if ey % 2: margin[2] += 1 margin_str = ' '.join(['%spx' % n for n in margin]) res_dt = { 'margin_str': margin_str, } if settings.LUGATI_FULL_IMAGE_PATH: res_dt['thumbnail_url'] = settings.POS_SERVER + image_thm.url else: res_dt['thumbnail_url'] = image_thm.url else: res_dt = { 'thumbnail_url': '', 'margin_str': '' } return res_dt['thumbnail_url'], res_dt['margin_str']
def process_image(image: Image, spec: Tuple[str, dict]) -> Image: size = spec[0] options = spec[1].copy() for key, value in list(ThumbnailBackend.default_options.items()): options.setdefault(key, value) ratio = engine.get_image_ratio(image, options) geometry = parse_geometry(size, ratio) return engine.create(image, geometry, options)
def _create_thumbnail(self, source_image, geometry_string, options, thumbnail): """ Creates the thumbnail by using default.engine """ ratio = default.engine.get_image_ratio(source_image) geometry = parse_geometry(geometry_string, ratio) image = default.engine.create(source_image, geometry, options) default.engine.write(image, options, thumbnail) # It's much cheaper to set the size here size = default.engine.get_image_size(image) thumbnail.set_size(size)
def _create_thumbnail(self, source_image, geometry_string, options, thumbnail): """ Creates the thumbnail by using default.engine """ logger.debug("Creating thumbnail file [%s] at [%s] with [%s]", thumbnail.name, geometry_string, options) ratio = default.engine.get_image_ratio(source_image, options) geometry = parse_geometry(geometry_string, ratio) image = default.engine.create(source_image, geometry, options) default.engine.write(image, options, thumbnail) # It's much cheaper to set the size here size = default.engine.get_image_size(image) thumbnail.set_size(size)
def get_thumbnail(self, file_, geometry_string, **options): source = ImageFile(file_) for key, value in self.default_options.iteritems(): options.setdefault(key, value) for key, attr in self.extra_options: value = getattr(settings, attr) if value != getattr(default_settings, attr): options.setdefault(key, value) # Generate a name for the thumbnail name = self._get_thumbnail_filename(source, geometry_string, options) # See if we've got a hit in the cache thumbnail = ImageFile(name, default.storage) cached = default.kvstore.get(thumbnail) if cached: return cached # We cannot check if the file exists, as remote storage is slow. If # we have reached this point, the image does not exist in our kvstore # so create the entry and queue the generation of the image. # # Note: If the thumbnail file has been deleted, you will need to manually # clear the corresponding row from the kvstore to have thumbnail rebuilt. job = create_thumbnail.delay(file_, geometry_string, options, name) if job: geometry = parse_geometry(geometry_string) # We can't add a source row to the kvstore without the size # information being looked up, so add dummy information here # We'll need to correct this information when we generate the thumbnail source.set_size(geometry) default.kvstore.get_or_set(source) # We don't want to do any file access in this thread, so we tell sorlery # to proceed as normal and cheekily update the name and storage after # the hash has been calculated. thumbnail.set_size(geometry) default.kvstore.set(thumbnail, source) # Now we go back and manually update the thumbnail to point at the source image # Hopefully someone can suggest a better way to do this ... but the sorl internals # don't make it easy to. rawvalue = default.kvstore._get_raw(add_prefix(thumbnail.key)) rawvaluearr = deserialize(rawvalue) rawvaluearr['name'] = file_.name default.kvstore._set_raw(add_prefix(thumbnail.key), serialize(rawvaluearr)) thumbnail.name = file_.name return thumbnail
def test_truncated_generation_failure(self): """ Confirm that generating a thumbnail for our "broken" image fails. """ name = 'data/broken.jpeg' with open(name, 'rb') as broken_jpeg: with self.assertRaises((OSError, IOError,)): im = default.engine.get_image(broken_jpeg) options = ThumbnailBackend.default_options ratio = default.engine.get_image_ratio(im, options) geometry = parse_geometry('120x120', ratio) default.engine.create(im, geometry, options)
def _create_thumbnail(self, source_image, geometry_string, options, thumbnail): """ Creates the thumbnail by using default.engine """ logger.debug('Creating thumbnail file [%s] at [%s] with [%s]', thumbnail.name, geometry_string, options) ratio = default.engine.get_image_ratio(source_image, options) geometry = parse_geometry(geometry_string, ratio) image = default.engine.create(source_image, geometry, options) default.engine.write(image, options, thumbnail) # It's much cheaper to set the size here size = default.engine.get_image_size(image) thumbnail.set_size(size)
def background_margin(file_, geometry_string): """ Returns the calculated margin for a background image and geometry """ if not file_ or settings.THUMBNAIL_DUMMY: return 'auto' margin = [0, 0] image_file = default.kvstore.get_or_set(ImageFile(file_)) x, y = parse_geometry(geometry_string, image_file.ratio) ex = x - image_file.x margin[0] = ex / 2 ey = y - image_file.y margin[1] = ey / 2 return ' '.join(['%spx' % n for n in margin])
def get_thumbnail(self, file_, geometry_string, **options): source = ImageFile(file_) for key, value in self.default_options.items(): options.setdefault(key, value) name = self._get_thumbnail_filename(source, geometry_string, options) thumbnail = ImageFile(name, default.storage) cached = default.kvstore.get(thumbnail) if cached: return cached # We don't check if thumbnail exists as sorl-thumbnail does. It becomes # very costly for remote storages. # Furthermore, I have added following code to reduce/prevent duplicate # tasks in celery. It's hacky. # Finally, if there is no thumbnail, we create one. from .tasks import create_thumbnail job = create_thumbnail.delay(source.name, geometry_string, **options) # Sometimes thumbnail generation takes quite some time, just return # the original image then. if job: geometry = parse_geometry(geometry_string) # We can't add a source row to the kvstore without the size # information being looked up, so add dummy information here # We'll need to correct this information when we generate the thumbnail source.set_size(geometry) default.kvstore.get_or_set(source) # We don't want to do any file access in this thread, so we tell sorlery # to proceed as normal and cheekily update the name and storage after # the hash has been calculated. thumbnail.set_size(geometry) default.kvstore.set(thumbnail, source) # Now we go back and manually update the thumbnail to point at the source image # Hopefully someone can suggest a better way to do this ... but the sorl internals # don't make it easy to. rawvalue = default.kvstore._get_raw(add_prefix(thumbnail.key)) rawvaluearr = deserialize(rawvalue) rawvaluearr['name'] = file_.name default.kvstore._set_raw(add_prefix(thumbnail.key), serialize(rawvaluearr)) thumbnail.name = file_.name return thumbnail
def _create_alternative_resolutions(self, source, geometry_string, options, name): """ Creates the thumbnail by using default.engine with multiple output sizes. Appends @<ratio>x to the file name. """ if not options['alternative_resolutions']: return source_image = default.engine.get_image(source) ratio = default.engine.get_image_ratio(source_image, options) geometry_orig = parse_geometry(geometry_string, ratio) file_type = name.split('.')[len(name.split('.'))-1] for res in options['alternative_resolutions']: geometry = (toint(geometry_orig[0]*res), toint(geometry_orig[1]*res)) thumbnail_name = name.replace(".%s" % file_type, "@%sx.%s" % (res, file_type)) source_image = default.engine.get_image(source) image = default.engine.create(source_image, geometry, options) thumbnail = ImageFile(thumbnail_name, default.storage) default.engine.write(image, options, thumbnail) size = default.engine.get_image_size(image) thumbnail.set_size(size)
def sorl_margin(file_, geometry_string): """ This is copied from sorl/thumbnail/templatetags/thumbnail.py because of problems with importing it. This should be removed when we remove easy_thumbnail. Returns the calculated margin for an image and geometry """ if not file_ or settings.THUMBNAIL_DUMMY: return 'auto' margin = [0, 0, 0, 0] image_file = default.kvstore.get_or_set(ImageFile(file_)) x, y = parse_geometry(geometry_string, image_file.ratio) ex = x - image_file.x margin[3] = ex / 2 margin[1] = ex / 2 if ex % 2: margin[1] += 1 ey = y - image_file.y margin[0] = ey / 2 margin[2] = ey / 2 if ey % 2: margin[2] += 1 return ' '.join([ '%spx' % n for n in margin ])
def sorl_margin(file_, geometry_string): """ This is copied from sorl/thumbnail/templatetags/thumbnail.py because of problems with importing it. This should be removed when we remove easy_thumbnail. Returns the calculated margin for an image and geometry """ if not file_ or settings.THUMBNAIL_DUMMY: return 'auto' margin = [0, 0, 0, 0] image_file = default.kvstore.get_or_set(ImageFile(file_)) x, y = parse_geometry(geometry_string, image_file.ratio) ex = x - image_file.x margin[3] = ex / 2 margin[1] = ex / 2 if ex % 2: margin[1] += 1 ey = y - image_file.y margin[0] = ey / 2 margin[2] = ey / 2 if ey % 2: margin[2] += 1 return ' '.join(['%spx' % n for n in margin])
def __init__(self, geometry_string): self.size = parse_geometry( geometry_string, settings.THUMBNAIL_DUMMY_RATIO, )
def get_placeholder_thumbnail(file_, geometry_string, **options): """Return a place holder url for the given geometry string""" x, y = parse_geometry(geometry_string, ratio=1) url = '//placehold.it/{}x{}'.format(x, y) Url = namedtuple('Url', ('url',)) return Url(url=url)
def get_placeholder_thumbnail(file_, geometry_string, **options): """Return a place holder url for the given geometry string""" x, y = parse_geometry(geometry_string, ratio=1) url = '//placehold.it/{}x{}'.format(x, y) Url = namedtuple('Url', ('url', )) return Url(url=url)
def clean_geometry(self): data = self.cleaned_data['geometry'] try: parse_geometry(data) except ThumbnailParseError, e: raise forms.ValidationError(str(e))
def get_thumbnail(self, file_, geometry_string, **options): # Correct way for create source image, This is coped from begining of # ThumbnailBackend.get_thumbnail if file_: source = ImageFile(file_) elif settings.THUMBNAIL_DUMMY: return DummyImageFile(geometry_string) else: return None for key, value in self.default_options.iteritems(): options.setdefault(key, value) for key, attr in self.extra_options: value = getattr(settings, attr) if value != getattr(default_settings, attr): options.setdefault(key, value) # Generate a name for the thumbnail name = self._get_thumbnail_filename(source, geometry_string, options) # See if we've got a hit in the cache thumbnail = ImageFile(name, default.storage) cached = default.kvstore.get(thumbnail) if cached: return cached #fixing misssing 'image_info' to be compatible with sorl-thumbnail newewst version else: # We have to check exists() because the Storage backend does not # overwrite in some implementations. # so we make the assumption that if the thumbnail is not cached, it doesn't exist try: source_image = default.engine.get_image(source) except IOError: if settings.THUMBNAIL_DUMMY: return DummyImageFile(geometry_string) else: # if S3Storage says file doesn't exist remotely, don't try to # create it and exit early. # Will return working empty image type; 404'd image logger.warn('Remote file [%s] at [%s] does not exist', file_, geometry_string) return thumbnail # We might as well set the size since we have the image in memory image_info = default.engine.get_image_info(source_image) options['image_info'] = image_info # We cannot check if the file exists, as remote storage is slow. If # we have reached this point, the image does not exist in our kvstore # so create the entry and queue the generation of the image. # # Note: If the thumbnail file has been deleted, you will need to manually # clear the corresponding row from the kvstore to have thumbnail rebuilt. job = create_thumbnail.delay(file_, geometry_string, options, name) if job: geometry = parse_geometry(geometry_string) # We can't add a source row to the kvstore without the size # information being looked up, so add dummy information here # We'll need to correct this information when we generate the thumbnail source.set_size(geometry) default.kvstore.get_or_set(source) # We don't want to do any file access in this thread, so we tell sorlery # to proceed as normal and cheekily update the name and storage after # the hash has been calculated. thumbnail.set_size(geometry) default.kvstore.set(thumbnail, source) # Now we go back and manually update the thumbnail to point at the source image # Hopefully someone can suggest a better way to do this ... but the sorl internals # don't make it easy to. rawvalue = default.kvstore._get_raw(add_prefix(thumbnail.key)) rawvaluearr = deserialize(rawvalue) rawvaluearr['name'] = source.name default.kvstore._set_raw(add_prefix(thumbnail.key), serialize(rawvaluearr)) thumbnail.name = source.name return thumbnail