On 6 16 , 6 27 , Adam Teale <[EMAIL PROTECTED]> wrote: > hey guys > > Is there a builtin/standard install method in python for retrieving or > finding out an image's dimensions? Sorry, after i review these code in http://www.pycode.com/modules/?id=32, i found some(not just a few) *BUGS* in it. I must apologize to you for this. I have rewrite the moudle. please have a try.
"""Recognize image file formats and size based on their first few bytes.""" # Perl Image::Size module clone # see more http://search.cpan.org/author/RJRAY/Image-Size-3.01/lib/Image/Size.pm # rewrited by jigloo([EMAIL PROTECTED]) # GPL-2 license __all__ = ["what", "imgsz", "size"] import os # for os.path os.error sys.stderr import StringIO # for StringIO.StringIO import struct # for unpack import re # for regex # jpegsize: gets the width and height (in pixels) of a jpeg file # def jpegsize(stream): (x, y, error) = (None, None, "could not determine JPEG size") # Dummy read to skip header ID stream.read(2) while True: # Extract the segment header. (marker, code, length) = struct.unpack("!BBH", stream.read(4)) # Verify that it's a valid segment. if marker != 0xFF: # Was it there? error = "JPEG marker not found" break elif code >= 0xC0 and code <= 0xC3: # Segments that contain size info (y, x) = struct.unpack("!xHH", stream.read(5)) error = "no error" break else: # Dummy read to skip over data stream.read(length - 2) return ("JPEG", x, y, error) # bmpsize: size a Windows-ish BitMaP image # def bmpsize(stream): (x, y, error) = (None, None, "Unable to determine size of BMP data") # Dummy read to skip header data stream.read(18) (x, y) = struct.unpack("<LL", stream.read(8)) if x > 0 and y > 0: error = "no error" return ("BMP", x, y, error) # pngsize : gets the width & height (in pixels) of a png file # cor this program is on the cutting edge of technology! (pity it's blunt!) # def pngsize(stream): (x, y, error) = (None, None, "could not determine PNG size") # Dummy read to skip header data stream.read(12) if stream.read(4) == "IHDR": (x, y) = struct.unpack("!LL", stream.read(8)) error = "no error" return ("PNG", x, y, error) # gifsize : Subroutine gets the size of the specified GIF # # Default behavior for GIFs is to return the "screen" size GIF_BEHAVIOR = 0 # def gifsize(stream): if GIF_BEHAVIOR > 2: return ("GIF", 0, 0, "Out-of-range value for GIF_BEHAVIOR: %d" % GIF_BEHAVIOR) # Skip over the identifying string, since we already know this is a GIF type = stream.read(6) buf = stream.read(5) if len(buf) != 5: return ("GIF", 0, 0, "Invalid/Corrupted GIF (bad header)") (sw, sh, x) = struct.unpack("<HHB", buf) if GIF_BEHAVIOR == 0: return ("GIF", sw, sh, "no error") return ("GIF", None, None, "Invalid/Corrupted GIF (missing image header?)") # ppmsize : gets data on the PPM/PGM/PBM family. # def ppmsize(stream): (mime, x, y, error) = ("PPM", None, None, "Unable to determine size of PPM/PGM/PBM data") header = stream.read(1024) # PPM file of some sort re.sub(r"^\#.*", "", header, re.M) m = re.match(r"^(P[1-6])\s+(\d+)\s+(\d+)", header, re.S) if m: (n, x, y) = m.group(1, 2, 3) mime = {"P1":"PBM", "P2":"PGM", "P3":"PPM", "P4":"BPM", "P5":"PGM", "P6":"PPM"}[n] if n == "P7": mime = "XV" m = re.match(r"IMGINFO:(\d+)x(\d+)", header, re.S) if m: (x, y) = m.group(1, 2) error = "no error" return (mime, int(x), int(y), error) else: return (mime, x, y, error) # xbmsize : # def xbmsize(stream): (x, y, error) = (None, None, "could not determine XBM size") header = stream.read(1024) m = re.match(r"^\#define\s*\S*\s*(\d+)\s*\n\#define\s*\S*\s*(\d+)", header, re.S|re.I) if m: (x, y) = m.group(1, 2) error = "no error" return ("XBM", int(x), int(y), error) else: return ("XBM", x, y, error) # Size an XPM file by looking for the "X Y N W" line, where X and Y are # dimensions, N is the total number of colors defined, and W is the width of # a color in the ASCII representation, in characters. We only care about X & Y. def xpmsize(stream): (x, y, error) = (None, None, "could not determine XPM size") while True: line = stream.readline() if line == "": break m = re.compile(r"\s*(\d+)\s+(\d+)(\s+\d+\s+\d+){1,2}\s*", re.M).match(line, 1) if m: (x, y) = map(lambda x: int(x), m.group(1, 2)) error = "no error" break return ("XPM", x, y, error) # tiffsize : size a TIFF image # def tiffsize(stream): (x, y, error) = (None, None, "Unable to determine size of TIFF data") be = "!" # Default to big-endian; I like it better if stream.read(4) == "II\x2a\x00": # little-endian be = "<" # Set up an association between data types and their corresponding # pack/unpack specification. Don't take any special pains to deal with # signed numbers; treat them as unsigned because none of the image # dimensions should ever be negative. (I hope.) packspec = [ None, # nothing (shouldn't happen) "Bxxx", # BYTE (8-bit unsigned integer) None, # ASCII be+"Hxx", # SHORT (16-bit unsigned integer) be+"L", # LONG (32-bit unsigned integer) None, # RATIONAL "bxxx", # SBYTE (8-bit signed integer) None, # UNDEFINED be+"Hxx", # SSHORT (16-bit unsigned integer) be+"L" # SLONG (32-bit unsigned integer) ] offset = struct.unpack(be+"L", stream.read(4))[0] # Get offset to IFD ifd = stream.read(2) # Get number of directory entries num_dirent = struct.unpack(be+"H", ifd)[0] # Make it useful num_dirent = offset + (num_dirent * 12) # Calc. maximum offset of IFD # Do all the work ifd = '' tag = 0 type = 0 while x is None or y is None: ifd = stream.read(12) # Get first directory entry if ifd == "" or stream.tell() > num_dirent: break tag = struct.unpack(be+"H", ifd[:2])[0] # ...and decode its tag type = struct.unpack(be+"H", ifd[2:2+2])[0] # ...and the data type # Check the type for sanity. if type > len(packspec) or packspec[type] is None: continue if tag == 0x0100: # ImageWidth (x) # Decode the value x = struct.unpack(packspec[type], ifd[8:4+8])[0] elif tag == 0x0101: # ImageLength (y) # Decode the value y = struct.unpack(packspec[type], ifd[8:4+8])[0] # Decide if we were successful or not if x and y: error = "no error" else: error = "" if x is None: error = "ImageWidth " if y is None: if error != "": error = error + "and " error = error + "ImageWidth " error = error + "tag(s) could not be found" return ("TIFF", x, y, error) # psdsize : determine the size of a PhotoShop save-file (*.PSD) # def psdsize(stream): (x, y, error) = (None, None, "could not determine PSD size") stream.read(14) (y, x) = struct.unpack("!LL", stream.read(8)) if x > 0 and y > 0: error = "no error" return ("PSD", x, y, error) # pcdsize : # Kodak photo-CDs are weird. Don't ask me why, you really don't want details. PCD_MAP = { "base/16" : [ 192, 128 ], "base/4" : [ 384, 256 ], "base" : [ 768, 512 ], "base4" : [ 1536, 1024 ], "base16" : [ 3072, 2048 ], "base64" : [ 6144, 4096 ]} # Default scale for PCD images PCD_SCALE = "base"; # def pcdsize(stream): (x, y, error) = (None, None, "Unable to determine size of PCD data") buff = strean.read(0xf00) if buff[0x800:3+0x800] != "PCD": error = "Invalid/Corrupted PCD (bad header)" return ("PCD", x, y, error) orient = ord(buff[0x0e02:1+0x0e02]) & 1 # Clear down to one bit if orient: (x, y) = PCD_MAP[PCD_SCALE] else: (y, x) = PCD_MAP[PCD_SCALE] error = "no error" return ("PCD", x, y, error) # swfsize : # def swfsize(stream): (x, y, error) = (None, None, "not implemented. --I hate swf :(") return ("SWF", x, y, error) # swfmxsize : # def swfmxsize(stream): (x, y, error) = (None, None, "not implemented. --I hate swf :(") return ("SWF", x, y, error) # mngsize : gets the width and height (in pixels) of an MNG file. # # Basically a copy of pngsize. def mngsize(stream): (x, y, error) = (None, None, "could not determine MNG size") stream.read(12) if stream.read(4) == "MHDR": # MHDR = Image Header (x, y) = struct.unpack("!LL", stream.read(8)) error = "MNG" else: error = "Invalid/Corrupted MNG (bad header)" return ("MNG", x, y, error) # type_map used in function type_map_match type_map = { re.compile(r"^\xFF\xD8") : ["JPEG", jpegsize], re.compile(r"^BM") : ["BMP", bmpsize], re.compile(r"^\x89PNG\x0d\x0a\x1a\x0a") : ["PNG", pngsize], re.compile(r"^P[1-7]") : ["PPM", ppmsize], # also XVpics re.compile(r"\#define\s+\S+\s+\d+") : ["XBM", xbmsize], re.compile(r"\/\* XPM \*\/") : ["XPM", xpmsize], re.compile(r"^MM\x00\x2a") : ["TIFF", tiffsize], re.compile(r"^II\x2a\x00") : ["TIFF", tiffsize], re.compile(r"^8BPS") : ["PSD", psdsize], re.compile(r"^PCD_OPA") : ["PCD", pcdsize], re.compile(r"^FWS") : ["SWF", swfsize], re.compile(r"^CWS") : ["SWF", swfmxsize], re.compile(r"^\x8aMNG\x0d\x0a\x1a\x0a") : ["MNG", mngsize], re.compile(r"^GIF8[7,9]a") : ["GIF", gifsize]} # type_map_match to get MIME-TYPE and callback function def type_map_match(buffer): for rx in type_map.keys(): if rx.match(buffer): return type_map[rx] else: return None # Recognize image headers # def what(filename): try: f = open(filename, "rb") h = f.read(512) except IOError: print "IOError %s\n" % os.error finally: if f: f.close() m = type_map_match(h) if m: return m[0] return None # size: size a image from buffer # def size(buffer): m = type_map_match(buffer) if m: return (m[1])(StringIO.StringIO(buffer)) else: return (None, None, None, "Unable to Recognize image file format") # imgsz: size a image by file name # def imgsz(path): (type, x, y, error) = (None, None, None, "Unable to Recognize image file format") f = None try: f = open(path, "rb") header = f.read(256) f.seek(0) m = type_map_match(header) if m: (type, x, y, error) = (m[1])(f) except: print "IOError %s\n" % os.error return None finally: if f: f.close() return (type, x, y, error) if __name__ == "__main__": for filename in [f for f in os.listdir(".") if os.path.isfile(f)]: print filename, imgsz(filename) > > A quick google found me > this:http://www.pythonware.com/library/pil/handbook/introduction.htm > > but it looks like it is something I will need to install - I'd like to > be able to pass my script around to people without them needing any > additional modules > > Any help would be fantastic! > > Cheers > > Adam > python 2.3.5 > osx 10.4.9 -- http://mail.python.org/mailman/listinfo/python-list