2011-01-03 1 views
17

Sto inviando molte immagini dal mio server al client in sequenza continuamente tramite TCP.Ora al client, come dovrei rilevare in modo efficiente che questa è la fine della mia immagine, quindi scriverlo nel file system e quindi immagine successiva e così via.Rileva Eof per immagini JPG

Con i migliori saluti, ...

+0

"Invio" utilizzando quale protocollo? Il tuo protocollo non sa quando termina automaticamente un file? –

+1

Perché non inviare preventivamente la lunghezza dell'immagine? – Kornel

+0

Utilizzare un protocollo. –

risposta

26

Beh, non c'è alcuna garanzia che non troverai FFD9 all'interno di un'immagine jpeg. Il modo migliore per trovare la fine di un'immagine jpeg è analizzarlo. Ogni marcatore, ad eccezione di FFD0 a FFD9 e FF01 (riservato), viene immediatamente seguito da un identificatore di lunghezza che ti darà la lunghezza di quel segmento di marcatore, incluso l'identificatore di lunghezza ma non il marcatore. FF00 non è un marker, ma per i tuoi scopi puoi trattarlo come marker senza un identificatore di lunghezza.

Lo specificatore di lunghezza è lungo due byte ed è big endian. Quindi, quello che farai è cercare FF, e se il seguente byte non è uno di 0x00, 0x01 o 0xD0-0xD8, leggi l'identificatore di lunghezza e salta avanti nel flusso finché l'identificatore di lunghezza dice meno due byte.

Inoltre, ogni indicatore può essere riempito all'inizio con qualsiasi numero di FF.

Quando arrivi a FFD9 sei alla fine del flusso.

Ovviamente si può leggere il flusso parola per parola, cercando FF se si desidera una performance ma è lasciato come esercizio per il lettore. ;-)

+1

Dovrei chiarire la prima frase. È ovvio che FFD9 è alla fine di un'immagine. Ma FFD9 potrebbe apparire incorporato in un'immagine JPEG senza essere un marcatore EOI. Ecco perché devi _ analizzare il file JPEG per trovare il marcatore EOI. – onemasse

+4

** Riepilogato **: lettura 0xFF. Leggi il marcatore. Leggi lo specificatore della lunghezza L e salta avanti di L - 2 byte. Dopo un segmento SOS (0xFFDA) (seguito da dati compressi), vai al primo 0xFF ** not ** seguito da 0x00 o 0xD0-0xD8. Ripeti dall'inizio fino a quando non incontri 0xFFD9. Funziona su [questo multi-scan JPEG] (http://hodapple.com/blag/assets/obscure_jpeg_features/20100713-0107-interleave.jpg). –

+1

Questo approccio è vulnerabile alle immagini danneggiate (sia file che sono stati tagliati per errore o immagini falsificate ingegnerizzate) –

12

Un rapido sguardo a Wikipedia's JPEG article ti avrebbe dato la risposta:

  • byte 0xFF, 0xd8 indicano inizio di immagine
  • byte 0xFF, 0xD9 indicare la fine dell'immagine
+5

Importante notare che ci possono essere file JPEG incorporati nei file JPEG (ad esempio l'immagine di anteprima) in modo da poter visualizzare i marcatori EOI SOI SOI EOI. Assicurati di prenderlo in considerazione. –

+0

@ SB: vero. Un modo infallibile sarebbe quello di scansionare i marcatori EOI SOI in sequenza se la lettura da stream non è finita, e per EOI se è finita. – darioo

-3

onemase

Perché stai dicendo non v'è garanzia di trovare EOI? Deve essere lì alla fine.

C'è almeno un altro contrassegno che non è seguito dal campo di lunghezza di 2 byte. È SOS, Start of Scan, 0xFFDA. E 'seguita da

lunghezza - Ls specificati come 6 + 2xNs (due byte)

numero di segmenti Ns (un byte)

campi successivi di questa intestazione non contengono la dimensione dei dati entropia che segue l'intestazione SOS. Quindi l'unico modo per trovare la dimensione è guardare byte per byte per EOI (End Of Image) = 0xFFD9.

Mi piacerebbe trovare altro modo.

+0

Ti stai sbagliando. Non è garantito che un'immagine jpeg non sia incorporata come miniatura all'interno di un segmento APP. Scansionando sequenzialmente troverai EOI prematuramente. – onemasse

+0

Sì. Non ho detto di immagini incorporate. Quindi l'unico modo per cercare la dimensione di un flusso è cercare tutte le coppie di StartOfImage, EndOfImage imho. Affidarsi alla lunghezza non funziona perché il marcatore SOS non è seguito dalla lunghezza. – whobertoos

+1

No, perché l'immagine incorporata è solo un esempio. Il segmento APP potrebbe contenere qualsiasi cosa, incluso FFD9. Devi cercare in sequenza, ma saltare i segmenti che puoi. Il modo per farlo è descritto nella mia risposta. – onemasse

0

Se si inviano le immagini tramite un array di byte, è possibile aggiungere semplicemente le dimensioni del file dell'immagine come una coppia di byte prima dell'inizio del file.
Il client afferra i primi due byte per trovare il numero specificato di byte (lo chiameremo x) e li elimina, quindi pompa il successivo numero x di byte in un buffer che può scrivere su file.
Risciacquare e ripetere per tutti i seguenti jpeg.

Un'alternativa è solo cercare il marcatore FFD9 - se non sbaglio, qualsiasi valore compresso FF sarà codificato come FF00 (il byte 00 viene scartato e il byte FF viene mantenuto).
Il problema con questo è che si ottiene cose come miniature con le proprie intestazioni FFD9, ma quelle sono contenute all'interno di un segmento nelle intestazioni. Questi segmenti hanno un valore di lunghezza nei due byte dopo il loro indicatore in modo da poter saltare alla fine di ogni segmento che si incontra per evitare il rilevamento prematura di eoi.