Source code for jasy.asset.ImageInfo

#
# Jasy - Web Tooling Framework
# Copyright 2010-2012 Zynga Inc.
# Copyright 2013-2014 Sebastian Werner
#

import struct

import jasy.core.Console as Console
import jasy.core.File as File

"""
Contains image format detection classes. Once the format is detect it supports image size detection, too.
"""


[docs]class ImgFile(object): """Abstract base class for all image types.""" def __init__(self, filename): try: self.fp = open(filename, "rb") except IOError as err: Console.error("Could not open file: %s" % filename) raise err
[docs] def verify(self): raise NotImplementedError("%s: %s" % (self.__class__, "verify()"))
[docs] def type(self): raise NotImplementedError("%s: %s" % (self.__class__, "type()"))
[docs] def size(self): raise NotImplementedError("%s: %s" % (self.__class__, "size()"))
[docs] def close(self): self.fp.close()
[docs] def getChecksum(self): return File.sha1(self.fp)
def __del__(self): self.close()
# http://www.w3.org/Graphics/GIF/spec-gif89a.txt
[docs]class GifFile(ImgFile): """Class for parsing GIF files."""
[docs] def verify(self): self.fp.seek(0) header = self.fp.read(6) signature = struct.unpack("3s3s", header[:6]) isGif = signature[0] == b"GIF" and signature[1] in [b"87a", b"89a"] return isGif
[docs] def type(self): return "gif"
[docs] def size(self): self.fp.seek(0) header = self.fp.read(6 + 6) (width, height) = struct.unpack("<HH", header[6:10]) return width, height
# http://www.libmng.com/pub/png/spec/1.2/png-1.2-pdg.html#Structure
[docs]class PngFile(ImgFile): """Class for parsing PNG files."""
[docs] def type(self): return "png"
[docs] def verify(self): self.fp.seek(0) header = self.fp.read(8) signature = struct.pack("8B", 137, 80, 78, 71, 13, 10, 26, 10) isPng = header[:8] == signature return isPng
[docs] def size(self): self.fp.seek(0) header = self.fp.read(8 + 4 + 4 + 13 + 4) ihdr = struct.unpack("!I4s", header[8:16]) data = struct.unpack("!II5B", header[16:29]) (width, height, bitDepth, colorType, compressionMethod, filterMethod, interleaceMethod) = data return (width, height)
# http://www.obrador.com/essentialjpeg/HeaderInfo.htm
[docs]class JpegFile(ImgFile):
[docs] def verify(self): self.fp.seek(0) signature = struct.unpack("!H", self.fp.read(2)) isJpeg = signature[0] == 0xFFD8 return isJpeg
[docs] def type(self): return "jpeg"
[docs] def size(self): self.fp.seek(0) self.fp.read(2) b = self.fp.read(1) try: while (b and ord(b) != 0xDA): while (ord(b) != 0xFF): b = self.fp.read(1) while (ord(b) == 0xFF): b = self.fp.read(1) if (ord(b) >= 0xC0 and ord(b) <= 0xC3): self.fp.read(3) h, w = struct.unpack(">HH", self.fp.read(4)) break else: self.fp.read(int(struct.unpack(">H", self.fp.read(2))[0]) - 2) b = self.fp.read(1) width = int(w) height = int(h) return (width, height) except struct.error: pass except ValueError: pass
[docs]class ImgInfo(object): def __init__(self, filename): self.__filename = filename classes = [PngFile, GifFile, JpegFile]
[docs] def getSize(self): """ Returns the image sizes of png, gif and jpeg files as. (width, height) tuple """ filename = self.__filename classes = self.classes for cls in classes: img = cls(filename) if img.verify(): size = img.size() if size is not None: img.close() return size img.close() return 0, 0
[docs] def getInfo(self): """Returns (width, height, "type") of the image.""" filename = self.__filename classes = self.classes for cls in classes: img = cls(filename) if img.verify(): return (img.size()[0], img.size()[1], img.type()) return None
[docs] def getChecksum(self): img = ImgFile(self.__filename) checksum = img.getChecksum() img.close() return checksum