Exemplo n.º 1
0
    def getBlob(self):
        """ Return a binary string representing the IPTC record. """

        data_str = ""

        # Iterate over all the tag numbers
        for tag_num in self.getTagNums():
            # Iterate over all the tags set with this number
            for tag in self.fields[tag_num]:
                # Each tag starts with 0x1C, the record number, and the tag number
                data_str += "\x1C" + chr(self.RECORD_NUM) + chr(tag_num)

                # If the number of data bytes exceeds 32767, we should encode an extended tag
                data_length = tag.getDataLength()
                if (data_length > 32767):
                    # Extended tags are indicated with a 1 for the most significant bit
                    data_length = data_length & 32768  # 10000000 00000000
                    # An extended tag uses two bytes to specify the number of bytes to
                    # encode the length of the data. If we cannot encode the length in
                    # two bytes, we only know how to encode it in four bytes. In
                    # practive this will always do.
                    data_str += byteform.itob(4, 2, big_endian=self.big_endian)

                # Append the data length in bytes, and the actual binary data
                data_str += byteform.itob(data_length,
                                          2,
                                          big_endian=self.big_endian)
                data_str += tag.getData()

        return data_str
Exemplo n.º 2
0
  def getDataBlock(self):
    """ Return the Photoshop structure as a binary data block. """

    # Store the buffer as string    
    out_str = ""
    
    # Iterate over all tags
    for tag_num in self.tags:
      tag = self.tags[tag_num]
      
      # Every data structure starts with "8BIM"
      out_str += "8BIM"
      
      # The next two bytes specify the resource ID (tag number)
      out_str += byteform.itob(tag_num, 2, big_endian = self.big_endian)
        
      # Then we get the Pascal string, which we simply set to nothing
      out_str += "\x00\x00"
           
      # Encode the length of the data
      out_str += byteform.itob(tag.getDataLength(), 4, big_endian = self.big_endian)
       
      # And append the data itself
      out_str += tag.getData()
      
    return out_str
Exemplo n.º 3
0
    def getDataBlock(self):
        """ Return the Photoshop structure as a binary data block. """

        # Store the buffer as string
        out_str = ""

        # Iterate over all tags
        for tag_num in self.tags:
            tag = self.tags[tag_num]

            # Every data structure starts with "8BIM"
            out_str += "8BIM"

            # The next two bytes specify the resource ID (tag number)
            out_str += byteform.itob(tag_num, 2, big_endian=self.big_endian)

            # Then we get the Pascal string, which we simply set to nothing
            out_str += "\x00\x00"

            # Encode the length of the data
            out_str += byteform.itob(tag.getDataLength(),
                                     4,
                                     big_endian=self.big_endian)

            # And append the data itself
            out_str += tag.getData()

        return out_str
Exemplo n.º 4
0
 def getBlob(self):
   """ Return a binary string representing the IPTC record. """
   
   data_str = ""
   
   # Iterate over all the tag numbers
   for tag_num in self.getTagNums():
     # Iterate over all the tags set with this number
     for tag in self.fields[tag_num]:
       # Each tag starts with 0x1C, the record number, and the tag number
       data_str += "\x1C" + chr(self.RECORD_NUM) + chr(tag_num)
       
       # If the number of data bytes exceeds 32767, we should encode an extended tag
       data_length = tag.getDataLength()
       if (data_length > 32767):
         # Extended tags are indicated with a 1 for the most significant bit
         data_length = data_length & 32768 # 10000000 00000000
         # An extended tag uses two bytes to specify the number of bytes to
         # encode the length of the data. If we cannot encode the length in
         # two bytes, we only know how to encode it in four bytes. In
         # practive this will always do.
         data_str += byteform.itob(4, 2, big_endian = self.big_endian)
         
       # Append the data length in bytes, and the actual binary data
       data_str += byteform.itob(data_length, 2, big_endian = self.big_endian)
       data_str += tag.getData()
       
   return data_str
Exemplo n.º 5
0
 def getBlob(self):
   """ Return the complete segment, including headers. """
   
   byte_str = "\xff" + chr(self.number)
   byte_str += byteform.itob(self.getDataLength() + 2, 2, big_endian = self.big_endian)
   content = self.getData()
   byte_str += content
     
   return byte_str
Exemplo n.º 6
0
    def getBlob(self):
        """ Return the complete segment, including headers. """

        byte_str = "\xff" + chr(self.number)
        byte_str += byteform.itob(self.getDataLength() + 2,
                                  2,
                                  big_endian=self.big_endian)
        content = self.getData()
        byte_str += content

        return byte_str
Exemplo n.º 7
0
  def writeFile(self, file_path):
    # Write the header
    out_fp = convenience.PersistentFileHandle(file_path, "wb")
    if (self.big_endian):
      out_fp.write("\x4d\x4d")
    else:
      out_fp.write("\x49\x49")
    out_fp.write(byteform.itob(42, 2, big_endian = self.big_endian))
    out_fp.write(byteform.itob(8, 4, big_endian = self.big_endian))
    
    # Embed the IPTC data in the Exif structure
    if (self.iptc):
      self.exif.setTag(33723, self.iptc.getBlob(), record = 1)
      
    # Save the old strip offsets before we overwrite it
    old_strip_offsets = self.__getExif__().getTag("StripOffsets", 1)

    # Restructure the Exif metadata to contain the new strip offsets
    curr_offset = self.exif.getSize() + 8 # 8 bytes for the Tiff header
    tiff = self.exif.getRecord(1)
    strip_lengths = self.exif.getTag("StripByteCounts", 1)
    new_strip_offsets = []
    for length in strip_lengths:
      new_strip_offsets.append(curr_offset)
      curr_offset += length
    self.exif.setTag("StripOffsets", new_strip_offsets, 1)

    # Write the Exif data
    out_fp.write(self.exif.getBlob(8))
    
    # Write the image data
    for strip_num in range(len(strip_lengths)):
      offset = old_strip_offsets[strip_num]
      length = strip_lengths[strip_num]
      self.fp.seek(offset)
      out_fp.write(self.fp.read(length))
      
    out_fp.close()
Exemplo n.º 8
0
    def writeFile(self, file_path):
        # Write the header
        out_fp = convenience.PersistentFileHandle(file_path, "wb")
        if (self.big_endian):
            out_fp.write("\x4d\x4d")
        else:
            out_fp.write("\x49\x49")
        out_fp.write(byteform.itob(42, 2, big_endian=self.big_endian))
        out_fp.write(byteform.itob(8, 4, big_endian=self.big_endian))

        # Embed the IPTC data in the Exif structure
        if (self.iptc):
            self.exif.setTag(33723, self.iptc.getBlob(), record=1)

        # Save the old strip offsets before we overwrite it
        old_strip_offsets = self.__getExif__().getTag("StripOffsets", 1)

        # Restructure the Exif metadata to contain the new strip offsets
        curr_offset = self.exif.getSize() + 8  # 8 bytes for the Tiff header
        tiff = self.exif.getRecord(1)
        strip_lengths = self.exif.getTag("StripByteCounts", 1)
        new_strip_offsets = []
        for length in strip_lengths:
            new_strip_offsets.append(curr_offset)
            curr_offset += length
        self.exif.setTag("StripOffsets", new_strip_offsets, 1)

        # Write the Exif data
        out_fp.write(self.exif.getBlob(8))

        # Write the image data
        for strip_num in range(len(strip_lengths)):
            offset = old_strip_offsets[strip_num]
            length = strip_lengths[strip_num]
            self.fp.seek(offset)
            out_fp.write(self.fp.read(length))

        out_fp.close()
Exemplo n.º 9
0
  def getBlob(self, offset, next_ifd = 0):
    """Returns the entry stream and the data stream for writing the IFD. offset
    is the offset to byte addresses specified in tghe IFD (usually the size of
    the TIFF header). next_ifd is the byte position for the next IFD, if any.
    If next_ifd is set to None, it will be omitted
    """
    
    if not (self.hasTags()):
      # If we don't have any tags, simply return nothing
      return None
    else:
      tag_nums = self.getTagNums()
  
      # For writing the data, we split the stream in two; one part contains the
      # 12-byte fields specifying tags, data type, etc. and the other one contains
      # the encoded data (which is over 4 bytes in size). At the end, these two
      # fields will be concatenated
      fields_stream = byteform.itob(len(tag_nums), 2, big_endian = self.big_endian)
      data_stream = ""
      
      # Calculate the offset at which we may write data (after the offset, 2
      # bytes at the start of the IFD and 12 bytes for each field
      data_offset = offset + 12 * len(tag_nums) + 2

      # If we have a pointer to the next IFD, write it to the data stream
      if (next_ifd != None):
        data_stream = byteform.itob(next_ifd, 4, big_endian = self.big_endian)
        data_offset += 4

      # Write each tag
      for tag_num in tag_nums:
        tag       = self.fields[tag_num]
        data_type = tag.getDataType()
        data      = tag.getData()
        count     = len(data) / DATA_TYPES[data_type].word_width
        
        # Write the tag number, data type and data count
        fields_stream += byteform.itob(tag_num, 2, big_endian = self.big_endian)
        fields_stream += byteform.itob(data_type, 2, big_endian = self.big_endian)
        fields_stream += byteform.itob(count, 4, big_endian = self.big_endian)
        
        # If we can fit the data into four bytes, do so, otherwise write it in
        # the data field and store the offset
        if (len(data) <= 4):
          fields_stream += data
          fields_stream += (4 - len(data)) * "\x00"
        else:
          fields_stream += byteform.itob(data_offset, 4, big_endian = self.big_endian)
          data_stream   += data
          data_offset   += len(data)
          
      return fields_stream + data_stream
Exemplo n.º 10
0
 def getBlob(self, offset, next_ifd = 0):
   ret_str = "FUJIFILM"
   ret_str += byteform.itob(12, 4, big_endian = self.big_endian)
   ret_str += ifd.IFD.getBlob(self, 12, next_ifd)
   return ret_str
Exemplo n.º 11
0
 def getBlob(self, offset, next_ifd=0):
     ret_str = "FUJIFILM"
     ret_str += byteform.itob(12, 4, big_endian=self.big_endian)
     ret_str += ifd.IFD.getBlob(self, 12, next_ifd)
     return ret_str
Exemplo n.º 12
0
 def writeFile(self, file_path):
   # Open the new file for writing
   out_fp = convenience.PersistentFileHandle(file_path, "wb")
   out_fp.write("\xff\xd8")
   
   # Prepare the Exif segment for writing
   # Write the Exif header
   byte_str = "Exif\x00\x00"
   
   # Construct the Tiff header
   ifd_big_endian = self.__getExif__().big_endian
   if (ifd_big_endian):
     byte_str += "\x4d\x4d"
   else:
     byte_str += "\x49\x49"
   byte_str += byteform.itob(42, 2, big_endian = ifd_big_endian)
   byte_str += byteform.itob(8, 4, big_endian = ifd_big_endian)
   
   # Write the Exif data
   byte_str += self.__getExif__().getBlob(8)
   
   # Put the Exif data into an appropriate APP1 segment. FIXME: This
   # invalidates that segment for future data extraction.
   exif = self.__getExif__()
   if (exif.hasTags()):
     if (not self.exif_segment):
       self.exif_segment = Segment(num = SEG_NUMS["APP1"], data = byte_str)
       self.segments[SEG_NUMS["APP1"]].append(self.exif_segment)
     else:
       self.exif_segment.setData(byte_str, 0)
   else:
     if (self.exif_segment):
       del self.segments[SEG_NUMS["APP1"]][self.segments[SEG_NUMS[APP1]].index(self.exif_segment)]
       self.exif_segment = None
   
   # Prepare the IPTC segment for writing. FIXME: This
   # invalidates that segment for future data extraction.
   iptc = self.__getIPTC__()
   if (iptc.hasTags()):
     if (not self.iptc_segment):
       self.iptc_segment = Segment(num = SEG_NUMS["APP13"])
       self.segments[SEG_NUMS["APP13"]].append(self.iptc_segment)
     if (not self.ps_info):
       self.ps_info = photoshop.Photoshop()
     self.ps_info.setTag(1028, self.__getIPTC__().getBlob())
     self.iptc_segment.setData("Photoshop 3.0\x00" + self.ps_info.getDataBlock(), 0)
   # If we don't have any tags, remove the IPTC segment and Photoshop info
   else:
     if (self.iptc_segment):
       del self.segments[SEG_NUMS["APP13"]][self.segments[SEG_NUMS["APP13"]].index(self.iptc_segment)]
       self.iptc_segment = None
     if (self.ps_info):
       self.ps_info = None
   
   # Iterate over all segments and copy them from the original file or rewrite
   # them.
   for seg_type in SEGMENTS:
     seg_num = SEG_NUMS[seg_type]
     for segment in self.segments[seg_num]:
       # Write the segment
       out_fp.write(segment.getBlob())
       
   # Write the image data
   if (self.image_data_offset): # We only do the check here and not in the parsing, so we can still extract metadata from a broken image file
     self.fp.seek(self.image_data_offset)
     out_fp.write(self.fp.read())
   else:
     raise "Due to an error in the parsing of the file, it can not be written."
   
   out_fp.close()
Exemplo n.º 13
0
    def writeFile(self, file_path):
        # Open the new file for writing
        out_fp = convenience.PersistentFileHandle(file_path, "wb")
        out_fp.write("\xff\xd8")

        # Prepare the Exif segment for writing
        # Write the Exif header
        byte_str = "Exif\x00\x00"

        # Construct the Tiff header
        ifd_big_endian = self.__getExif__().big_endian
        if (ifd_big_endian):
            byte_str += "\x4d\x4d"
        else:
            byte_str += "\x49\x49"
        byte_str += byteform.itob(42, 2, big_endian=ifd_big_endian)
        byte_str += byteform.itob(8, 4, big_endian=ifd_big_endian)

        # Write the Exif data
        byte_str += self.__getExif__().getBlob(8)

        # Put the Exif data into an appropriate APP1 segment. FIXME: This
        # invalidates that segment for future data extraction.
        exif = self.__getExif__()
        if (exif.hasTags()):
            if (not self.exif_segment):
                self.exif_segment = Segment(num=SEG_NUMS["APP1"],
                                            data=byte_str)
                self.segments[SEG_NUMS["APP1"]].append(self.exif_segment)
            else:
                self.exif_segment.setData(byte_str, 0)
        else:
            if (self.exif_segment):
                del self.segments[SEG_NUMS["APP1"]][self.segments[
                    SEG_NUMS[APP1]].index(self.exif_segment)]
                self.exif_segment = None

        # Prepare the IPTC segment for writing. FIXME: This
        # invalidates that segment for future data extraction.
        iptc = self.__getIPTC__()
        if (iptc.hasTags()):
            if (not self.iptc_segment):
                self.iptc_segment = Segment(num=SEG_NUMS["APP13"])
                self.segments[SEG_NUMS["APP13"]].append(self.iptc_segment)
            if (not self.ps_info):
                self.ps_info = photoshop.Photoshop()
            self.ps_info.setTag(1028, self.__getIPTC__().getBlob())
            self.iptc_segment.setData(
                "Photoshop 3.0\x00" + self.ps_info.getDataBlock(), 0)
        # If we don't have any tags, remove the IPTC segment and Photoshop info
        else:
            if (self.iptc_segment):
                del self.segments[SEG_NUMS["APP13"]][self.segments[
                    SEG_NUMS["APP13"]].index(self.iptc_segment)]
                self.iptc_segment = None
            if (self.ps_info):
                self.ps_info = None

        # Iterate over all segments and copy them from the original file or rewrite
        # them.
        for seg_type in SEGMENTS:
            seg_num = SEG_NUMS[seg_type]
            for segment in self.segments[seg_num]:
                # Write the segment
                out_fp.write(segment.getBlob())

        # Write the image data
        if (
                self.image_data_offset
        ):  # We only do the check here and not in the parsing, so we can still extract metadata from a broken image file
            self.fp.seek(self.image_data_offset)
            out_fp.write(self.fp.read())
        else:
            raise "Due to an error in the parsing of the file, it can not be written."

        out_fp.close()