def get_jpeg_or_png_image_file(item, collection, size, strip_metadata, apply_transforms=False, filename=''): ''' returns a filename with a jpeg or png of the image associated with item, writing a new copy of the image if necessary ''' if not filename: filename = collection.get_path(item) src_filename = filename icopy = None def get_processed_copy(icopy): if icopy is not None: return icopy icopy = baseobjects.Item(filename) icopy.meta = item.meta.copy() if not load_image(icopy, None, lambda: True, apply_transforms=apply_transforms, itemfile=src_filename): return None, None if 'Orientation' in icopy.meta: del icopy.meta['Orientation'] if 'ImageTransforms' in icopy.meta: del icopy.meta['ImageTransforms'] return icopy def write_processed_image(icopy): import tempfile h, filename = tempfile.mkstemp( '.jpg', os.path.splitext(os.path.split(src_filename)[1])[0]) icopy.image.save(filename, quality=95) if not strip_metadata: metadata.copy_metadata(icopy.meta, src_filename, filename) return h, filename if size: if isinstance(size, str): size = tuple(int(dim) for dim in size.split('x')) if isinstance(size, int): size = (size, size) if len(size) > 0 and size[0] > 0 and size[1] > 0: icopy = get_processed_copy(icopy) icopy.image.thumbnail(size, Image.ANTIALIAS) if io.get_mime_type(filename) not in ['image/jpeg', 'image/png']: icopy = get_processed_copy(icopy) if strip_metadata: icopy = get_processed_copy(icopy) if apply_transforms and 'ImageTransforms' in item.meta: icopy = get_processed_copy(icopy) if icopy is not None: h, filename = write_processed_image(icopy) return filename ##todo: potentially insecure because the reference to the file handle gets dropped
def get_jpeg_or_png_image_file(item,collection,size,strip_metadata,apply_transforms=False,filename=''): ''' returns a filename with a jpeg or png of the image associated with item, writing a new copy of the image if necessary ''' if not filename: filename=collection.get_path(item) src_filename=filename icopy=None def get_processed_copy(icopy): if icopy is not None: return icopy icopy = baseobjects.Item(filename) icopy.meta = item.meta.copy() if not load_image(icopy,None,lambda: True, apply_transforms=apply_transforms,itemfile=src_filename): return None,None if 'Orientation' in icopy.meta: del icopy.meta['Orientation'] if 'ImageTransforms' in icopy.meta: del icopy.meta['ImageTransforms'] return icopy def write_processed_image(icopy): import tempfile h,filename=tempfile.mkstemp('.jpg',os.path.splitext(os.path.split(src_filename)[1])[0]) icopy.image.save(filename,quality=95) if not strip_metadata: metadata.copy_metadata(icopy.meta,src_filename,filename) return h,filename if size: if isinstance(size,str): size=tuple(int(dim) for dim in size.split('x')) if isinstance(size,int): size = (size,size) if len(size)>0 and size[0]>0 and size[1]>0: icopy = get_processed_copy(icopy) icopy.image.thumbnail(size,Image.ANTIALIAS) if io.get_mime_type(filename) not in ['image/jpeg','image/png']: icopy = get_processed_copy(icopy) if strip_metadata: icopy = get_processed_copy(icopy) if apply_transforms and 'ImageTransforms' in item.meta: icopy = get_processed_copy(icopy) if icopy is not None: h,filename = write_processed_image(icopy) return filename ##todo: potentially insecure because the reference to the file handle gets dropped
def make_thumb(item, collection, interrupt_fn=None, force=False, cache=None, use_embedded=False, write_to_cache=True): ''' create a thumbnail from the original image using either PIL or dcraw interrupt_fn = callback that returns False if routine should cancel (not implemented) force = True if thumbnail should be recreated even if already present affects thumb, thumburi members of item ''' itemfile = collection.get_path(item) thumb_pb = None if cache == None and thumb_factory.has_valid_failed_thumbnail( itemfile, int(item.mtime)): if not force: item.thumb = False return False print 'Forcing thumbnail creation' uri = io.get_uri(itemfile) thumb_uri = thumb_factory.lookup(uri, int(item.mtime)) if write_to_cache and thumb_uri: os.remove(thumb_uri) if not force and item.thumb == False: return False delete_thumb(item) ##todo: could also try extracting the thumb from the image (essential for raw files) ## would not need to make the thumb in that case print 'Creating thumbnail for', item.uid, itemfile t = time.time() try: uri = io.get_uri(itemfile) mimetype = io.get_mime_type(itemfile) thumb_pb = None if mimetype.lower().startswith('video'): cmd = settings.video_thumbnailer % (itemfile, ) imdata = os.popen(cmd).read() image = Image.open(StringIO.StringIO(imdata)) image.thumbnail( (128, 128), Image.ANTIALIAS) ##TODO: this is INSANELY slow -- find out why else: try: mime = io.get_mime_type(itemfile) if use_embedded and load_embedded_thumb(item, collection): thumb_pb = item.thumb image = None print 'Used embedded thumb' elif not settings.is_windows and mime in gdk_mime_types: #todo: this is completely broken on windows thumb_pb = gtk.gdk.pixbuf_new_from_file_at_size( itemfile, 128, 128) thumb_pb = orient_pixbuf(thumb_pb, item.meta) image = None print 'Opened with GDK' else: image = Image.open(itemfile) image.thumbnail((128, 128), Image.ANTIALIAS) print 'Opened with PIL' except: cmd = settings.dcraw_cmd % (itemfile, ) imdata = os.popen(cmd).read() if not imdata or len(imdata) < 100: cmd = settings.dcraw_backup_cmd % (itemfile, ) imdata = os.popen(cmd).read() # pipe = subprocess.Popen(cmd, shell=True, # stdout=PIPE) ##, close_fds=True # print pipe # pipe=pipe.stdout # print 'pipe opened' # imdata=pipe.read() # print 'pipe read' p = ImageFile.Parser() p.feed(imdata) image = p.close() image.thumbnail((128, 128), Image.ANTIALIAS) image = orient_image(image, item.meta) print 'Opened with DCRAW' if image is not None: thumb_pb = image_to_pixbuf(image) if thumb_pb is None: raise TypeError except: item.thumb = False item.thumburi = None if write_to_cache and cache == None: thumb_factory.create_failed_thumbnail(itemfile, int(item.mtime)) print 'Error creating thumbnail for', item import sys import traceback tb_text = traceback.format_exc(sys.exc_info()[2]) print tb_text return False width = thumb_pb.get_width() height = thumb_pb.get_height() uri = io.get_uri(itemfile) #save the new thumbnail try: if write_to_cache: if cache == None: thumb_factory.save_thumbnail(thumb_pb, uri, int(item.mtime)) item.thumburi = thumb_factory.lookup(uri, int(item.mtime)) else: if not os.path.exists(cache): os.makedirs(cache) item.thumburi = os.path.join( cache, muuid(item.uid + str(int(item.mtime)))) + '.png' thumb_pb.save(item.thumburi, "png") print 'cached at', item.thumburi except: print 'Error caching thumbnail for', item import sys import traceback tb_text = traceback.format_exc(sys.exc_info()[2]) print tb_text item.thumb = False item.thumburi = None if write_to_cache and cache == None: thumb_factory.create_failed_thumbnail(itemfile, int(item.mtime)) return False item.thumb = thumb_pb cache_thumb_in_memory(item) return True
def load_image(item, collection, interrupt_fn, draft_mode=False, apply_transforms=True, itemfile=None): ''' load a PIL image and store it in item.image if transform_handlers are specified and the image has tranforms they will be applied ''' if itemfile is None: itemfile = collection.get_path(item) mimetype = io.get_mime_type(itemfile) oriented = False try: ##todo: load by mimetype (after porting to gio) # non-parsed version if 'original_image' in item.__dict__: image = item.original_image.copy() oriented = True else: if not mimetype.startswith('image'): print 'No image available for item', item, 'with mimetype', mimetype item.image = False return False print 'Loading Image:', item, mimetype if io.get_mime_type( itemfile ) in settings.raw_image_types: ##for extraction with dcraw raise TypeError image = Image.open( itemfile ) ## retain this call even in the parsed version to avoid lengthy delays on raw images (since this call trips the exception) # parsed version if not draft_mode and image.format == 'JPEG': #parser doesn't seem to work correctly on anything but JPEGs f = open(itemfile, 'rb') imdata = f.read(10000) p = ImageFile.Parser() while imdata and len(imdata) > 0: p.feed(imdata) if not interrupt_fn(): return False imdata = f.read(10000) f.close() image = p.close() print 'Parsed image with PIL' else: raise TypeError except: try: if mimetype in gdk_mime_types: image_pb = gtk.gdk.pixbuf_new_from_file(itemfile) image_pb = orient_pixbuf(image_pb, item.meta) print image_pb.get_has_alpha() print image_pb.get_n_channels() print image_pb.get_colorspace() oriented = True width, height = image_pb.get_width(), image_pb.get_height() if image_pb.get_n_channels() >= 3: if image_pb.get_has_alpha(): image = Image.fromstring("RGBA", (width, height), image_pb.get_pixels()) else: image = Image.fromstring("RGB", (width, height), image_pb.get_pixels()) else: print "GDK Parser - Can't handle image with less than 3 channel" raise TypeError print 'Parsed image with GDK' else: if mimetype in settings.raw_image_types: cmd = settings.raw_image_types[mimetype][0] % (itemfile, ) else: cmd = settings.dcraw_cmd % (itemfile, ) imdata = os.popen(cmd).read() if not imdata or len(imdata) < 100: cmd = settings.dcraw_backup_cmd % (itemfile, ) oriented = True imdata = os.popen(cmd).read() if not interrupt_fn(): return False p = ImageFile.Parser() p.feed(imdata) image = p.close() print 'Parsed image with DCRAW' except: import sys import traceback tb_text = traceback.format_exc(sys.exc_info()[2]) print 'Error Loading Image', item, mimetype print tb_text item.image = False return False print item.meta if draft_mode: image.draft(image.mode, (1024, 1024)) ##todo: pull size from screen resolution if not interrupt_fn(): return if oriented: item.image = orient_image(image, {}) else: item.image = orient_image(image, item.meta) try: item.imagergba = 'A' in item.image.getbands() except: item.imagergba = False if item.image: if apply_transforms: transformer.apply_transforms(item, interrupt_fn) cache_image(item) return True return False
def make_thumb(item,collection,interrupt_fn=None,force=False,cache=None,use_embedded=False,write_to_cache=True): ''' create a thumbnail from the original image using either PIL or dcraw interrupt_fn = callback that returns False if routine should cancel (not implemented) force = True if thumbnail should be recreated even if already present affects thumb, thumburi members of item ''' itemfile=collection.get_path(item) thumb_pb=None if cache==None and thumb_factory.has_valid_failed_thumbnail(itemfile,int(item.mtime)): if not force: item.thumb=False return False print 'Forcing thumbnail creation' uri = io.get_uri(itemfile) thumb_uri=thumb_factory.lookup(uri,int(item.mtime)) if write_to_cache and thumb_uri: os.remove(thumb_uri) if not force and item.thumb==False: return False delete_thumb(item) ##todo: could also try extracting the thumb from the image (essential for raw files) ## would not need to make the thumb in that case print 'Creating thumbnail for',item.uid,itemfile t=time.time() try: uri = io.get_uri(itemfile) mimetype=io.get_mime_type(itemfile) thumb_pb=None if mimetype.lower().startswith('video'): cmd=settings.video_thumbnailer%(itemfile,) imdata=os.popen(cmd).read() image=Image.open(StringIO.StringIO(imdata)) image.thumbnail((128,128),Image.ANTIALIAS) ##TODO: this is INSANELY slow -- find out why else: try: mime=io.get_mime_type(itemfile) if use_embedded and load_embedded_thumb(item,collection): thumb_pb = item.thumb image = None print 'Used embedded thumb' elif not settings.is_windows and mime in gdk_mime_types: #todo: this is completely broken on windows thumb_pb = gtk.gdk.pixbuf_new_from_file_at_size(itemfile,128,128) thumb_pb = orient_pixbuf(thumb_pb,item.meta) image = None print 'Opened with GDK' else: image=Image.open(itemfile) image.thumbnail((128,128),Image.ANTIALIAS) print 'Opened with PIL' except: cmd=settings.dcraw_cmd%(itemfile,) imdata=os.popen(cmd).read() if not imdata or len(imdata)<100: cmd=settings.dcraw_backup_cmd%(itemfile,) imdata=os.popen(cmd).read() # pipe = subprocess.Popen(cmd, shell=True, # stdout=PIPE) ##, close_fds=True # print pipe # pipe=pipe.stdout # print 'pipe opened' # imdata=pipe.read() # print 'pipe read' p = ImageFile.Parser() p.feed(imdata) image = p.close() image.thumbnail((128,128),Image.ANTIALIAS) image=orient_image(image,item.meta) print 'Opened with DCRAW' if image is not None: thumb_pb=image_to_pixbuf(image) if thumb_pb is None: raise TypeError except: item.thumb=False item.thumburi=None if write_to_cache and cache==None: thumb_factory.create_failed_thumbnail(itemfile,int(item.mtime)) print 'Error creating thumbnail for',item import sys import traceback tb_text=traceback.format_exc(sys.exc_info()[2]) print tb_text return False width=thumb_pb.get_width() height=thumb_pb.get_height() uri = io.get_uri(itemfile) #save the new thumbnail try: if write_to_cache: if cache==None: thumb_factory.save_thumbnail(thumb_pb,uri,int(item.mtime)) item.thumburi=thumb_factory.lookup(uri,int(item.mtime)) else: if not os.path.exists(cache): os.makedirs(cache) item.thumburi=os.path.join(cache,muuid(item.uid+str(int(item.mtime))))+'.png' thumb_pb.save(item.thumburi,"png") print 'cached at',item.thumburi except: print 'Error caching thumbnail for',item import sys import traceback tb_text=traceback.format_exc(sys.exc_info()[2]) print tb_text item.thumb=False item.thumburi=None if write_to_cache and cache==None: thumb_factory.create_failed_thumbnail(itemfile,int(item.mtime)) return False item.thumb=thumb_pb cache_thumb_in_memory(item) return True
def load_image(item,collection,interrupt_fn,draft_mode=False,apply_transforms=True,itemfile=None): ''' load a PIL image and store it in item.image if transform_handlers are specified and the image has tranforms they will be applied ''' if itemfile is None: itemfile=collection.get_path(item) mimetype=io.get_mime_type(itemfile) oriented=False try: ##todo: load by mimetype (after porting to gio) # non-parsed version if 'original_image' in item.__dict__: image=item.original_image.copy() oriented=True else: if not mimetype.startswith('image'): print 'No image available for item',item,'with mimetype',mimetype item.image=False return False print 'Loading Image:',item,mimetype if io.get_mime_type(itemfile) in settings.raw_image_types: ##for extraction with dcraw raise TypeError image=Image.open(itemfile) ## retain this call even in the parsed version to avoid lengthy delays on raw images (since this call trips the exception) # parsed version if not draft_mode and image.format=='JPEG': #parser doesn't seem to work correctly on anything but JPEGs f=open(itemfile,'rb') imdata=f.read(10000) p = ImageFile.Parser() while imdata and len(imdata)>0: p.feed(imdata) if not interrupt_fn(): return False imdata=f.read(10000) f.close() image = p.close() print 'Parsed image with PIL' else: raise TypeError except: try: if mimetype in gdk_mime_types: image_pb=gtk.gdk.pixbuf_new_from_file(itemfile) image_pb=orient_pixbuf(image_pb,item.meta) print image_pb.get_has_alpha() print image_pb.get_n_channels() print image_pb.get_colorspace() oriented=True width,height = image_pb.get_width(),image_pb.get_height() if image_pb.get_n_channels() >=3: if image_pb.get_has_alpha(): image=Image.fromstring("RGBA",(width,height),image_pb.get_pixels() ) else: image=Image.fromstring("RGB",(width,height),image_pb.get_pixels() ) else: print "GDK Parser - Can't handle image with less than 3 channel" raise TypeError print 'Parsed image with GDK' else: if mimetype in settings.raw_image_types: cmd=settings.raw_image_types[mimetype][0]%(itemfile,) else: cmd=settings.dcraw_cmd%(itemfile,) imdata=os.popen(cmd).read() if not imdata or len(imdata)<100: cmd=settings.dcraw_backup_cmd%(itemfile,) oriented=True imdata=os.popen(cmd).read() if not interrupt_fn(): return False p = ImageFile.Parser() p.feed(imdata) image = p.close() print 'Parsed image with DCRAW' except: import sys import traceback tb_text=traceback.format_exc(sys.exc_info()[2]) print 'Error Loading Image',item,mimetype print tb_text item.image=False return False print item.meta if draft_mode: image.draft(image.mode,(1024,1024)) ##todo: pull size from screen resolution if not interrupt_fn(): return if oriented: item.image=orient_image(image,{}) else: item.image=orient_image(image,item.meta) try: item.imagergba='A' in item.image.getbands() except: item.imagergba=False if item.image: if apply_transforms: transformer.apply_transforms(item,interrupt_fn) cache_image(item) return True return False