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
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
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
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
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
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
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()
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()
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
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
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
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()
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()