2012-04-27 119 views
10

我想從jpegs中提取縮略圖圖像,無需任何外部庫。我的意思是這並不難,因爲我需要知道縮略圖的起始位置,並在文件中結束,並簡單地剪切它。我研究了許多文檔(例如:http://www.media.mit.edu/pia/Research/deepview/exif.html),並嘗試分析jpegs,但並非一切都清楚。我試圖跟蹤字節的一步一步,但在深深的我困惑。是否有任何良好的文檔或可讀的源代碼來提取有關jpeg文件中縮略圖開始和結束位置的信息?從jpeg文件中提取縮略圖

謝謝!

+1

至少有3個地方,其可以存儲縮略圖JPEG圖像:JFIF/APP0 ,EXIF APP1和ADEOBE APP13。這裏http://javagraphics.blogspot.ca/2010/03/images-reading-jpeg-thumbnails.html是一個關於它的博客,你也可以找到這個https://github.com/dragon66/icafe/wiki有用。 – dragon66 2014-10-06 21:04:37

回答

11

對於由電話或數碼相機創建的大多數JPEG圖像,縮略圖圖像(如果存在)存儲在APP1標記(FFE1)中。該標記段內有一個TIFF文件,其中包含主圖像的EXIF信息以及作爲JPEG壓縮圖像存儲的可選縮略圖圖像。 TIFF文件通常包含兩個「頁面」,其中第一頁是EXIF信息,第二頁是以「舊」TIFF類型6格式存儲的縮略圖。類型6格式是當JPEG文件原樣存儲在TIFF包裝器中時。如果您希望最簡單的代碼將縮略圖提取爲JFIF,則需要執行以下步驟:

  1. 熟悉JFIF和TIFF標記/標記。 JFIF標記由兩個字節組成:0xFF後跟標記類型(APP1的0xE1)。這兩個字節之後是以big-endian順序存儲的兩字節長度。對於TIFF文件,請參閱Adobe TIFF 6.0參考。
  2. 在您的JPEG文件中搜索APP1(FFE1)EXIF標記。可能有多個APP1標記,APP1之前可能有多個標記。
  3. 您正在查找的APP1標記包含緊跟在長度字段後面的字母「EXIF」。
  4. 查找「II」或「MM」(距離長度6個字節)以指示TIFF文件中使用的字節順序。 II = Intel =小端,MM =摩托羅拉=大端。
  5. 跳過第一頁的標籤,找到存儲圖像的第二個IFD。在第二個「頁面」中,查找指向JPEG數據的兩個TIFF標籤。標記0x201具有JPEG數據的偏移量(相對於II/MM),標記0x202具有以字節爲單位的長度。
+2

可能還會指出Exif數據中可能存在多個降低分辨率的圖像。例如在Nikon JPEG文件中,有一個縮略圖和第二個(較大的)預覽圖像。唯一的限制是總Exif數據不能超過64,000字節。還有一點 - 如你所說,Exif數據可以是小尾數或大尾數。但是,JPEG標記和數據以及縮略圖數據總是大端的。諸如0xFFE1(APP1標記)的標記由JPEG標準ISO DIS 10918-1定義並可在線獲得。 – 2012-04-30 19:09:10

+1

謝謝你,我幫你成功地寫了代碼! – 2012-05-08 14:05:02

+0

謝謝你,這是非常明確的 – 2016-11-10 11:11:36

-1

JFIF上的維基百科頁面http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format給出了JPEG Header的一個很好的描述(標題包含縮略圖作爲未壓縮的光柵圖像)。這應該給你一個佈局的想法,因此需要提取信息的代碼。

進制打印圖像頭(小端顯示器):

[email protected]:~$ head -c 48 stfu.jpg |hexdump 
0000000 d8ff e0ff 1000 464a 4649 0100 0101 4800 
0000010 4800 0000 e1ff 1600 7845 6669 0000 4d4d 
0000020 2a00 0000 0800 0000 0000 0000 feff 1700 

圖片魔(字節1,0),APP0段頭的幻(字節3,2),報頭長度(5,4)報頭類型簽名(「JFIF \ 0」||「JFXX \ 0」)(字節6-10),版本(字節11,12)密度單位(字節13),X密度(字節15,14),Y密度(字節17,16),縮略圖寬度(字節19),縮略圖高度(字節18)以及最後休息到「標題長度」是縮略圖數據。

從以上示例中,可以看到標題長度爲16個字節(字節6,5),版本爲01.01(字節12,13)。此外,由於縮略圖寬度和縮略圖高度都是0x00,圖像不包含縮略圖。

+0

您對JFIF標頭的分析不正確。 JPEG文件通常包含JPEG壓縮的縮略圖圖像。縮略圖的寬度和高度作爲TIFF文件的一部分存儲在APP1標記中。您可以在偏移量爲0x1E的轉儲中看到TIFF頭「II」的開頭,後面跟着版本0x2a和IFD偏移0x0008。 – BitBank 2012-04-27 18:00:15

+0

我的分析是基於http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format上的信息以及jpeg標準http://www.ecma-international.org/publications/files/ECMA-TR/TR -098.pdf第10節(第5頁)。請詳細說明您的信息來源。您可能在談論JFIF擴展(JFXX)段格式,而上面的示例是JFIF段格式(字節偏移量0x06-0x10是「JFIF \ 0」) – Samveen 2012-04-27 19:58:21

+1

縮略圖信息可能在規範中,但這是而不是如何在現實世界中使用它。我從來沒有見過帶有APP0頭縮略圖的JPEG圖像。它作爲TIFF文件的一部分存儲(通常壓縮)在EXIF(APP1)頭中,其中包含其他EXIF信息作爲TIFF標籤。發佈您在上面引用的文件,然後我會告訴你它裏面有什麼。 – BitBank 2012-04-27 20:29:29

4

這個問題有一個更簡單的解決方案,但我不知道它有多可靠:從第三個字節開始讀取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 
    } 
} 
+0

很好的簡單代碼的概念證明,但這大約有1/20照片我有,因爲我不認爲你可以保證0xFFD8不會出現在其他地方。 – 2016-03-16 08:57:18

11

Exiftool是非常有能力快速,輕鬆地這樣做的:

exiftool -b -ThumbnailImage my_image.jpg > my_thumbnail.jpg 
+4

您應該使用'exiftool -a -b -W%d%f_%t%-c。%s -preview:all YourFileOrDirectory'來提取每個縮略圖變體。 – tricasse 2017-05-18 12:14:24

+2

ExifTool中可用的縮略圖類型可以通過'exiftool -list -preview:all'列出。 – tricasse 2017-05-18 13:31:08