Search code examples
pythonimagejpegexifjfif

Updating JFIF thumbnail in JPEG file


I am trying to update the embedded JFIF thumbnail in a JPEG File using Python.

This is the (slightly hackish) method that is supposed to achieve this:

def set_thumbnail(self, data):
    # Data of the updated thumbnail
    data = bytearray(data)
    # Get offset of the old thumbnail data
    offset = (self._exif_start +
              self._unpack('I', self._get_tag_offset(0x201)+8))
    # Get size of the old thumbnail
    old_size = self._unpack('I', self._get_tag_offset(0x202)+8)
    try:
        # Strip everything between the JFIF APP1 and the quant table
        jfif_start = data.index('\xff\xe0')
        quant_start = data.index('\xff\xdb')
        stripped_data = data[0:jfif_start] + data[quant_start:]
    except ValueError:
        stripped_data = data
    # Writes the new length to the buffer
    self._pack('I', self._get_tag_offset(0x202)+8, len(stripped_data))
    # Writes the new data to the image buffer
    self._buf[offset:offset+old_size] = stripped_data

This function works fine when I re-write the old thumbnail, i.e. the size of the thumbnail data does not change. However, once I apply some transformation (e.g. crop or rotate) to it and store it again, the resulting file seems to be no longer valid.

I uploaded both an original image and one with an updated thumbnail for better comparison.

The error I get from e.g. identify is the following:

identify.im6: Invalid JPEG file structure: two SOI markers `/tmp/thumb_rotated.jpg' @ error/jpeg.c/JPEGErrorHandler/316.

On diffing the two images, the value in the 0x202 size tag matches the size of the embedded thumbnail data, and the file is also accordingly larger.


Solution

  • I just found the answer:

    The problem was that while I updated the size of the thumbnail in the TIFF tag, I did not update the APP1 length. Once that was updated as well, the image loaded correctly.