1

Python を使用して、JPEG ファイルに埋め込まれた JFIF サムネイルを更新しようとしています。

これは、これを達成することになっている(少しハックな)方法です。

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

この関数は、古いサムネイルを書き直しても問題なく動作します。つまり、サムネイル データのサイズは変わりません。ただし、何らかの変換 (切り抜きや回転など) を適用して再度保存すると、結果のファイルは有効ではなくなったようです。

元の画像と、比較しやすいようにサムネイルを更新した画像の両方をアップロードしました。

identifyたとえば、次のようなエラーが表示されます。

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

2 つの画像を比較すると、0x202size タグの値は埋め込まれたサムネイル データのサイズと一致し、それに応じてファイルも大きくなります。

4

2 に答える 2

1

これが画像ファイルの構造です。APP1 マーカーの直後に 2 つ目の SOI マーカーがあることに注意してください。

{ 画像の開始 }

{ APP0 マーカーの長さ: 16 バージョン: 1.1 密度の単位: (ピクセル/インチ) X 密度: 72 Y 密度: 72 サムネイルの幅: 0 サムネイルの高さ: 0 }

{ APP1 マーカーの長さ: 7678 Exif }

{ 画像の開始 }

{ 量子化テーブルの長さを定義: 67 テーブル インデックス: 0 テーブル精度: 0 テーブル値: 8 6 6 7 6 5 8 7 7 9 9 8 10 12 20 13 12 11 11 12 25 18 19 15 20 29 26 31 30 29 26 28 28 32 36 46 39 32 34 44 35 28 28 40 55 41 44 48 49 52 52 52 31 39 57 61 56 50 60 46 51 52 50 }

{ 量子化テーブルの長さを定義: 67 テーブル インデックス: 1 テーブル精度: 0 テーブル値: 9 9 9 12 11 12 24 13 13 24 50 33 28 33 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 }

{ フレーム タイプの開始: ベースライン (ハフマン) 長さ: 17 精度: 8 高さ: 360 幅: 480 コンポーネント数: 3 コンポーネント 1 水平周波数: 2 垂直周波数: 2 量子化テーブル: 0 コンポーネント 2 水平周波数: 1 垂直周波数: 1量子化テーブル: 1 コンポーネント 3 水平周波数: 1 垂直周波数: 1 量子化テーブル: 1 }

{ ハフマン テーブルの長さを定義: 28 テーブル インデックス 0 テーブル クラス: DC コード カウント: 0 1 5 1 1 1 0 0 0 0 0 0 0 0 コード値: 3 1 2 4 5 6 0 7 8 }

{ ハフマン テーブルの長さを定義: 65 テーブル インデックス 0 テーブル クラス: AC コード カウント: 0 2 1 3 2 4 4 4 4 4 5 3 3 4 3 0 コード値: 1 2 3 0 4 11 12 21 5 31 41 51 13 22 61 71 6 32 81 91 14 42 a1 b1 23 52 c1 d1 7 15 33 62 e1 43 72 f0 24 92 f1 16 34 53 82 25 83 c2 }

{ ハフマン テーブルの長さを定義: 26 テーブル インデックス 1 テーブル クラス: DC コード カウント: 0 3 1 1 1 1 0 0 0 0 0 0 0 0 コード値: 0 1 2 3 4 5 6 }

{ ハフマン テーブルの長さを定義: 45 テーブル インデックス 1 テーブル クラス: AC コード カウント: 0 2 2 1 4 1 4 2 2 2 1 5 0 0 0 0 コード値: 0 1 2 11 3 4 12 21 31 41 13 22 51 61 32 71 5 14 23 91 f0 33 42 81 a1 b1 }

{ スキャン長の開始: 12 コンポーネント ID: 1 AC エントロピー テーブル: 0 DC エントロピー テーブル: 0 コンポーネント ID: 2 AC エントロピー テーブル: 1 DC エントロピー テーブル: 1 コンポーネント ID: 3 AC エントロピー テーブル: 1 DC エントロピー テーブル: 1 スペクトル選択の開始: 0 スペクトル選択の終了: 63 逐次近似の上限: 0 逐次近似の下限: 0 }

{画像の終わり}

于 2014-05-08T15:55:45.630 に答える
1

私はちょうど答えを見つけました:

問題は、TIFF タグのサムネイルのサイズを更新したときに、APP1 の長さを更新しなかったことです。それも更新されると、画像は正しく読み込まれました。

于 2014-05-08T16:05:15.627 に答える