home *** CD-ROM | disk | FTP | other *** search
- # -*- coding: utf-8 -*-
- #
- # (c) Copyright 2001-2006 Hewlett-Packard Development Company, L.P.
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- #
- # Author: Don Welch
-
- #
- # Ported from Perl's Image::Size module by Randy J. Ray
- #
-
- import os, os.path, re, struct
-
-
- xbm_pat = re.compile(r'^\#define\s*\S*\s*(\d+)\s*\n\#define\s*\S*\s*(\d+)', re.IGNORECASE)
- xpm_pat = re.compile(r'"\s*(\d+)\s+(\d+)(\s+\d+\s+\d+){1,2}\s*"', re.IGNORECASE)
- ppm_pat1 = re.compile(r'^\#.*', re.IGNORECASE | re.MULTILINE)
- ppm_pat2 = re.compile(r'^(P[1-6])\s+(\d+)\s+(\d+)', re.IGNORECASE)
- ppm_pat3 = re.compile(r'IMGINFO:(\d+)x(\d+)', re.IGNORECASE)
- tiff_endian_pat = re.compile(r'II\x2a\x00')
-
-
-
- def readin(stream, length, offset=0):
- if offset != 0:
- stream.seek(offset, 0)
-
- return stream.read(length)
-
-
- def xbmsize(stream):
- width, height = -1, -1
- match = xbm_pat.match(readin(stream,1024))
-
- try:
- width = int(match.group(1))
- height = int(match.group(2))
- except:
- pass
-
- return width, height
-
-
- def xpmsize(stream):
- width, height = -1, -1
- match = re.search(xpm_pat, readin(stream, 1024))
- try:
- width = int(match.group(1))
- height = int(match.group(2))
- except:
- pass
-
- return width, height
-
-
- def pngsize(stream): # also does MNG
- width, height = -1, -1
-
- if readin(stream, 4, 12) in ('IHDR', 'MHDR'):
- height, width = struct.unpack("!II", stream.read(8))
-
- return width,height
-
-
- def jpegsize(stream):
- width, height = -1, -1
- stream.seek(2)
- while True:
- length = 4
- buffer = readin(stream, length)
- try:
- marker, code, length = struct.unpack("!c c h", buffer)
- except:
- break
-
- if marker != '\xff':
- break
-
- if 0xc0 <= ord(code) <= 0xc3:
- length = 5
- height, width = struct.unpack("!xhh", readin(stream, length))
-
- else:
- readin(stream, length-2)
-
- return width, height
-
-
- def ppmsize(stream):
- width, height = -1, -1
- header = re.sub(ppm_pat1, '', readin(stream, 1024))
- match = ppm_pat2.match(header)
- typ = ''
- try:
- typ = match.group(1)
- width = int(match.group(2))
- height = int(match.group(3))
- except:
- pass
-
- if typ == 'P7':
- match = ppm_pat3.match(header)
-
- try:
- width = int(match.group(1))
- height = int(match.group(2))
- except:
- pass
-
- return width, height
-
-
- def tiffsize(stream):
- header = readin(stream, 4)
- endian = ">"
- match = tiff_endian_pat.match(header)
-
- if match is not None:
- endian = "<"
-
- input = readin(stream, 4, 4)
- offset = struct.unpack('%si' % endian, input)[0]
- num_dirent = struct.unpack('%sH' % endian, readin(stream, 2, offset))[0]
- offset += 2
- num_dirent = offset+(num_dirent*12)
- width, height = -1, -1
-
- while True:
- ifd = readin(stream, 12, offset)
-
- if ifd == '' or offset > num_dirent:
- break
-
- offset += 12
- tag = struct.unpack('%sH'% endian, ifd[0:2])[0]
- type = struct.unpack('%sH' % endian, ifd[2:4])[0]
-
- if tag == 0x0100:
- width = struct.unpack("%si" % endian, ifd[8:12])[0]
-
- elif tag == 0x0101:
- height = struct.unpack("%si" % endian, ifd[8:12])[0]
-
- return width, height
-
-
- def bmpsize(stream):
- width, height = struct.unpack("<II", readin(stream, 8, 18))
- return width, height
-
-
- def gifsize(stream):
- # since we only care about the printed size of the image
- # we only need to get the logical screen sizes, which are
- # the maximum extents of the image. This code is much simpler
- # than the code from Image::Size
- #width, height = -1, -1
- buf = readin(stream, 7, 6) # LSx, GCTF, etc
- height, width, flags, bci, par = struct.unpack('<HHBBB', buf)
-
- return width, height
-
-
-
-
- TYPE_MAP = {re.compile('^GIF8[7,9]a') : ('image/gif', gifsize),
- re.compile("^\xFF\xD8") : ('image/jpeg', jpegsize),
- re.compile("^\x89PNG\x0d\x0a\x1a\x0a") : ('image/png', pngsize),
- re.compile("^P[1-7]") : ('image/x-portable-pixmap', ppmsize),
- re.compile('\#define\s+\S+\s+\d+') : ('image/x-xbitmap', xbmsize),
- re.compile('\/\* XPM \*\/') : ('image/x-xpixmap', xpmsize),
- re.compile('^MM\x00\x2a') : ('image/tiff', tiffsize),
- re.compile('^II\*\x00') : ('image/tiff', tiffsize),
- re.compile('^BM') : ('image/x-bitmap', bmpsize),
- re.compile("^\x8aMNG\x0d\x0a\x1a\x0a") : ('image/png', pngsize),
- }
-
-
- def imagesize(filename, mime_type=''):
- width, height = -1, -1
-
- f = file(filename, 'r')
- buffer = f.read(4096)
-
- if not mime_type:
- for t in TYPE_MAP:
- match = t.search(buffer)
- if match is not None:
- mime_type, func = TYPE_MAP[t]
- break
-
- if mime_type and func:
- f.seek(0)
- width, height = func(f)
- else:
- width, height = -1, -1
-
- f.close()
-
- return height, width, mime_type
-
-