"""Utility functions for handling images.Requires Pillow as you might imagine."""importstructimportzlibfromgingerdj.core.filesimportFile
[docs]classImageFile(File):""" A mixin for use alongside gingerdj.core.files.base.File, which provides additional features for dealing with images. """@propertydefwidth(self):returnself._get_image_dimensions()[0]@propertydefheight(self):returnself._get_image_dimensions()[1]def_get_image_dimensions(self):ifnothasattr(self,"_dimensions_cache"):close=self.closedself.open()self._dimensions_cache=get_image_dimensions(self,close=close)returnself._dimensions_cache
defget_image_dimensions(file_or_path,close=False):""" Return the (width, height) of an image, given an open file or a path. Set 'close' to True to close the file at the end if it is initially in an open state. """fromPILimportImageFileasPillowImageFilep=PillowImageFile.Parser()ifhasattr(file_or_path,"read"):file=file_or_pathfile_pos=file.tell()file.seek(0)else:try:file=open(file_or_path,"rb")exceptOSError:return(None,None)close=Truetry:# Most of the time Pillow only needs a small chunk to parse the image# and get the dimensions, but with some TIFF files Pillow needs to# parse the whole file.chunk_size=1024while1:data=file.read(chunk_size)ifnotdata:breaktry:p.feed(data)exceptzlib.errorase:# ignore zlib complaining on truncated stream, just feed more# data to parser (ticket #19457).ife.args[0].startswith("Error -5"):passelse:raiseexceptstruct.error:# Ignore PIL failing on a too short buffer when reads return# less bytes than expected. Skip and feed more data to the# parser (ticket #24544).passexceptRuntimeError:# e.g. "RuntimeError: could not create decoder object" for# WebP files. A different chunk_size may work.passifp.image:returnp.image.sizechunk_size*=2return(None,None)finally:ifclose:file.close()else:file.seek(file_pos)