2012-04-27 72 views
10

Tôi muốn trích xuất hình thu nhỏ từ jpeg, mà không có bất kỳ thư viện bên ngoài nào. Ý tôi là điều này không quá khó, vì tôi cần phải biết hình thu nhỏ bắt đầu từ đâu, và kết thúc trong tập tin, và đơn giản là cắt nó. Tôi nghiên cứu nhiều tài liệu (ví dụ: http://www.media.mit.edu/pia/Research/deepview/exif.html), và cố gắng phân tích jpegs, nhưng không phải mọi thứ rõ ràng. Tôi đã cố gắng theo dõi từng bước các byte, nhưng trong sâu tôi bối rối. Có tài liệu hay hay mã nguồn có thể đọc được nào để trích xuất thông tin về vị trí bắt đầu và kết thúc của hình thu nhỏ trong tệp jpeg?Trích xuất hình thu nhỏ từ tệp jpeg

Cảm ơn bạn!

+1

Có ít nhất 3 địa điểm mà có thể lưu trữ hình thu nhỏ cho hình ảnh JPEG: JFIF/APP0 , EXIF ​​APP1 và ADEOBE APP13. Ở đây http://javagraphics.blogspot.ca/2010/03/images-reading-jpeg-thumbnails.html là một blog về nó và bạn cũng có thể tìm thấy https://github.com/dragon66/icafe/wiki hữu ích này. – dragon66

Trả lời

11

Đối với hầu hết các hình ảnh JPEG được tạo bởi điện thoại hoặc máy ảnh kỹ thuật số, hình thu nhỏ (nếu có) được lưu trữ trong nhãn hiệu APP1 (FFE1). Bên trong đoạn nhãn này là tệp TIFF chứa thông tin EXIF ​​cho hình ảnh chính và hình ảnh thu nhỏ tùy chọn được lưu trữ dưới dạng hình ảnh nén JPEG. Tệp TIFF thường chứa hai "trang" trong đó trang đầu tiên là thông tin EXIF ​​và trang thứ hai là hình thu nhỏ được lưu trữ ở định dạng "cũ" TIFF loại 6. Định dạng loại 6 là khi một tệp JPEG được lưu trữ như bên trong của trình bao bọc TIFF. Nếu bạn muốn mã có thể đơn giản nhất để trích xuất hình thu nhỏ dưới dạng JFIF, bạn sẽ cần thực hiện các bước sau:

  1. Tự làm quen với các dấu/thẻ JFIF và TIFF. Các dấu JFIF bao gồm hai byte: 0xFF theo sau là kiểu dấu (0xE1 cho APP1). Hai byte này được theo sau bởi độ dài hai byte được lưu trữ theo thứ tự lớn. Đối với các tệp TIFF, hãy tham khảo tài liệu tham khảo Adobe TIFF 6.0.
  2. Tìm kiếm tệp JPEG của bạn cho điểm đánh dấu EXIF ​​APP1 (FFE1). Có thể có nhiều điểm đánh dấu APP1 và có thể có nhiều điểm đánh dấu trước APP1.
  3. Điểm đánh dấu APP1 bạn đang tìm chứa các chữ cái "EXIF" ngay sau trường độ dài.
  4. Tìm "II" hoặc "MM" (6 byte cách chiều dài) để cho biết độ bền được sử dụng trong tệp TIFF. II = Intel = nhỏ endian, MM = Motorola = lớn endian.
  5. Bỏ qua thẻ của trang đầu tiên để tìm IFD thứ hai nơi hình ảnh được lưu trữ. Trong "trang" thứ hai, tìm hai thẻ TIFF trỏ đến dữ liệu JPEG. Thẻ 0x201 có độ lệch của dữ liệu JPEG (so với II/MM) và thẻ 0x202 có độ dài bằng byte.
+2

Cũng có thể chỉ ra rằng có thể có nhiều hơn một hình ảnh độ phân giải giảm trong dữ liệu Exif. Ví dụ: trong tệp JPEG của Nikon, có hình thu nhỏ và hình ảnh xem trước thứ hai (lớn hơn). Hạn chế duy nhất là tổng số dữ liệu Exif không được vượt quá 64.000 byte. Một điểm khác - các dữ liệu Exif có thể là endian nhỏ hoặc endian lớn như bạn nói. Tuy nhiên, các điểm đánh dấu JPEG và dữ liệu cũng như dữ liệu thu nhỏ luôn là kết thúc lớn. Các điểm đánh dấu như 0xFFE1 (điểm đánh dấu APP1) được xác định bởi tiêu chuẩn JPEG ISO DIS 10918-1 và có sẵn trên mạng. –

+1

Cảm ơn bạn, tôi đã viết mã thành công với sự giúp đỡ của bạn! –

+0

cảm ơn bạn, nó rất rõ ràng –

-1

Trang wikipedia trên JFIF tại http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format mô tả đúng tiêu đề JPEG (tiêu đề chứa hình thu nhỏ dưới dạng hình ảnh raster không nén). Điều đó sẽ cung cấp cho bạn một ý tưởng về cách bố trí và do đó mã cần thiết để trích xuất thông tin.

hexdump của một tiêu đề hình ảnh (little endian hiển thị):

[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 

Hình ảnh kì ảo (byte 1,0), App0 Segment tiêu đề Magic (byte 3,2), Header Chiều dài (5,4) Tiêu đề Nhập chữ ký ("JFIF \ 0" || "JFXX \ 0") (byte 6-10), Phiên bản (byte 11,12) Đơn vị mật độ (byte 13), Mật độ X (byte 15,14), Mật độ Y (byte 17,16), Chiều rộng hình thu nhỏ (byte 19), Chiều cao hình thu nhỏ (byte 18) và cuối cùng là "Chiều dài tiêu đề" là dữ liệu hình thu nhỏ.

Từ ví dụ trên, bạn có thể thấy rằng độ dài tiêu đề là 16 byte (byte 6,5) và phiên bản là 01,01 (byte 12,13). Hơn nữa, như Chiều rộng Hình thu nhỏ và Chiều cao Hình thu nhỏ đều là 0x00, hình ảnh không chứa hình thu nhỏ.

+0

Phân tích của bạn về tiêu đề JFIF không chính xác. Tệp JPEG thường chứa hình ảnh thu nhỏ được nén JPEG. Chiều rộng và chiều cao của hình thu nhỏ được lưu trữ trong điểm đánh dấu APP1 như là một phần của tệp TIFF. Bạn có thể thấy trong bãi chứa của bạn tại offset 0x1E bắt đầu của tiêu đề TIFF "II" theo sau là phiên bản 0x2a và IFD offset 0x0008. – BitBank

+0

Phân tích của tôi dựa trên thông tin tìm thấy trên http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format cũng như tiêu chuẩn jpeg http://www.ecma-international.org/publications/files/ECMA-TR/TR -098.pdf Mục 10 (trang 5). Vui lòng giải thích chi tiết hơn về nguồn thông tin của bạn. Có thể bạn đang nói về định dạng phân đoạn mở rộng JFIF (JFXX), trong khi ví dụ trên là định dạng phân đoạn JFIF (byte offset 0x06-0x10 là "JFIF \ 0") – Samveen

+1

Thông tin thu nhỏ có thể nằm trong thông số kỹ thuật, nhưng đó là không phải cách nó được sử dụng trong thế giới thực. Tôi chưa bao giờ thấy một hình ảnh JPEG với hình thu nhỏ trong tiêu đề APP0. Nó được lưu trữ (thường được nén) trong tiêu đề EXIF ​​(APP1) như một phần của tệp TIFF chứa thông tin EXIF ​​khác dưới dạng thẻ TIFF. Đăng tập tin bạn tham khảo ở trên và tôi sẽ cho bạn biết những gì trong đó. – BitBank

4

Có một giải pháp đơn giản hơn nhiều cho vấn đề này, nhưng tôi không biết nó đáng tin cậy như thế nào: Bắt đầu đọc tệp JPEG từ byte thứ ba và tìm kiếm FFD8 (bắt đầu đánh dấu ảnh JPEG), FFD9 (kết thúc điểm đánh dấu ảnh JPEG). Giải nén nó và thì đấy, đó là hình thu nhỏ của bạn.

Một thi JavaScript đơn giản:

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

Mã đơn giản đẹp cho một bằng chứng về khái niệm, nhưng điều này phá vỡ cho khoảng 1/20 ảnh tôi có, bởi vì tôi không nghĩ rằng bạn có thể đảm bảo rằng 0xFFD8 không xuất hiện ở nơi khác. –

11

Exiftool là rất có khả năng để làm điều này một cách nhanh chóng và dễ dàng:

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

Bạn nên sử dụng 'exiftool -a -b -W% d% f_% t% -c.% S -preview: tất cả YourFileOrDirectory' để trích xuất mọi biến thể hình thu nhỏ. – tricasse

+2

Các loại hình thu nhỏ có sẵn trong ExifTool có thể được liệt kê bởi 'exiftool -list -preview: all'. – tricasse

Các vấn đề liên quan