2013-08-16 10 views
5

Erstens möchte ich sagen, ich habe oft versucht, die Antwort zu finden, indem Sie Google-Suche verwenden, und ich fand viele Ergebnisse, aber ich habe nicht verstanden, weil ich nicht die Idee des Lesens einer Binärdatei weiß, und den Wert konvertieren Erhalten zu lesbarem Wert.Wie bekomme ich die Breite/Höhe der JPEG-Datei ohne Verwendung der Bibliothek?

Was ich versuchte es zu tun.

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."); 
} 

Ich mag eine einfache Erklärung mit Beispiel zeigt, wie Breite/Höhe von JPEG-Datei aus seinem Header zu bekommen, und dann diesen Wert lesbar Wert umwandeln.

+0

Haben Sie die Details, was in den JPEG-Dateien enthalten ist? Wenn Sie haben, fügen Sie es bitte in Ihre Frage ein. Ich bezweifle, dass Ihre obige Methode funktioniert, da es in der Regel eine Kopfzeile am Anfang gibt und dann die eigentlichen Pixelwerte beginnen. Wenn Sie nur die Höhe und Breite Informationen benötigen, glaube ich, dass Sie das bekommen können, indem Sie den Header allein lesen. – shrm

+0

@misfr: Ich spreche über 'JPEG-Dateien' im Allgemeinen. –

+0

Ich verstehe das, aber die Frage ist, wissen Sie, was ist das Format für JPEG-Dateien? Oder willst du, dass wir es für dich finden? – shrm

Antwort

12

Leider scheint es für JPEG nicht einfach zu sein. Sie sollten sich die Quelle für das Befehlszeilen-Tool jhead ansehen. Es stellt diese Informationen bereit. Wenn Sie die Quelle durchlaufen, sehen Sie die Funktion ReadJpegSections. Diese Funktion durchsucht alle in der JPEG-Datei enthaltenen Segmente, um die gewünschten Informationen zu extrahieren. Die Bildbreite und -höhe wird erhalten, wenn die Rahmen verarbeitet werden, die einen SOFn Marker haben.

Ich sehe die Quelle in der Public Domain, also werde ich das Snippet zeigen, dass die Bildinfo bekommt:

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); 

aus dem Quellcode, ist es mir klar, gibt es keinen einzigen „header "Mit dieser Information. Sie müssen die JPEG-Datei durchsuchen und jedes Segment analysieren, bis Sie das Segment mit den gewünschten Informationen gefunden haben. Dies wird in der wikipedia article beschrieben:

Ein JPEG-Bild besteht aus einer Folge von Segmenten, jeder beginnend mit einem Marker, von denen jeder mit einem 0xFF Byte gefolgt von einem Byte beginnt angibt, welche Art von Marker ist. Einige Markierungen bestehen nur aus diesen zwei Bytes; Anderen folgen zwei Bytes, die die Länge markerspezifischer Nutzdaten angeben, die folgen.


ein JPEG-Datei besteht aus einer Folge von Segmenten:

SEGMENT_0 
SEGMENT_1 
SEGMENT_2 
... 

Jedes Segment beginnt mit einem 2-Byte-Marker. Das erste Byte ist 0xFF, das zweite Byte bestimmt den Typ des Segments. Danach folgt eine Codierung der Länge des Segments. Innerhalb des Segments gibt es Daten, die für diesen Segmenttyp spezifisch sind.

Die Bildbreite und -höhe wird in einem Segment des Typs SOFn oder "Start of frame [n]" gefunden, wobei "n" eine Zahl ist, die für einen JPEG-Decoder etwas Besonderes bedeutet. Es sollte gut genug sein, nur nach einem SOF0 zu suchen, und seine Byte-Bezeichnung ist 0xC0. Sobald Sie diesen Rahmen gefunden haben, können Sie ihn entschlüsseln, um die Höhe und Breite des Bildes zu finden.

So ist die Struktur eines Programms zu tun, was würden Sie aussehen wollen wie:

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 

Dies ist im Wesentlichen die in Michael Petrov's get_jpeg_size() implementation gefunden Struktur.

+0

@LionKing, lassen Sie mich wissen, wenn die Erklärung nicht klar ist oder wenn Sie zusätzliche Hilfe benötigen. – jxh

+0

Danke, aber ich verstehe es nicht, ich möchte einen sehr einfachen Weg und Beispiel, um es zu verstehen. –

+0

Ich würde einen Grund für die Down-Abstimmung sehr schätzen. Vielen Dank! – jxh

0

Hier ist ein einfacher Code, den ich schrieb, der zuverlässig funktioniert.

#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

Danke, ist das vorherige Beispiel mit 'C/C++' ?, was ist 'Suchen', 'Lesen' Funktionen?, Und was ist der Vorteil dieser Funktion' MOTOSHORT' ?, auch was ist 'iHandle' Variable ?. –

+0

Die Such- und Lesefunktionen sind generische Datei-E/A, die in allen Systemen vorhanden sein sollten. Das MOTOSHORT ist ein Makro (siehe Oberseite des Codes), das zum Lesen von Big-Endian-Kurzschlüssen auf jedem System geeignet ist, unabhängig von der Endanfälligkeit. Die Variable ihandle ist das Dateihandle, von dem angenommen wird, dass es vor dem Aufruf der Funktion geöffnet wird. – 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

dann müssen Sie Höhe und Breite Markierung von jpeg zu finden, die [ffc0].

nach dem Finden von ffc0 in Binärformat, die vier, fünf Bytes sind Höhe und sechs und sieben Bytes sind Breite.

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

Hier ist ein Code, den ich in Java schrieb. Funktioniert gut für JPEGs, die von einer Kamera aufgenommen wurden. Es scannt den gesamten Code, um die größte Bildgröße zu finden. Ich konnte es nicht verbessern, um die Längen jedes Blocks zu überspringen, weil es nicht funktioniert. Wenn jemand den Code verbessern kann, wäre das großartig.

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

Die Frage ist alt und die anderen Antworten sind korrekt, aber ihr Format ist nicht das einfachste. Ich benutze getc nur, um schnell die Dimensionen zu erhalten, während irrelevante Markierungen Überspringen (es unterstützt auch Progressive JPEGs):

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

Wenn ich etwas nicht vermisse, scheitern diese und alle anderen Antworten, die alle Bytes lesen, wenn das Segment ff c0 oder ff c2 nach einem anderen Segment kommt, in dem die Nutzlast zufällig ff c0/ff c2 enthält. –