def thumbnail(filename, thumb_path, width, height): _, tmp_thumb_path = tempfile.mkstemp(prefix="ojo_thumbnail_") def use_pil(): pil = get_pil(filename, width, height) try: pil.save(tmp_thumb_path, "JPEG") except Exception: logging.exception("Could not save thumbnail in format %s:" % format) raise def use_pixbuf(): pixbuf = get_pixbuf(filename, width, height) pixbuf.savev(tmp_thumb_path, "png", [], []) cache_dir = os.path.dirname(thumb_path) if not os.path.exists(cache_dir): os.makedirs(cache_dir) if ext(filename) in {".gif", ".png", ".svg", ".xpm"}.union(RAW_FORMATS): try: use_pixbuf() except Exception: use_pil() else: try: use_pil() except Exception: use_pixbuf() os.rename(tmp_thumb_path, thumb_path) return filename, thumb_path
def is_image(filename): """Decide if something might be a supported image based on extension""" try: return os.path.isfile(filename) and ext( filename) in get_supported_image_extensions() except Exception: return False
def read(self, filename): try: if imaging.exiftool is None or not imaging.exiftool.running: return None meta = imaging.exiftool.get_metadata(filename) meta["SourceFile"] = { "desc": "Source File", "val": meta["SourceFile"] } # also cache the most important part needs_rot = needs_rotation(meta) stat = os.stat(filename) result = { "filename": os.path.basename(filename), "needs_rotation": needs_rot, "width": meta["ImageWidth" if not needs_rot else "ImageHeight"]["val"], "height": meta["ImageHeight" if not needs_rot else "ImageWidth"]["val"], "orientation": meta.get("Orientation", {"val": None})["val"], "file_date": stat.st_mtime, "file_size": stat.st_size, "exif": meta, } if ext(filename) == ".svg": # svg sizing is special, exiftool could return things like "270mm" which causes # exceptions downstream, as width and height are expected to be numbers. # So use size from pixbuf, it works OK for svgs. meta_svg = self.read_via_pixbuf(filename) result["width"] = meta_svg["width"] result["height"] = meta_svg["height"] return result except Exception: logging.exception("Could not parse meta-info for %s" % filename) return None
def get_cached_thumbnail_path(filename, force_cache=False, thumb_height=None): # Use gifs directly - webkit will handle transparency, animation, etc. if not force_cache and ext(filename) == ".gif": return filename if thumb_height is None: thumb_height = options["thumb_height"] # we append modification time to ensure we're not using outdated cached images mtime = os.path.getmtime(filename) hash = hashlib.md5(_bytes(filename + "{0:.2f}".format(mtime))).hexdigest() # we use .2 precision to keep the same behavior of getmtime as under Python 2 folder = os.path.dirname(filename) if folder.startswith(os.sep): folder = folder[1:] return os.path.join( Thumbs.get_thumbs_cache_dir(thumb_height), # cache folder root folder, # mirror the original directory structure os.path.basename(filename) + "_" + hash + ".jpg", ) # filename + hash of the name & time
def get_pixbuf(filename, width=None, height=None): meta = metadata.get(filename) orientation = meta["orientation"] image_width, image_height = meta["width"], meta["height"] def _from_preview(): try: with tempfile.TemporaryDirectory(prefix="ojo") as to_folder: optimal_preview = get_optimal_preview(filename, to_folder, width, height) pixbuf = pixbuf_from_file(optimal_preview) pixbuf = auto_rotate_pixbuf(orientation, pixbuf) logging.debug("Loaded from preview") return pixbuf except Exception: return None # below we'll use another method def _from_gdk_pixbuf(): try: pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename) pixbuf = auto_rotate_pixbuf(orientation, pixbuf) logging.debug("Loaded directly") return pixbuf except GObject.GError: return None # below we'll use another method def _from_pil(): try: pixbuf = pil_to_pixbuf(get_pil(filename)) logging.debug("Loaded with PIL") return pixbuf except: return None if ext(filename) in RAW_FORMATS: # raw file, prefer preview with max size pixbuf = _from_preview() if not pixbuf: pixbuf = _from_gdk_pixbuf() else: # ordinary image, prefer loading with GdkPixbuf directly # (previews here might be present, but wrong) pixbuf = _from_gdk_pixbuf() if not pixbuf: pixbuf = _from_preview() if not pixbuf: pixbuf = _from_pil() if not pixbuf: raise Exception("Could not load %s" % filename) if width is not None and (width < image_width or height < image_height): # scale it if float(width) / height < float(image_width) / image_height: pixbuf = pixbuf.scale_simple( width, int(float(width) * image_height / image_width), GdkPixbuf.InterpType.BILINEAR) else: pixbuf = pixbuf.scale_simple( int(float(height) * image_width / image_height), height, GdkPixbuf.InterpType.BILINEAR, ) return pixbuf