2013-08-16 9 views
5

In primo luogo voglio dire che ho provato molte volte a trovare la risposta usando la ricerca di google, e ho trovato molti risultati ma non ho capito, perché non conosco l'idea di leggere un file binario e convertire il valore che Ottenuto a valore leggibile.Come ottenere la larghezza/altezza del file jpeg senza usare la libreria?

Quello che ho provato a farlo.

unsigned char fbuff[16]; 
FILE *file; 
file = fopen("C:\\loser.jpg", "rb"); 
if(file != NULL){ 
    fseek(file, 0, SEEK_SET); 
    fread(fbuff, 1, 16, file); 
    printf("%d\n", fbuff[1]); 
    fclose(file); 
}else{ 
    printf("File does not exists."); 
} 

Voglio una spiegazione semplice con esempio mostra, come ottenere la larghezza/altezza del file jpeg dalla sua intestazione, e poi convertire tale valore per il valore leggibile.

+0

Avete i dettagli di ciò che è contenuto nei file JPEG? Se lo hai, per favore includilo nella tua domanda. Dubito che il tuo metodo sopra funzionerà dato che all'inizio c'è generalmente un'intestazione e poi iniziano i valori effettivi dei pixel. Se hai bisogno solo delle informazioni di altezza e larghezza, credo che puoi ottenerlo leggendo da solo l'intestazione. – shrm

+0

@mishr: sto parlando di 'file jpeg 'in generale. –

+0

Capisco, ma la domanda è: sai qual è il formato per i file jpeg? O vuoi che lo troviamo per te? – shrm

risposta

12

Sfortunatamente, non sembra essere semplice per JPEG. Si dovrebbe guardare la fonte allo strumento da riga di comando jhead. Fornisce queste informazioni. Passando attraverso la fonte, vedrai la funzione ReadJpegSections. Questa funzione analizza tutti i segmenti contenuti nel file JPEG per estrarre le informazioni desiderate. La larghezza e l'altezza dell'immagine si ottengono quando si elaborano i frame con un indicatore SOFn.

vedo la fonte è di pubblico dominio, quindi te lo mostrerò il frammento che ottiene l'Info d'immagine:

static int Get16m(const void * Short) 
{ 
    return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1]; 
} 

static void process_SOFn (const uchar * Data, int marker) 
{ 
    int data_precision, num_components; 

    data_precision = Data[2]; 
    ImageInfo.Height = Get16m(Data+3); 
    ImageInfo.Width = Get16m(Data+5); 

dal codice sorgente, è chiaro per me non esiste un unico colpo di testa " "con questa informazione. È necessario eseguire la scansione del file JPEG, analizzando ogni segmento, finché non si trova il segmento con le informazioni in esso desiderate. Questo è descritto nella wikipedia article:

immagine Un JPEG costituito da una sequenza di segmenti, ogni inizio con un marcatore, ognuno dei quali inizia con un byte 0xFF seguito da un byte che indica il tipo di indicatore è. Alcuni indicatori consistono solo di quei due byte; altri sono seguiti da due byte che indicano la lunghezza dei dati del payload specifici del marcatore che segue.


Un file JPEG è costituito da una sequenza di segmenti:

SEGMENT_0 
SEGMENT_1 
SEGMENT_2 
... 

Ogni segmento inizia con un pennarello 2 byte. Il primo byte è 0xFF, il secondo byte determina il tipo del segmento. Questo è seguito da una codifica della lunghezza del segmento. All'interno del segmento sono dati specifici per quel tipo di segmento.

La larghezza e l'altezza dell'immagine si trovano in un segmento di tipo SOFn o "Inizio frame [n]", dove "n" è un numero che significa qualcosa di speciale per un decodificatore JPEG. Dovrebbe essere sufficiente per cercare solo uno SOF0 e la sua designazione di byte è 0xC0. Una volta trovato questo frame, puoi decodificarlo per trovare l'altezza e la larghezza dell'immagine.

Quindi la struttura di un programma per fare quello che vuoi sarebbe simile:

file_data = the data in the file 
data = &file_data[0] 
while (data not at end of file_data) 
    segment_type = decoded JPEG segment type at data 
    if (type != SOF0) 
     data += byte length for segment_type 
     continue 
    else 
     get image height and width from segment 
     return 

Questo è essenzialmente la struttura si trovano in Michael Petrov's get_jpeg_size() implementation.

+0

@LionKing, fammi sapere se la spiegazione non è chiara o se hai bisogno di ulteriore aiuto. – jxh

+0

Grazie, ma non lo capisco, voglio un modo molto semplice e un esempio per capirlo. –

+0

Gradirei molto un motivo per il voto negativo. Grazie! – jxh

0

Ecco un semplice codice che ho scritto che sembra funzionare in modo affidabile.

#define MOTOSHORT(p) ((*(p))<<8) + *(p+1) 
unsigned char cBuf[32]; 
int iBytes, i, j, iMarker, iFilesize; 
unsigned char ucSubSample; 
int iBpp, iHeight, iWidth; 

     Seek(iHandle, 0, 0); // read the first 32 bytes 
     iBytes = Read(iHandle, cBuf, 32); 

     i = j = 2; /* Start at offset of first marker */ 
     iMarker = 0; /* Search for SOF (start of frame) marker */ 
     while (i < 32 && iMarker != 0xffc0 && j < iFileSize) 
      { 
      iMarker = MOTOSHORT(&cBuf[i]) & 0xfffc; 
      if (iMarker < 0xff00) // invalid marker, could be generated by "Arles Image Web Page Creator" or Accusoft 
       { 
       i += 2; 
       continue; // skip 2 bytes and try to resync 
       } 
      if (iMarker == 0xffc0) // the one we're looking for 
       break; 
      j += 2 + MOTOSHORT(&cBuf[i+2]); /* Skip to next marker */ 
      if (j < iFileSize) // need to read more 
       { 
       Seek(iHandle, j, 0); // read some more 
       iBytes = Read(iHandle, cBuf, 32); 
       i = 0; 
       } 
      else // error, abort 
       break; 
      } // while 
     if (iMarker != 0xffc0) 
      goto process_exit; // error - invalid file? 
     else 
      { 
      iBpp = cBuf[i+4]; // bits per sample 
      iHeight = MOTOSHORT(&cBuf[i+5]); 
      iWidth = MOTOSHORT(&cBuf[i+7]); 
      iBpp = iBpp * cBuf[i+9]; /* Bpp = number of components * bits per sample */ 
      ucSubSample = cBuf[i+11]; 
      } 
+0

Grazie, è l'esempio precedente usando 'C/C++' ?, quali sono 'Seek',' Leggi' le funzioni?, E Qual è il vantaggio di questa funzione 'MOTOSHORT'?, Anche quale è la variabile' iHandle' ?. –

+0

Le funzioni di ricerca e lettura sono file generici i/o che dovrebbero esistere in tutti i sistemi. Il MOTOSHORT è una macro (vedi parte superiore del codice) che è comoda per la lettura di cortometraggi di grandi endian su qualsiasi sistema, indipendentemente dalle endianess. La variabile ihandle è l'handle di file che si presume venga aperto prima di chiamare la funzione. – BitBank

0
int GetJpegDimensions(
    char   *pImage, 
    size_t   nSize, 
    unsigned32  *u32Width, 
    unsigned32  *u32Height, 
    char   *szErrMsg) 
{ 
    int    nIndex; 
    int    nStartOfFrame; 
    int    nError = NO_ERROR; 
    bool   markerFound = false; 
    unsigned char ucWord0; 
    unsigned char ucWord1; 

    // verify START OF IMAGE marker = FF D8 
    nIndex = 0; 
    ucWord0 = pImage[nIndex]; 
    ucWord1 = pImage[nIndex+1]; 

    // marker FF D8 starts a valid JPEG 
    if ((ucWord0 == 0xFF) && (ucWord1 == 0xD8)) 
    { 
     // search for START OF FRAME 0 marker FF C0 
     for (nIndex = 2; 
      (nIndex < nSize-2) && (markerFound == false); 
      nIndex += 2) 
     { 
      ucWord0 = pImage[nIndex]; 
      ucWord1 = pImage[nIndex+1]; 
      if (ucWord0 == 0xFF) 
      { 
       if (ucWord1 == 0xC0) 
       { 
        markerFound = true; 
        nStartOfFrame = nIndex; 
       } 
      } 
      if (ucWord1 == 0xFF) 
      { 
       ucWord0 = pImage[nIndex+2]; 
       if (ucWord0 == 0xC0) 
       { 
        markerFound = true; 
        nStartOfFrame = nIndex+1; 
       } 
      } 
     } // while 

     if (markerFound) 
     { 
      nError = NO_ERROR; 
      ucWord0 = pImage[nStartOfFrame+5]; 
      ucWord1 = pImage[nStartOfFrame+6]; 
      *u32Height = ucWord1 + (ucWord0 << 8); 

      ucWord0 = pImage[nStartOfFrame+7]; 
      ucWord1 = pImage[nStartOfFrame+8]; 
      *u32Width = ucWord1 + (ucWord0 << 8); 
     } 
     else 
     { 
      // start of frame 0 not found 
      nError = -2; 
      sprintf(szErrMsg, 
       "Not a valid JPEG image. START OF FRAME 0 marker FFC0 not found"); 
     } 
    } 
    else // START OF IMAGE marker not found 
    { 
     nError = -1; 
     sprintf(szErrMsg, 
      "Not a valid JPEG image. START OF IMAGE marker FFD8 not found"); 
    } 
    return nError; 
} 
4

allora dovete trovare altezza e larghezza del marcatore jpeg che è [ffc0].

dopo aver trovato ffc0 in formato binario, i quattro, cinque byte sono alti e sei e sette byte sono larghi.

eg: [ff c0] d8 c3 c2 [ff da] [00 ff] 
         |   | 
         |   | 
         ->height ->width 

int position; 
unsigned char len_con[2]; 
/*Extract start of frame marker(FFC0) of width and hight and get the position*/ 
for(i=0;i<FILE_SIZE;i++) 
{ 
    if((image_buffer[i]==FF) && (image_buffer[i+1]==c0)) 
    { 
     position=i; 
    } 
} 
/*Moving to the particular byte position and assign byte value to pointer variable*/ 
position=position+5; 
*height=buffer_src[position]<<8|buffer_src[position+1]; 
*width=buffer_src[position+2]<<8|buffer_src[position+3]; 

printf("height %d",*height); 
printf("width %d",*width); 
0

Ecco un codice che ho scritto in Java. Funziona bene per i jpeg presi da una fotocamera. Esegue la scansione di tutto il codice per trovare la dimensione dell'immagine più grande. Non ho potuto migliorarlo per saltare le lunghezze di ogni blocco perché non funziona. Se qualcuno può migliorare il codice per farlo sarebbe fantastico.

int getShort(byte[] p, int i) 
{ 
    int p0 = p[i] & 0xFF; 
    int p1 = p[i+1] & 0xFF; 
    return p1 | (p0 << 8); 
} 

int[] GetJpegDimensions(byte[] b) 
{ 
    int nIndex; 
    int height=0, width=0, size=0; 
    int nSize = b.length; 

    // marker FF D8 starts a valid JPEG 
    if (getShort(b,0) == 0xFFD8) 
     for (nIndex = 2; nIndex < nSize-1; nIndex += 4) 
      if (b[nIndex] == -1/*FF*/ && b[nIndex+1] == -64/*C0*/) 
      { 
      int w = getShort(b,nIndex+7); 
      int h = getShort(b,nIndex+5); 
      if (w*h > size) 
      { 
       size = w*h; 
       width = w; 
       height = h; 
      } 
      } 
    return new int[]{width,height}; 
} 
2

la domanda è vecchia e le altre risposte sono corrette ma il loro formato non è il più semplice. Mi basta usare getc per ottenere rapidamente le dimensioni, mentre sono assenti i marcatori irrilevanti (supporta anche JPEG progressivi):

int height, width; 
    // start of image (SOI) 
    getc(f); // oxff 
    getc(f); // oxd8 
    // Scan miscellaneous markers until we reach SOF0 marker (0xC0) 
    for(;;) { 
    // next marker 
    int marker; 
    while((marker = getc(f)) != 0xFF); 
    while((marker = getc(f)) == 0xFF); 
    // SOF 
    if (marker == 0xC0 || marker == 0xC2) { 
     getc(f); // length (2 bytes) 
     getc(f); // # 
     getc(f); // bpp, usually 8 
     height = (getc(f) << 8) + getc(f); // height 
     width = (getc(f) << 8) + getc(f); // width 
     break; 
    } 
    } 
+0

A meno che non manchi qualcosa, questa e tutte le altre risposte che leggono tutti i byte falliranno se il segmento ff c0 o ff c2 arriva dopo un altro segmento in cui il carico utile contiene ff c0/ff c2. –

Problemi correlati