web-dev-qa-db-ja.com

jpegファイルからサムネイルを抽出

外部ライブラリなしで、jpegsからサムネイル画像を抽出したいと思います。私はサムネイルがファイルのどこで始まりどこで終わるかを知り、単にそれをカットする必要があるので、これはそれほど難しくないことを意味します。私は多くのドキュメント(つまり: http://www.media.mit.edu/pia/Research/deepview/exif.html )を研究し、jpegの分析を試みますが、すべてが明確ではありません。私はバイトを段階的に追跡しようとしましたが、深いところで混乱しました。 jpegファイル内のサムネイルの開始位置と終了位置に関する情報を抽出するための優れたドキュメントや読みやすいソースコードはありますか?

ありがとうございました!

17
Lay András

電話またはデジタルカメラで作成されたほとんどのJPEG画像の場合、サムネイル画像(存在する場合)はAPP1マーカー(FFE1)に保存されます。このマーカーセグメントの内部には、メイン画像のEXIF情報と、JPEG圧縮画像として保存されたオプションのサムネイル画像を含むTIFFファイルがあります。 TIFFファイルには通常2つの「ページ」が含まれており、最初のページはEXIF情報で、2番目のページは「古い」TIFFタイプ6形式で保存されたサムネイルです。タイプ6形式は、JPEGファイルがそのままTIFFラッパー内に格納される場合です。最も簡単なコードでサムネイルをJFIFとして抽出する場合は、次の手順を実行する必要があります。

  1. JFIFおよびTIFFマーカー/タグをよく理解してください。 JFIFマーカーは2バイトで構成されます。0xFFの後にマーカータイプが続きます(APP1の場合は0xE1)。これらの2バイトの後に、ビッグエンディアン順に格納された2バイトの長さが続きます。 TIFFファイルについては、Adobe TIFF 6.0リファレンスを参照してください。
  2. JPEGファイルでAPP1(FFE1)EXIFマーカーを検索します。 APP1マーカーが複数ある場合とAPP1の前に複数のマーカーがある場合があります。
  3. お探しのAPP1マーカーには、長さフィールドの直後に「EXIF」という文字が含まれています。
  4. "II"または "MM"(長さから6バイト離れている)を探して、TIFFファイルで使用されているエンディアンを示します。 II = Intel =リトルエンディアン、MM = Motorola =ビッグエンディアン。
  5. 最初のページのタグをスキップして、画像が保存されている2番目のIFDを見つけます。 2番目の「ページ」で、JPEGデータを指す2つのTIFFタグを探します。タグ0x201にはJPEGデータのオフセット(II/MMを基準)があり、タグ0x202にはバイト単位の長さがあります。
16
BitBank

Exiftool は、これをすばやく簡単に実行できます。

exiftool -b -ThumbnailImage my_image.jpg > my_thumbnail.jpg
18
Riot

この問題のはるかに簡単な解決策がありますが、それがどれほど信頼できるかわかりません:3番目のバイトからJPEGファイルの読み取りを開始し、FFD8(JPEG画像マーカーの開始)を検索してから、FFD9(JPEG画像の終了)を検索しますマーカー)。それを抽出して出来上がり、それがあなたのサムネイルです。

簡単なJavaScript実装:

function getThumbnail(file, callback) {
    if (file.type == "image/jpeg") {
        var reader = new FileReader();
        reader.onload = function (e) {
            var array = new Uint8Array(e.target.result),
                start, end;
            for (var i = 2; i < array.length; i++) {
                if (array[i] == 0xFF) {
                    if (!start) {
                        if (array[i + 1] == 0xD8) {
                            start = i;
                        }
                    } else {
                        if (array[i + 1] == 0xD9) {
                            end = i;
                            break;
                        }
                    }
                }
            }
            if (start && end) {
                callback(new Blob([array.subarray(start, end)], {type:"image/jpeg"}));
            } else {
                // TODO scale with canvas
            }
        }
        reader.readAsArrayBuffer(file.slice(0, 50000));
    } else if (file.type.indexOf("image/") === 0) {
        // TODO scale with canvas
    }
}
4
Joel Richard