retrieve / find out an image's dimensions

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Adam Teale

    #1

    retrieve / find out an image's dimensions

    hey guys

    Is there a builtin/standard install method in python for retrieving or
    finding out an image's dimensions?

    A quick google found me this:
    http://www.pythonware.com/library/pi...troduction.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

  • jigloo

    #2
    Re: retrieve / find out an image's dimensions



    On 6 16 , 6 27 , Adam Teale <a...@lumanatio n.comwrote:
    hey guys
    >
    Is there a builtin/standard install method in python for retrieving or
    finding out an image's dimensions?
    >
    A quick google found me this:http://www.pythonware.com/library/pi...troduction.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

    Comment

    • jigloo

      #3
      Re: retrieve / find out an image's dimensions

      On 6 16 , 6 27 , Adam Teale <a...@lumanatio n.comwrote:
      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.


      """Recogniz e 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.pm
      # rewrited by jigloo(phus@liv e.com)
      # GPL-2 license

      __all__ = ["what", "imgsz", "size"]

      import os # for os.path os.error sys.stderr
      import StringIO # for StringIO.String IO
      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(len gth - 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(102 4)
      # 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"IMGI NFO:(\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(102 4)

      m = re.match(r"^\#d efine\s*\S*\s*( \d+)\s*\n\#defi ne\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(lin e, 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(b e+"L", stream.read(4))[0] # Get offset to IFD

      ifd = stream.read(2) # Get number of directory entries
      num_dirent = struct.unpack(b e+"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(b e+"H", ifd[:2])[0] # ...and decode its tag
      type = struct.unpack(b e+"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(p ackspec[type], ifd[8:4+8])[0]
      elif tag == 0x0101: # ImageLength (y)
      # Decode the value
      y = struct.unpack(p ackspec[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(0xf 00)
      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(strea m):
      (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"^B M") : ["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"^M M\x00\x2a") : ["TIFF", tiffsize],
      re.compile(r"^I I\x2a\x00") : ["TIFF", tiffsize],
      re.compile(r"^8 BPS") : ["PSD", psdsize],
      re.compile(r"^P CD_OPA") : ["PCD", pcdsize],
      re.compile(r"^F WS") : ["SWF", swfsize],
      re.compile(r"^C WS") : ["SWF", swfmxsize],
      re.compile(r"^\ x8aMNG\x0d\x0a\ x1a\x0a") : ["MNG", mngsize],
      re.compile(r"^G IF8[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.Stri ngIO(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/pi...troduction.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

      Comment

      Working...