Beispiel #1
0
    def __init__(self, tag, parent):
        if DEBUG:
            print repr(tag)
        self.parent = parent
        self.endian = parent.endian
        tiff = parent.tiff
        self.id = tag[:2]
        self.type = util.getNr(tag[2:4], self.endian)
        self.count = util.getNr(tag[4:8], self.endian)
        try:
            self.bytes = self.typeMap[self.type]
            self.len = self.bytes * self.count
        except:
            raise ValueError, "Value type %s is not supported for %s - %s" % (self.type, self.niceID(), repr(tag))

        if self.len <= 4:
            self.valueFlat = tag[8:]  #as it needs to be written back into the file
            self.value = self._getVal(tag[8:])
        else:
            offset = util.getNr(tag[8:], self.endian) 
            self.valueFlat = tiff[offset: offset + self.len]
            self.value = self._getVal(tiff[offset: offset + self.len]) 
        
        if DEBUG:
            self.display()
Beispiel #2
0
 def niceID(self):
     "return tag hex value and also a description if available"
     id = exif_tags_description.get(self.endian == "MM" and self.id or util.reverse(self.id), None)
     if id == None: 
         id = hex(util.getNr(self.id, self.endian))
     else:
         id = hex(util.getNr(self.id, self.endian)) + " - " + (type(id) == type(()) and id[0] or id)
     return id
Beispiel #3
0
 def _getVal(self, val):      #from binary to python
     if self.type in [1,3,4]: #byte, sort, long
         if len(val)> self.len:
             val = self.endian == "II" and val[:self.bytes] or val[self.bytes:]
         r = [util.getNr(''.join(t), self.endian) for t in util.unzip(val, self.bytes)]
         if len(r)==1: return r[0]
         return r
     if self.type == 5: #rational
         r = util.unzip([util.getNr(''.join(t), self.endian) for t in util.unzip(val, 4)], 2)
         if len(r)==1: return r[0]
         return r
     if self.type == 2: #string
         return val[:-1]   #strip NULL from NULL terminated string
     return val  # unknown
Beispiel #4
0
def _write(value, file, marker):
    """-Overwrights <marker> segment with given <value>
       -if <marker> segment does not already exist then it will write it 
        right before the image segment (SOF - FFC0)
    """
    markerSeg, sof, length, im = _process(file, marker)
    if markerSeg or sof:
        lenHex = util.setNr(len(value) + 2, "short")  #the length on 2 bytes
        segment = "\xFF" + marker + lenHex + value  #segment = marker + value length + value

        pos = im.tell() - 4
        im.seek(0)
        before = im.read(pos)
        if markerSeg:
            im.seek(util.getNr(length) + 2,
                    1)  #skip over existing segment, including marker
        after = im.read()
        im.reset()
        im.write(before)
        im.write(segment)
        im.write(after)
        im.close()
        return im
    else:
        im.close()
        raise NoImageFound, "There is no image in this image file ?"
Beispiel #5
0
def _write(value, file, marker):
    """-Overwrights <marker> segment with given <value>
       -if <marker> segment does not already exist then it will write it 
        right before the image segment (SOF - FFC0)
    """
    markerSeg, sof, length, im = _process(file, marker)
    if markerSeg or sof:
        lenHex = util.setNr(len(value)+2, "short")  #the length on 2 bytes
        segment = "\xFF" + marker + lenHex + value  #segment = marker + value length + value
        
        pos = im.tell() - 4 
        im.seek(0)
        before = im.read(pos)
        if markerSeg: 
            im.seek(util.getNr(length) + 2, 1)      #skip over existing segment, including marker
        after = im.read()
        im.reset()
        im.write(before)
        im.write(segment)
        im.write(after)
        im.close()
        return im
    else:
        im.close()
        raise NoImageFound, "There is no image in this image file ?"
Beispiel #6
0
 def parse_ifd(self, ifdOffset, context, next=None):
     """ Construct a modifiable Exif.
         
         Get nr of tags and parse each tag. If a pointer tags to other ifd is found, 
         recurse inside that ifd as well
     """
     ifd = self.tiff[ifdOffset:]
     nrTags = util.getNr(ifd[:2], self.endian)
     if DEBUG: 
         print self.ifdName(context), "nr tags", nrTags
     offset = 2  #position after nr tags bytes
     for i in range(nrTags):
         try:
             tag = Tag(ifd[offset : offset+12], self)
         except Exception, e:  #mainly unsuported tag types, etc
             # TODO: if a tag is buggy is it ok to just ignore it and go on or should we crash alltoghether
             if DEBUG: 
                 print "Can't create tag", str(e)
             offset += 12
             continue
         context.append(tag)
         if next is not None:   # and tag.value is not None:
             for ix in range(len(next)):
                 nxtId = next[ix][0]
                 if (tag.id == nxtId) or (self.endian=="II" and tag.id == util.reverse(nxtId)):
                     next[ix][1] = tag.value
         offset += 12
Beispiel #7
0
 def __init__(self, marker, type, value, record):
     self.marker = marker
     self.type = type
     self.value = value
     self.record = record
     self.nrType = util.getNr(type)  #nr_datasets dictionary key
     self.name = nr_datasets.get(self.nrType, None)
Beispiel #8
0
 def __init__(self, marker, type, value, record):
     self.marker = marker
     self.type = type
     self.value = value
     self.record = record
     self.nrType = util.getNr(type)  #nr_datasets dictionary key
     self.name = nr_datasets.get(self.nrType, None)
Beispiel #9
0
 def dict(self):
     "return a dictionary {tag description: (ifd, tag id, value)} of all parsed tags"
     d = {}
     for ifd in self.ifds:
         for tag in ifd:
             id = exif_tags_description.get(self.endian == "MM" and tag.id or util.reverse(tag.id), repr(tag.id))
             id = type(id) == type(()) and id[0] or id
             d[id] = (self.ifdName(ifd), hex(util.getNr(tag.id, self.endian)), tag.value)
     return d
Beispiel #10
0
def _read(file, marker):
    "return value of <marker> segment if exists, or None otherwise"
    segmentValue=None
    try: markerSeg, sof, length, im = _process(file, marker)
    except: return ""
    if markerSeg:
        im.seek(-2, 1)  #retract right after marker ID
        segmentValue = im.read(util.getNr(length))[2:]
    im.close()
    if not markerSeg and not sof:
        raise NoImageFound, "There is no image in this image file ?"
    return segmentValue
Beispiel #11
0
    def parse(self, value):  # 8BIM  Records
        if value:
            marker = value[:4]
            type = value[4:6]
            padding = value[6:10]
            length = util.getNr(value[10:12])
            rValue = value[12:12 + length]
            self.records.append(Record(marker, type, padding, rValue, self))

            #Skip a NULL (\x00 terminated value) if not even size
            if length % 2 != 0: length += 1
            self.parse(value[12 + length:])
Beispiel #12
0
    def parse(self, value):   # 8BIM  Records
        if value:
            marker = value[:4]
            type = value[4:6]
            padding = value[6:10]
            length = util.getNr(value[10:12])
            rValue = value[12:12+length]
            self.records.append(Record(marker, type, padding, rValue, self))

            #Skip a NULL (\x00 terminated value) if not even size
            if length % 2 != 0: length += 1
            self.parse(value[12+length:])  
Beispiel #13
0
def _process(file, target):
    """seek target marker in JPEG file, and return tuple:
    (found marker segment boolean, reached image segment boolean, marker segment length, 
    the open file object positioned at the begining of value)
    """
    comment = image = False
    im = ImgObj(file)
    marker = im.read(2)
    if marker != "\xFF\xD8":
        raise NoJPEGFound, "Not a JPEG image"
    l = 2
    while im.read(1) == "\xFF":
        markerType = im.read(1)
        length = im.read(2)
        l += util.getNr(length) + 2
        if markerType == "\xC0":  #SOF - got to the image, stop
            return (False, True, length, im)
        if markerType == target:
            return (True, False, length, im)
        #skip over current segment
        #-2 to move <length> positions starting right after marker
        im.seek(util.getNr(length) - 2, 1)
    return (False, False, length, im)
Beispiel #14
0
def _process(file, target):
    """seek target marker in JPEG file, and return tuple:
    (found marker segment boolean, reached image segment boolean, marker segment length, 
    the open file object positioned at the begining of value)
    """
    comment = image = False
    im = ImgObj(file)
    marker = im.read(2)
    if marker != "\xFF\xD8":
        raise NoJPEGFound, "Not a JPEG image"
    l=2
    while im.read(1) == "\xFF":
        markerType = im.read(1)
        length = im.read(2)
        l += util.getNr(length) + 2
        if markerType == "\xC0": #SOF - got to the image, stop
            return (False, True, length, im) 
        if markerType == target: 
            return (True, False, length, im) 
        #skip over current segment 
        #-2 to move <length> positions starting right after marker
        im.seek(util.getNr(length) - 2, 1)  
    return (False, False, length, im) 
Beispiel #15
0
def _read(file, marker):
    "return value of <marker> segment if exists, or None otherwise"
    segmentValue = None
    try:
        markerSeg, sof, length, im = _process(file, marker)
    except:
        return ""
    if markerSeg:
        im.seek(-2, 1)  #retract right after marker ID
        segmentValue = im.read(util.getNr(length))[2:]
    im.close()
    if not markerSeg and not sof:
        raise NoImageFound, "There is no image in this image file ?"
    return segmentValue
Beispiel #16
0
    def parse(self, value):  # sub-segments for 8BIM segment
        if value:
            marker = value[:2]
            type = value[2:3]
            length = util.getNr(value[3:5])
            rValue = value[5:5 + length]
            self.datasets.append(DataSet(marker, type, rValue, self))

            # Skip a NULL (\x00 terminated value) if not even size
            try:
                if length % 2 != 0 and value[5 + length + 1] == '\x00':
                    length += 1
            except IndexError, e:
                pass
            self.parse(value[5 + length:])
Beispiel #17
0
    def parse(self, value):  # sub-segments for 8BIM segment
        if value:
            marker = value[:2]
            type = value[2:3]
            length = util.getNr(value[3:5])
            rValue = value[5:5+length]
            self.datasets.append(DataSet(marker, type, rValue, self))

            # Skip a NULL (\x00 terminated value) if not even size
            try:
                if length % 2 != 0 and value[5+length+1]=='\x00':
                    length += 1
            except IndexError, e:
                pass
            self.parse(value[5+length:])
Beispiel #18
0
 def __init__(self, value=None):
     if value is None:
         raise "EXIF must not be empty"
     self.origValue = value
     self.tiff = value[6:]
     self.endian = value[6:8]  
     self.fixed42 = "\x00\x2A"    #42 value[8:10]
     
     #IFD's data structure
     self.ifd0 = []
     self.exif = []
     self.gps = []
     self.interop = []
     self.ifd1 = None    #we are not messing with ifd1 (thumbnail etc.) in this app at all
     self.ifds = [self.ifd0, self.exif, self.gps, self.interop]
     if DEBUG: 
         print "endian", self.endian
     #parse IFD's into above data structure:
     self.parse_ifd(util.getNr(value[10:14], self.endian), 
                     self.ifd0, 
                     [["\x87\x69", None, self.exif,                # EXIFOffset
                       [["\xA0\x05", None, self.interop, None]]],  # Interopelability IFD offset
                     ["\x88\x25", None, self.gps, None]])          # GPSOffset