2012-04-27 15 views
10

Chciałbym wyodrębnić miniaturę z jpegs, bez żadnej zewnętrznej biblioteki. Chodzi mi o to, że nie jest to zbyt trudne, ponieważ muszę wiedzieć, gdzie zaczyna się miniatura, a kończy w pliku i po prostu go wyciąć. Studiuję wiele dokumentacji (np .: http://www.media.mit.edu/pia/Research/deepview/exif.html) i próbuję analizować jpeg, ale nie wszystko jest jasne. Próbowałem krok po kroku śledzić bajty, ale w głębi dezorientowałem się. Czy istnieje dobra dokumentacja lub czytelny kod źródłowy do wyodrębnienia informacji o początkowym i końcowym położeniu miniatury w pliku jpeg?Wyciągnij miniaturę z pliku jpeg

Dziękujemy!

+1

Istnieją co najmniej 3 miejsca, które mogą przechowywać miniatury dla obrazów JPEG: JFIF/APP0 , EXIF ​​APP1 i ADEOBE APP13. Tutaj http://javagraphics.blogspot.ca/2010/03/images-reading-jpeg-thumbnails.html jest blogiem na ten temat i może ci się również przydać ten https://github.com/dragon66/icafe/wiki. – dragon66

Odpowiedz

11

W przypadku większości zdjęć w formacie JPEG utworzonych za pomocą telefonów lub aparatów cyfrowych miniaturka obrazu (jeśli występuje) jest zapisana w znaczniku APP1 (FFE1). Wewnątrz tego segmentu znacznika znajduje się plik TIFF zawierający informacje EXIF ​​dla obrazu głównego i opcjonalnego obrazu miniatury zapisanego jako obraz skompresowany w formacie JPEG. Plik TIFF zwykle zawiera dwie "strony", gdzie pierwsza strona jest informacją EXIF, a druga strona jest miniaturą zapisaną w "starym" formacie TIFF typu 6. Typ 6 to format, w którym plik JPEG jest właśnie zapisywany jako-znajduje się wewnątrz opakowania TIFF. Jeśli chcesz najprostszy możliwy kod do wyodrębnienia miniatury jako JFIF, musisz wykonać następujące kroki:

  1. Zapoznaj się ze znacznikami/znacznikami JFIF i TIFF. Znaczniki JFIF składają się z dwóch bajtów: 0xFF, po którym następuje typ znacznika (0xE1 dla APP1). Po tych dwóch bajtach następuje dwubajtowa długość przechowywana w kolejności wielko-endianowej. W przypadku plików TIFF zapoznaj się z odniesieniem do programu Adobe TIFF 6.0.
  2. Wyszukaj swój plik JPEG dla znacznika EXIF ​​APP1 (FFE1). Może występować wiele markerów APP1 i może istnieć wiele markerów przed APP1.
  3. Znacznik APP1, którego szukasz zawiera litery "EXIF" zaraz po polu długości.
  4. Odszukaj "II" lub "MM" (6 bajtów od długości), aby wskazać endianness użytą w pliku TIFF. II = Intel = mały endian, MM = Motorola = duży endian.
  5. Pomiń znaczniki pierwszej strony, aby znaleźć drugie IFD, w którym zapisany jest obraz. Na drugiej "stronie" wyszukaj dwa znaczniki TIFF, które wskazują dane JPEG. Znacznik 0x201 ma przesunięcie danych JPEG (względem II/MM), a znacznik 0x202 ma długość w bajtach.
+2

Może również zwrócić uwagę, że w danych Exif może występować więcej niż jeden obraz o zmniejszonej rozdzielczości. Na przykład w plikach JPEG firmy Nikon znajduje się miniatura i drugi (większy) obraz podglądu. Jedynym ograniczeniem jest to, że całkowita ilość danych Exif nie może przekroczyć 64 000 bajtów. Kolejna kwestia - dane Exif mogą być małe endianów lub dużych endianów, jak mówisz. Jednak znaczniki i dane JPEG oraz dane miniatur są zawsze duże endian. Znaczniki takie jak 0xFFE1 (znacznik APP1) są zdefiniowane przez standard JPEG ISO DIS 10918-1 i są dostępne on-line. –

+1

Dziękuję, udało mi się napisać kod przy pomocy! –

+0

dziękuję, to jest bardzo jasne –

-1

Strona wikipedia na JFIF pod http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format podaje dobry opis nagłówka JPEG (nagłówek zawiera miniaturę jako nieskompresowany obraz rastrowy). To powinno dać ci wyobrażenie o układzie, a tym samym kod potrzebny do wyodrębnienia informacji.

hexdump nagłówka obrazu (little endian wyświetlacza):

[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 

Obrazek Magii (bajty 1,0), App0 nagłówek segmentu Magia (bajty 3,2), długość nagłówka (5,4) Header Wpisz podpis ("JFIF \ 0" || "JFXX \ 0") (bajty 6-10), Wersja (bajty 11,12) Jednostki gęstości (bajt 13), X Gęstość (bajty 15,14), Y Gęstość (bajty 17,16), szerokość Thumbnail (byte 19), Thumbnail height (byte 18), a na koniec spoczynkowo do "Header Length" są dane miniatur.

Z powyższego przykładu widać, że długość nagłówka wynosi 16 bajtów (bajty 6,5), a wersja to 01.01 (bajty 12,13). Ponadto, ponieważ szerokość i wysokość miniaturek są równe 0x00, obraz nie zawiera miniatury.

+0

Twoja analiza nagłówka JFIF jest niepoprawna. Pliki JPEG zwykle zawierają skompresowane miniaturki JPEG. Szerokość i wysokość miniatur są przechowywane w znaczniku APP1 jako część pliku TIFF. Możesz zobaczyć w swoim zrzucie w offsecie 0x1E początek nagłówka TIFF "II", a następnie wersję 0x2a i przesunięcie IFD 0x0008. – BitBank

+0

Moja analiza oparta jest na informacjach znalezionych na http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format, a także na standardzie jpeg http://www.ecma-international.org/publications/files/ECMA-TR/TR -098.pdf Rozdział 10 (strona 5). Proszę opracować więcej na temat źródła informacji. Prawdopodobnie mówimy o formacie segmentu JFIF (JFXX), podczas gdy powyższy przykład dotyczy formatu segmentu JFIF (offset bajtów 0x06-0x10 to "JFIF \ 0"). – Samveen

+1

Informacje o miniaturze mogą znajdować się w specyfikacji, ale to nie w jaki sposób jest używany w prawdziwym świecie. Nigdy nie widziałem obrazu JPEG z miniaturą w nagłówku APP0. Jest przechowywany (zazwyczaj skompresowany) w nagłówku EXIF ​​(APP1) jako część pliku TIFF, który zawiera inne informacje EXIF ​​jako znaczniki TIFF. Opublikuj powyższy plik, a powiem Ci, co w nim jest. – BitBank

4

Jest o wiele prostsze rozwiązanie tego problemu, ale nie wiem, jak jest on wiarygodny: Zacznij czytać plik JPEG z trzeciego bajtu i wyszukaj FFD8 (początek znacznika obrazu JPEG), a następnie dla FFD9 (koniec znacznika obrazu JPEG). Wypakuj to i voila, to twoja miniatura.

Prosta implementacja języka 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

Przyjemny prosty kod za dowód koncepcji, ale to zrywa z około 1/20 zdjęć, które mam, ponieważ nie sądzę, że można zagwarantować, że 0xFFD8 nie pojawi się gdzie indziej. –

11

Exiftool jest bardzo zdolny to szybko i łatwo:

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

Powinieneś użyć 'exiftool -a -b -W% d% f_% t% -c.% S -preview: all YourFileOrDirectory', aby wyodrębnić każdy wariant miniatury. – tricasse

+2

Typy miniatur dostępne w ExifTool można wyświetlić za pomocą 'exiftool -list -preview: all'. – tricasse