def _getAndCacheImage(self, item, imageFunc, checkAndCreate, keydict, **kwargs): if 'fill' in keydict and (keydict['fill']).lower() == 'none': del keydict['fill'] keydict = {k: v for k, v in six.viewitems(keydict) if v is not None} key = json.dumps(keydict, sort_keys=True, separators=(',', ':')) existing = File().findOne({ 'attachedToType': 'item', 'attachedToId': item['_id'], 'isLargeImageThumbnail': True, 'thumbnailKey': key }) if existing: if checkAndCreate: return True if kwargs.get('contentDisposition') != 'attachment': contentDisposition = 'inline' else: contentDisposition = kwargs['contentDisposition'] return File().download(existing, contentDisposition=contentDisposition) tileSource = self._loadTileSource(item, **kwargs) result = getattr(tileSource, imageFunc)(**kwargs) if result is None: thumbData, thumbMime = b'', 'application/octet-stream' else: thumbData, thumbMime = result # The logic on which files to save could be more sophisticated. maxThumbnailFiles = int(Setting().get( constants.PluginSettings.LARGE_IMAGE_MAX_THUMBNAIL_FILES)) saveFile = maxThumbnailFiles > 0 if saveFile: # Make sure we don't exceed the desired number of thumbnails self.removeThumbnailFiles(item, maxThumbnailFiles - 1) # Save the thumbnail as a file thumbfile = Upload().uploadFromFile(six.BytesIO(thumbData), size=len(thumbData), name='_largeImageThumbnail', parentType='item', parent=item, user=None, mimeType=thumbMime, attachParent=True) if not len(thumbData) and 'received' in thumbfile: thumbfile = Upload().finalizeUpload( thumbfile, Assetstore().load(thumbfile['assetstoreId'])) thumbfile.update({ 'isLargeImageThumbnail': True, 'thumbnailKey': key, }) # Ideally, we would check that the file is still wanted before we # save it. This is probably impossible without true transactions in # Mongo. File().save(thumbfile) # Return the data return thumbData, thumbMime
def _getAndCacheImageOrData( self, item, imageFunc, checkAndCreate, keydict, pickleCache=False, **kwargs): """ Get a file associated with an image that can be generated by a function. :param item: the idem to process. :param imageFunc: the function to call to generate a file. :param checkAndCreate: False to return the data, creating and caching it if needed. True to return True if the data is already in cache, or to create the data, cache, and return it if not. 'nosave' to return data from the cache if present, or generate the data but do not return it if not in the cache. 'check' to just return True or False to report if it is in the cache. :param keydict: a dictionary of values to use for the cache key. :param pickleCache: if True, the results of the function are pickled to preserver them. If Fales, the results can be saved as a file directly. :params **kwargs: passed to the tile source and to the imageFunc. May contain contentDisposition to determine how results are returned. :returns: """ if 'fill' in keydict and (keydict['fill']).lower() == 'none': del keydict['fill'] keydict = {k: v for k, v in keydict.items() if v is not None and not k.startswith('_')} key = json.dumps(keydict, sort_keys=True, separators=(',', ':')) existing = File().findOne({ 'attachedToType': 'item', 'attachedToId': item['_id'], 'isLargeImageThumbnail' if not pickleCache else 'isLargeImageData': True, 'thumbnailKey': key, }) if existing: if checkAndCreate and checkAndCreate != 'nosave': return True if kwargs.get('contentDisposition') != 'attachment': contentDisposition = 'inline' else: contentDisposition = kwargs['contentDisposition'] if pickleCache: data = File().open(existing).read() return pickle.loads(data), 'application/octet-stream' return File().download(existing, contentDisposition=contentDisposition) if checkAndCreate == 'check': return False tileSource = self._loadTileSource(item, **kwargs) result = getattr(tileSource, imageFunc)(**kwargs) if result is None: imageData, imageMime = b'', 'application/octet-stream' elif pickleCache: imageData, imageMime = result, 'application/octet-stream' else: imageData, imageMime = result saveFile = True if not pickleCache: # The logic on which files to save could be more sophisticated. maxThumbnailFiles = int(Setting().get( constants.PluginSettings.LARGE_IMAGE_MAX_THUMBNAIL_FILES)) saveFile = maxThumbnailFiles > 0 # Make sure we don't exceed the desired number of thumbnails self.removeThumbnailFiles( item, maxThumbnailFiles - 1, imageKey=keydict.get('imageKey') or 'none') if (saveFile and checkAndCreate != 'nosave' and ( pickleCache or isinstance(imageData, bytes))): dataStored = imageData if not pickleCache else pickle.dumps(imageData, protocol=4) # Save the data as a file try: datafile = Upload().uploadFromFile( io.BytesIO(dataStored), size=len(dataStored), name='_largeImageThumbnail', parentType='item', parent=item, user=None, mimeType=imageMime, attachParent=True) if not len(dataStored) and 'received' in datafile: datafile = Upload().finalizeUpload( datafile, Assetstore().load(datafile['assetstoreId'])) datafile.update({ 'isLargeImageThumbnail' if not pickleCache else 'isLargeImageData': True, 'thumbnailKey': key, }) # Ideally, we would check that the file is still wanted before # we save it. This is probably impossible without true # transactions in Mongo. File().save(datafile) except (GirderException, PermissionError): logger.warning('Could not cache data for large image') return imageData, imageMime