def _get_thumbnail_filename(self, source, geometry_string, options):###customization """ Computes the destination filename. """ try: root_path = source.storage.path('') except: #some storage backends do not support path() root_path = '' split_path = re.sub(r'^%s%s?' % (root_path, os.sep), '', source.name).split(os.sep) split_path.insert(-1, geometry_string) #make some subdirs to avoid putting too many files in a single dir. key = tokey(source.key, geometry_string, serialize(options)) split_path.insert(-1, key[:2]) split_path.insert(-1, key[2:4]) #attempt to slugify the filename to make it SEO-friendly split_name = split_path[-1].split('.') try: split_path[-1] = '%s.%s' % (slugify('.'.join(split_name[:-1])), split_name[-1]) except: #on fail keep the original filename pass path = os.sep.join(split_path) #if the path already starts with THUMBNAIL_PREFIX do not concatenate the PREFIX #this way we avoid ending up with a url like /images/images/120x120/my.png if not path.startswith(settings.THUMBNAIL_PREFIX): return '%s%s' % (settings.THUMBNAIL_PREFIX, path) return path
def _get_thumbnail_filename(self, source, geometry_string, options): """ Computes the destination filename. """ key = tokey(source.key, geometry_string, serialize(options)) # make some subdirs path = '%s/%s/%s' % (key[:2], key[2:4], key) return '%s%s.%s' % (settings.THUMBNAIL_PREFIX, path, EXTENSIONS[options['format']])
def _get_thumbnail_filename(self, source, geometry_string, options): """ Computes the destination filename. """ key = tokey(source.key, geometry_string, serialize(options)) filename, _ext = os.path.splitext(os.path.basename(source.name)) path = '%s/%s' % (key, filename) return '%s%s.%s' % (settings.THUMBNAIL_PREFIX, path, EXTENSIONS[options['format']])
def _get_thumbnail_filename(self, source, geometry_string, options): """ Computes the destination filename. """ key = tokey(source.key, geometry_string, serialize(options)) # make some subdirs path = "%s/%s/%s" % (key[:2], key[2:4], key) return "%s%s.%s" % (settings.THUMBNAIL_PREFIX, path, self.extensions[options["format"]])
def _get_thumbnail_filename(self, source, geometry_string, options): """ Computes the destination filename. """ key = tokey(serialize(options)) image_path = os.path.relpath(source.url, source.storage.location) path = '%s-%s-%s' % (os.path.splitext(image_path)[0], geometry_string, key) return '%s%s.%s' % (settings.THUMBNAIL_PREFIX, path, EXTENSIONS[options['format']])
def _set(self, key, value, identity='image'): """ Serializing, prefix wrapper for _set_raw """ if identity == 'image': s = serialize_image_file(value) else: s = serialize(value) self._set_raw(add_prefix(key, identity), s)
def _set(self, key, value, identity="image"): """ Serializing, prefix wrapper for _set_raw """ if identity == "image": s = serialize_image_file(value) else: s = serialize(value) self._set_raw(add_prefix(key, identity), s)
def _get_thumbnail_filename(self, source, geometry_string, options): """Computes the destination filename.""" key = tokey(source.key, geometry_string, serialize(options)) filename, _ext = os.path.splitext(os.path.basename(source.name)) path = '{0}/{1}'.format(key, filename) image_format = options['format'] return '{0}{1}.{2}'.format(settings.THUMBNAIL_PREFIX, path, EXTENSIONS[image_format])
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 _get_thumbnail_filename(self, source, geometry_string, options): """ Computes the destination filename. """ # HACK: preserving output format of the image if options.get('format', 'auto') == 'auto': options['format'] = guess_image_format(source.name) key = tokey(source.key, geometry_string, serialize(options)) # make some subdirs path = '%s/%s/%s' % (key[:2], key[2:4], key) return '%s%s.%s' % (settings.THUMBNAIL_PREFIX, path, EXTENSIONS[options['format']])
def _get_thumbnail_filename(self, source, geometry_string, options): """Computes the destination filename. Overridden to generate the same filename as generated with 'django.core.files.storage.FileSystemStorage' backend, irrespective of what the current storage back-end is. """ source_key = tokey(source.name, 'django.core.files.storage.FileSystemStorage') key = tokey(source_key, geometry_string, serialize(options)) path = '%s/%s/%s' % (key[:2], key[2:4], key) return '%s%s.%s' % (settings.THUMBNAIL_PREFIX, path, EXTENSIONS[options['format']])
def _get_thumbnail_filename(self, source, geometry_string, options): """ Computes the destination filename. """ key = tokey(source.key, geometry_string, serialize(options)) filename, _ext = os.path.splitext(os.path.basename(source.name)) cache_path = '{}/{}/{}'.format(key[:2], key[2:4], key) filename = '{prefix}{cache_path}/{filename}.{ext}'.format( prefix=settings.THUMBNAIL_PREFIX, cache_path=cache_path, filename=filename, ext=EXTENSIONS[options['format']], ) return filename
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 get_thumbnail(self, file_, geometry_string, **options): """ Returns thumbnail as an ImageFile instance for file with geometry and options given. First it will try to get it from the key value store, secondly it will create it. """ logger.debug(text_type('Getting thumbnail for file [%s] at [%s]'), file_, geometry_string) async = options.pop('async', True) if not async: return super(QueuedThumbnailBackend, self).get_thumbnail(file_, geometry_string, **options) if file_: source = ImageFile(file_) elif settings.THUMBNAIL_DUMMY: return DummyImageFile(geometry_string) else: return None # preserve image filetype if settings.THUMBNAIL_PRESERVE_FORMAT: options.setdefault('format', self._get_format(source)) for key, value in self.default_options.items(): options.setdefault(key, value) # For the future I think it is better to add options only if they # differ from the default settings as below. This will ensure the same # filenames being generated for new options at default. for key, attr in self.extra_options: value = getattr(settings, attr) if value != getattr(default_settings, attr): 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 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 isinstance(file_, string_type): filename = file_.split('/')[-1] else: filename = file_.name if job: geometry = (0, 0) # 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'] = filename default.kvstore._set_raw(add_prefix(thumbnail.key), serialize(rawvaluearr)) thumbnail.name = filename return thumbnail
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
def get_thumbnail(self, file_, geometry_string, **options): """ Returns thumbnail as an ImageFile instance for file with geometry and options given. First it will try to get it from the key value store, secondly it will create it. """ logger.debug('Getting thumbnail for file [%s] at [%s]', file_, geometry_string) source = ImageFile(file_) # preserve image filetype if settings.THUMBNAIL_PRESERVE_FORMAT: options.setdefault('format', self._get_format(source)) for key, value in self.default_options.items(): options.setdefault(key, value) # For the future I think it is better to add options only if they # differ from the default settings as below. This will ensure the same # filenames being generated for new options at default. for key, attr in self.extra_options: value = getattr(settings, attr) if value != getattr(default_settings, attr): options.setdefault(key, value) name = self._get_thumbnail_filename(source, geometry_string, options) thumbnail = ImageFile(name, default.storage, key=tokey(source.key, geometry_string, serialize(options))) cached = default.kvstore.get(thumbnail) if cached: return cached # We have to check exists() because the Storage backend does not # overwrite in some implementations. if settings.THUMBNAIL_FORCE_OVERWRITE or not thumbnail.exists(): try: source_image = default.engine.get_image(source) except IOError as e: logger.exception(e) 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.warning( '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 size = default.engine.get_image_size(source_image) source.set_size(size) try: self._create_thumbnail(source_image, geometry_string, options, thumbnail) self._create_alternative_resolutions(source_image, geometry_string, options, thumbnail.name) finally: default.engine.cleanup(source_image) # If the thumbnail exists we don't create it, the other option is # to delete and write but this could lead to race conditions so I # will just leave that out for now. default.kvstore.get_or_set(source) default.kvstore.set(thumbnail, source) return thumbnail
def create_sorl_key(source, geometry_string, options): return tokey(source.key, geometry_string, serialize(options))
def _get_thumbnail_filename(self, source, geometry_string, options): key = tokey(source.key, geometry_string, serialize(options)) path = '%s/%s/%s' % (key[:2], key[2:4], key) return '%s%s/%s' % (settings.THUMBNAIL_PREFIX, path, basename(source.name))
def get_thumbnail(self, file_, geometry_string, **options): """ Returns thumbnail as an ImageFile instance for file with geometry and options given. First it will try to get it from the key value store, secondly it will create it. """ logger.debug(text_type('Getting thumbnail for file [%s] at [%s]'), file_, geometry_string) async = options.pop('async', True) if not async: return super(QueuedThumbnailBackend, self).get_thumbnail( file_, geometry_string, **options) if file_: source = ImageFile(file_) elif settings.THUMBNAIL_DUMMY: return DummyImageFile(geometry_string) else: return None # preserve image filetype if settings.THUMBNAIL_PRESERVE_FORMAT: options.setdefault('format', self._get_format(source)) for key, value in self.default_options.items(): options.setdefault(key, value) # For the future I think it is better to add options only if they # differ from the default settings as below. This will ensure the same # filenames being generated for new options at default. for key, attr in self.extra_options: value = getattr(settings, attr) if value != getattr(default_settings, attr): 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 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 isinstance(file_, string_type): filename = file_.split('/')[-1] else: filename = file_.name if job: geometry = (0, 0) # 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'] = filename default.kvstore._set_raw(add_prefix(thumbnail.key), serialize(rawvaluearr)) thumbnail.name = filename return thumbnail
def _get_thumbnail_filename(self, source, geometry_string, options): key = tokey(source.key, geometry_string, serialize(options)) path = '%s/%s/%s' % (key[:2], key[2:4], key) return '%s%s/%s' % ( settings.THUMBNAIL_PREFIX, path, basename(source.name))