1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- """
- Utility functions for handling images.
- Requires Pillow as you might imagine.
- """
- import struct
- import zlib
- from django.core.files import File
- class ImageFile(File):
- """
- A mixin for use alongside django.core.files.base.File, which provides
- additional features for dealing with images.
- """
- @property
- def width(self):
- return self._get_image_dimensions()[0]
- @property
- def height(self):
- return self._get_image_dimensions()[1]
- def _get_image_dimensions(self):
- if not hasattr(self, '_dimensions_cache'):
- close = self.closed
- self.open()
- self._dimensions_cache = get_image_dimensions(self, close=close)
- return self._dimensions_cache
- def get_image_dimensions(file_or_path, close=False):
- """
- Returns 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.
- """
- from PIL import ImageFile as PillowImageFile
- p = PillowImageFile.Parser()
- if hasattr(file_or_path, 'read'):
- file = file_or_path
- file_pos = file.tell()
- file.seek(0)
- else:
- file = open(file_or_path, 'rb')
- close = True
- try:
- # 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 = 1024
- while 1:
- data = file.read(chunk_size)
- if not data:
- break
- try:
- p.feed(data)
- except zlib.error as e:
- # ignore zlib complaining on truncated stream, just feed more
- # data to parser (ticket #19457).
- if e.args[0].startswith("Error -5"):
- pass
- else:
- raise
- except struct.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).
- pass
- if p.image:
- return p.image.size
- chunk_size *= 2
- return (None, None)
- finally:
- if close:
- file.close()
- else:
- file.seek(file_pos)
|