2011-01-03 28 views
17

Wysyłam wiele obrazów z mojego serwera do klienta w sekwencji w sposób ciągły przez TCP. Teraz na kliencie, w jaki sposób powinienem skutecznie wykryć, że jest to koniec mojego jednego obrazu, więc zapisz go w systemie plików, a następnie następny obraz i tak dalej.Wykryj Eof dla obrazów JPG

poważaniem, ...

+0

"Wysyłanie" za pomocą jakiego protokołu? Czy twój protokół nie wie, kiedy plik kończy się automatycznie? –

+1

Dlaczego wcześniej nie wysłać długości obrazu? – Kornel

+0

Użyj protokołu. –

Odpowiedz

26

Nie ma gwarancji, że FFD9 nie znajdzie się w obrazie jpeg. Najlepszym sposobem znalezienia końca obrazu jpeg jest przeanalizowanie go. Każdy znacznik, z wyjątkiem FFD0 do FFD9 i FF01 (zastrzeżone), następuje bezpośrednio długości specyfikatorem który daje długość tego segmentu znacznika, w tym informacji o długości, ale nie markera. FF00 nie jest znacznikiem, ale dla swoich celów możesz traktować go jako znacznik bez specyfikatora długości.

Specyfikator długości ma długość dwóch bajtów i jest dużym endianem. Więc co można zrobić, to znaleźć na FF, a jeśli następuje bajt nie jest jednym z 0x00, 0x01 lub 0xD0-0xD8, odczytać długość specyfikator i przeskakuje do przodu w strumieniu dopóki długość specifier mówi minus dwa bajty.

Ponadto, każdy znacznik może zostać dopełniony na początku dowolną liczbą FF.

Po przejściu do FFD9 jesteś na końcu strumienia.

Oczywiście można czytać strumień słowo po słowie, szukając FF, jeśli chcesz wydajności, ale to pozostało jako ćwiczenie dla czytelnika. ;-)

+1

Powinienem wyjaśnić pierwsze zdanie. Oczywiste jest, że FFD9 znajduje się na końcu obrazu. Ale FFD9 może pojawić się osadzone w obrazie JPEG bez bycia znacznikiem EOI. Dlatego masz _ przeanalizować plik JPEG, aby znaleźć znacznik EOI. – onemasse

+4

** Podsumowany **: Czytaj 0xFF. Czytaj znacznik. Przeczytaj specyfikator długości L i przejdź do przodu o L - 2 bajty. Po segmencie SOS (0xFFDA) (a następnie skompresowanych danych) przejdź do pierwszego 0xFF ** nie **, a następnie 0x00 lub 0xD0-0xD8. Powtarzaj od początku, aż napotkasz 0xFFD9. Działa na [to wielo-skan JPEG] (http://hodapple.com/blag/assets/obscure_jpeg_features/20100713-0107-interleave.jpg). –

+1

To podejście jest podatne na uszkodzenia (pliki, które zostały obcięte przez przypadek lub złośliwie zmodyfikowane fałszywe obrazy) –

12

Szybkie spojrzenie na Wikipedia's JPEG article dałby wam odpowiedź:

  • bajtów 0xFF, 0xD8 wskazują początek obrazu
  • bajtów 0xFF, 0xD9 wskazuje koniec obrazu
+5

Ważne, aby pamiętać, że JPEG może zawierać pliki JPEG (np. Miniaturę), więc możesz zobaczyć znaczniki SOI SOI EOI EOI. Pamiętaj, aby wziąć to pod uwagę. –

+0

@SB: true. Niezawodny sposób polegałby na skanowaniu znaczników EOI SOI po kolei, jeśli odczyt ze strumienia nie został zakończony, a także w przypadku EOI, jeśli jest gotowy. – darioo

-3

onemase

Dlaczego mówisz, że nie ma gwarancji, aby znaleźć EoI? Musi tam być na końcu.

Istnieje co najmniej jeden znacznik, po którym nie występuje pole o długości 2 bajtów. Jest to SOS, Początek skanowania, 0xFFDA. To jest po

długości - Ls określono jako 6 + 2xNs (dwa bajty)

liczby segmentów Ns (jeden bajt)

Kolejne pola tego nagłówka nie zawierają rozmiar danych entropii który następuje po nagłówku SOS. Dlatego jedynym sposobem, aby znaleźć rozmiar jest patrzeć bajt po bajcie na EOI (koniec obrazu) = 0xFFD9.

chciałbym znaleźć inny sposób.

+0

Mylisz się. Nie ma gwarancji, że obraz jpeg nie zostanie osadzony jako miniatura w segmencie APP. Poprzez skanowanie sekwencyjne EOI znajdzie się przedwcześnie. – onemasse

+0

Tak. Nie mówiłem o osadzonych obrazach. Tak więc jedynym sposobem na sprawdzenie wielkości strumienia jest wyszukanie wszystkich par StartOfImage, EndOfImage imho. Poleganie na długości nie zadziała, ponieważ znacznik SOS nie jest śledzony przez długość. – whobertoos

+1

Nie, ponieważ osadzony obraz jest tylko przykładem. Segment aplikacji może zawierać wszystko, w tym FFD9. Musisz wyszukiwać sekwencyjnie, ale pomiń segmenty, które możesz. Sposób, w jaki to robię, opisano w mojej odpowiedzi. – onemasse

0

Jeśli wysyłasz obrazy za pomocą tablicy bajtów, możesz po prostu dodać rozmiar pliku obrazu jako parę bajtów przed rozpoczęciem pliku.
Klient pobiera pierwsze dwa bajty w celu znalezienia określonej liczby bajtów (nazwiemy to x) i odrzuca je, a następnie pompuje następną liczbę bajtów x do bufora, który może zapisać do pliku.
Przepłukać i powtórzyć dla wszystkich następujących jpeg.

Alternatywą jest po prostu szukanie znacznika FFD9 - jeśli się nie mylę, skompresowana wartość FF zostanie zakodowana jako FF00 (bajt 00 zostanie odrzucony, a bajt FF zostanie zachowany).
Problem polega na tym, że dostajesz takie miniatury, jak z ich własnymi nagłówkami FFD9, ale są one zawarte w segmencie w nagłówkach. Segmenty te mają wartość długości w dwóch bajtach po znaczniku, więc możesz po prostu przejść do końca dowolnego segmentu, aby uniknąć przedwczesnego wykrycia eoi.