# ##################################################
# AlbumEXIF.py
# Handle EXIF data collected by EXIFbp.py
# ##################################################
# Module of PyAlbum (http://pyalbum.sourceforge.net)
# (c) 2004 Bernd Preusing <bernd@preusing.de>
# License: GPL
#   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
# ##################################################



########################################
# This part is from PIL.JpegImagePlugin V 0.5
# It skipped the part 0xFFFE (COM), but this is just
# the part we need!
########################################
def i16(c,o=0):
	return ord(c[o+1]) + (ord(c[o])<<8)

def i32(c,o=0):
	return ord(c[o+3]) + (ord(c[o+2])<<8) + (ord(c[o+1])<<16) + (ord(c[o])<<24)

#
# Parser
def Skip(self, marker):
	self.fp.read(i16(self.fp.read(2))-2)

def COM(self, marker):
	#
	# COM comment 0xFFFE
	#
	s = self.fp.read(i16(self.fp.read(2))-2)
	self.COM = s

#
# JPEG marker table
MARKER = {
	0xFFC0: ("SOF0", "Baseline DCT", Skip),
	0xFFC1: ("SOF1", "Extended Sequential DCT", Skip),
	0xFFC2: ("SOF2", "Progressive DCT", Skip),
	0xFFC3: ("SOF3", "Spatial lossless", Skip),
	0xFFC4: ("DHT", "Define Huffman table", Skip),
	0xFFC5: ("SOF5", "Differential sequential DCT", Skip),
	0xFFC6: ("SOF6", "Differential progressive DCT", Skip),
	0xFFC7: ("SOF7", "Differential spatial", Skip),
	0xFFC8: ("JPG", "Extension", None),
	0xFFC9: ("SOF9", "Extended sequential DCT (AC)", Skip),
	0xFFCA: ("SOF10", "Progressive DCT (AC)", Skip),
	0xFFCB: ("SOF11", "Spatial lossless DCT (AC)", Skip),
	0xFFCC: ("DAC", "Define arithmetic coding conditioning", Skip),
	0xFFCD: ("SOF13", "Differential sequential DCT (AC)", Skip),
	0xFFCE: ("SOF14", "Differential progressive DCT (AC)", Skip),
	0xFFCF: ("SOF15", "Differential spatial (AC)", Skip),
	0xFFD0: ("RST0", "Restart 0", None),
	0xFFD1: ("RST1", "Restart 1", None),
	0xFFD2: ("RST2", "Restart 2", None),
	0xFFD3: ("RST3", "Restart 3", None),
	0xFFD4: ("RST4", "Restart 4", None),
	0xFFD5: ("RST5", "Restart 5", None),
	0xFFD6: ("RST6", "Restart 6", None),
	0xFFD7: ("RST7", "Restart 7", None),
	0xFFD8: ("SOI", "Start of image", None),
	0xFFD9: ("EOI", "End of image", None),
	0xFFDA: ("SOS", "Start of scan", Skip),
	0xFFDB: ("DQT", "Define quantization table", Skip),
	0xFFDC: ("DNL", "Define number of lines", Skip),
	0xFFDD: ("DRI", "Define restart interval", Skip),
	0xFFDE: ("DHP", "Define hierarchical progression", Skip),
	0xFFDF: ("EXP", "Expand reference component", Skip),
	0xFFE0: ("APP0", "Application segment 0", Skip),
	0xFFE1: ("APP1", "Application segment 1", Skip),
	0xFFE2: ("APP2", "Application segment 2", Skip),
	0xFFE3: ("APP3", "Application segment 3", Skip),
	0xFFE4: ("APP4", "Application segment 4", Skip),
	0xFFE5: ("APP5", "Application segment 5", Skip),
	0xFFE6: ("APP6", "Application segment 6", Skip),
	0xFFE7: ("APP7", "Application segment 7", Skip),
	0xFFE8: ("APP8", "Application segment 8", Skip),
	0xFFE9: ("APP9", "Application segment 9", Skip),
	0xFFEA: ("APP10", "Application segment 10", Skip),
	0xFFEB: ("APP11", "Application segment 11", Skip),
	0xFFEC: ("APP12", "Application segment 12", Skip),
	0xFFED: ("APP13", "Application segment 13", Skip),
	0xFFEE: ("APP14", "Application segment 14", Skip),
	0xFFEF: ("APP15", "Application segment 15", Skip),
	0xFFF0: ("JPG0", "Extension 0", None),
	0xFFF1: ("JPG1", "Extension 1", None),
	0xFFF2: ("JPG2", "Extension 2", None),
	0xFFF3: ("JPG3", "Extension 3", None),
	0xFFF4: ("JPG4", "Extension 4", None),
	0xFFF5: ("JPG5", "Extension 5", None),
	0xFFF6: ("JPG6", "Extension 6", None),
	0xFFF7: ("JPG7", "Extension 7", None),
	0xFFF8: ("JPG8", "Extension 8", None),
	0xFFF9: ("JPG9", "Extension 9", None),
	0xFFFA: ("JPG10", "Extension 10", None),
	0xFFFB: ("JPG11", "Extension 11", None),
	0xFFFC: ("JPG12", "Extension 12", None),
	0xFFFD: ("JPG13", "Extension 13", None),
	0xFFFE: ("COM", "Comment", COM)
}

class DummyJpegImageFile:
	"This class is for getting the JPEG comment only."
	def __init__(self, file): # open file
		self.fp = file
		self.COM = ""

	def getCOM(self):
		""" Skip all markers except COM """
		self.fp.seek(0) # who knows...
		s = self.fp.read(1)
		if ord(s[0]) != 255:
			raise AttributeError("not a JPEG file")

		while 1:
			s = s + self.fp.read(1)

			i = i16(s)

			if MARKER.has_key(i):
				name, description, handler = MARKER[i]
				if handler is not None:
					handler(self, i)
				if i == 0xFFDA: # start of scan
					break
				s = self.fp.read(1)
			elif i == 65535:
				# padded marker; move on
				s = "\xff"
			else:
				raise SyntaxError("no marker found")
		return self.COM


if __name__ == "__main__":
                # try to get COM comment
        fname = "AlbumEXIF.py"
        infile=open(fname, 'rb')
        dummy = DummyJpegImageFile(infile) # does not close!!
        comment = dummy.getCOM() # string! Should be part of PIL.Image!
        infile.close()

        print comment

