Wie erhalte ich die Breite/Höhe einer JPEG-Datei, ohne die Bibliothek zu verwenden?
Lesezeit: 10 Minuten
Zunächst möchte ich sagen, dass ich viele Male versucht habe, die Antwort mithilfe der Google-Suche zu finden, und ich habe viele Ergebnisse gefunden, aber ich habe sie nicht verstanden, weil ich die Idee nicht kenne, eine Binärdatei zu lesen und den erhaltenen Wert zu konvertieren ablesbarer Wert.
Ich möchte eine einfache Erklärung mit Beispielshows, wie man die Breite/Höhe einer JPEG-Datei aus ihrem Header erhält und diesen Wert dann in einen lesbaren Wert umwandelt.
Haben Sie die Details darüber, was in den JPEG-Dateien enthalten ist? Wenn ja, geben Sie es bitte in Ihre Frage ein. Ich bezweifle, dass Ihre obige Methode funktionieren wird, da am Anfang normalerweise ein Header steht und dann die eigentlichen Pixelwerte beginnen. Wenn Sie nur die Höhen- und Breiteninformationen benötigen, können Sie diese meiner Meinung nach allein durch Lesen der Kopfzeile erhalten.
– schrm
16. August 2013 um 2:01 Uhr
@mishr: Ich rede von jpeg files Im Algemeinen.
– König der Löwen
16. August 2013 um 2:04 Uhr
Ich verstehe das, aber die Frage ist, wissen Sie, welches Format JPEG-Dateien haben? Oder möchten Sie, dass wir es für Sie finden?
– schrm
16. August 2013 um 2:06 Uhr
@mishr: Dies ist das erste Mal, dass ich mich mit Binärdateien wie JPEG befasse, und ich verstehe nichts davon.
– König der Löwen
16. August 2013 um 2:10 Uhr
Schau dir das an fastgraph.com/help/jpeg_header_format.html. Es besagt, dass der Header die Breiten- und Höheninformationen an den Offsets 2 bzw. 4 enthält. Alles, was Sie tun müssen, ist dieser Punkt fread zu diesen Offsets mit fseek und lese 2 Bytes von jeder Stelle. Dann müssen Sie diese Bytes in ganze Zahlen umwandeln. Versuche es.
– schrm
16. August 2013 um 2:16 Uhr
jxh
Leider scheint es für JPEG nicht einfach zu sein. Sie sollten sich die Quelle dazu ansehen jhead Kommandozeilen-Tool. Es liefert diese Informationen. Wenn Sie durch die Quelle gehen, 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 bei der Verarbeitung der Rahmen mit einem erhalten SOFn Marker.
Ich sehe, dass die Quelle gemeinfrei ist, also zeige ich das Snippet, das die Bildinformationen erhält:
Aus dem Quellcode ist mir klar, dass es keinen einzigen “Header” mit diesen Informationen gibt. Sie müssen die JPEG-Datei durchsuchen und jedes Segment parsen, bis Sie das Segment mit den gewünschten Informationen darin finden. Dies ist in der beschrieben Wikipedia-Artikel:
Ein JPEG-Bild besteht aus einer Folge von Segmenten, die jeweils mit einer Markierung beginnen, die jeweils mit einem 0xFF-Byte beginnen, gefolgt von einem Byte, das angibt, um welche Art von Markierung es sich handelt. Einige Marker bestehen nur aus diesen zwei Bytes; anderen folgen zwei Bytes, die die Länge der darauffolgenden markierungsspezifischen Nutzlastdaten angeben.
Eine JPEG-Datei besteht aus einer Folge von Segmenten:
SEGMENT_0
SEGMENT_1
SEGMENT_2
...
Jedes Segment beginnt mit einer 2-Byte-Markierung. 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 befinden sich Daten, die für diesen Segmenttyp spezifisch sind.
Die Bildbreite und -höhe wird in einem Textsegment gefunden SOFnoder “Beginn des Frames [n]”, wobei “n” eine Zahl ist, die für einen JPEG-Decoder etwas Besonderes bedeutet. Es sollte ausreichen, nur nach a zu suchen SOF0und seine Byte-Bezeichnung ist 0xC0. Sobald Sie diesen Rahmen gefunden haben, können Sie ihn decodieren, um die Bildhöhe und -breite zu ermitteln.
Die Struktur eines Programms, das das tut, was Sie wollen, würde also folgendermaßen aussehen:
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
@LionKing, lassen Sie mich wissen, wenn die Erklärung nicht klar ist oder wenn Sie zusätzliche Hilfe benötigen.
– jxh
16. August 2013 um 18:18 Uhr
Danke, aber ich verstehe es nicht, ich möchte einen sehr einfachen Weg und ein Beispiel, um es zu verstehen.
– König der Löwen
16. August 2013 um 23:21 Uhr
Ich würde mich sehr über einen Grund für die Ablehnung freuen. Vielen Dank!
– jxh
16. August 2013 um 23:56 Uhr
Es tut mir so leid, aber dies ist unbeabsichtigt (falsch) aufgetreten, verzeihen Sie mir.
– König der Löwen
17. August 2013 um 0:07 Uhr
@LionKing: Es gibt wirklich kein Problem. Nur zu Ihrer Information, Down-Votes sind völlig anonym, daher kann ich nicht wissen, wer mich down-voted hat. Ich wollte nur einen Grund, damit ich die Antwort verbessern kann.
– jxh
17. August 2013 um 4:12 Uhr
Benutzer3614789
dann müssen Sie die Höhen- und Breitenmarkierung von JPEG finden [ffc0].
Nachdem ffc0 im Binärformat gefunden wurde, sind die vier, fünf Bytes hoch und sechs und sieben Bytes breit.
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);
vlzvl
Die Frage ist alt und die anderen Antworten sind richtig, aber ihr Format ist nicht das einfachste. Ich benutze nur getc um schnell die Abmessungen zu erhalten, während irrelevante Markierungen übersprungen werden (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;
}
}
Sofern mir nichts fehlt, schlagen diese und alle anderen Antworten, die alle Bytes lesen, fehl, 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.
– David S
29. November 2017 um 3:31 Uhr
@ Dave S hat noch nie von Byte Stuffing gehört?
– Lukas
7. August 2018 um 23:23 Uhr
@Luca Als ich den Wiki-Eintrag in der Spezifikation überflogen habe, habe ich gelesen, dass Segmente nur Byte-Füllung für entropiecodierte Daten durchgeführt haben, sodass ff co / ff c2 in anderen Nutzlasten auftreten könnte.
– David S
8. August 2018 um 18:40 Uhr
@DaveS Kennen Sie einen anderen zuverlässigeren Weg, um diese Informationen herauszufinden?
– HRK44
13. Dezember 2018 um 9:52 Uhr
@ HRK44, nur um minimal zu parsen, die Datensatzgrößen zu lesen und an ihnen vorbei zu springen, bis Sie den ff c0-Datensatz sehen.
– David S
13. Dezember 2018 um 21:35 Uhr
Apostel
Bildabmessungen in JPEG-Dateien finden Sie wie folgt:
1) Suchen Sie nach FF C0
2) An den Offsets +4 und +6 nach dieser Position sind jeweils Höhe und Breite (Wörter).
In den meisten Fällen sind die absoluten Versätze von Höhe und Breite A3 bzw. A5.
Hier ist ein einfacher Code, den ich geschrieben habe und der zuverlässig zu funktionieren scheint.
#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];
}
Danke, ist das vorherige Beispiel mit C/C++?, was ist Seek, Read Funktionen ? und Was ist der Vorteil dieser Funktion MOTOSHORT ?, auch was ist iHandle variabel?.
– König der Löwen
17. August 2013 um 17:17 Uhr
Die Such- und Lesefunktionen sind generische Datei-E/A, die in allen Systemen vorhanden sein sollten. MOTOSHORT ist ein Makro (siehe Anfang des Codes), das zum Lesen von Big-Endian-Shorts auf jedem System geeignet ist, unabhängig von der Endianität. Die ihandle-Variable ist das Datei-Handle, von dem angenommen wird, dass es geöffnet wird, bevor die Funktion aufgerufen wird.
– BitBank
18. August 2013 um 5:45 Uhr
Codefreak
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;
}
Danke, ist das vorherige Beispiel mit C/C++?, was ist Seek, Read Funktionen ? und Was ist der Vorteil dieser Funktion MOTOSHORT ?, auch was ist iHandle variabel?.
– König der Löwen
17. August 2013 um 17:17 Uhr
Die Such- und Lesefunktionen sind generische Datei-E/A, die in allen Systemen vorhanden sein sollten. MOTOSHORT ist ein Makro (siehe Anfang des Codes), das zum Lesen von Big-Endian-Shorts auf jedem System geeignet ist, unabhängig von der Endianität. Die ihandle-Variable ist das Datei-Handle, von dem angenommen wird, dass es geöffnet wird, bevor die Funktion aufgerufen wird.
– BitBank
18. August 2013 um 5:45 Uhr
Guilherme Campos Hazan
Hier ist ein Code, den ich in Java geschrieben habe. 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, die Längen jedes Blocks zu überspringen, weil es nicht funktioniert. Wenn jemand den Code dafür verbessern könnte, 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};
}
14328400cookie-checkWie erhalte ich die Breite/Höhe einer JPEG-Datei, ohne die Bibliothek zu verwenden?yes
Haben Sie die Details darüber, was in den JPEG-Dateien enthalten ist? Wenn ja, geben Sie es bitte in Ihre Frage ein. Ich bezweifle, dass Ihre obige Methode funktionieren wird, da am Anfang normalerweise ein Header steht und dann die eigentlichen Pixelwerte beginnen. Wenn Sie nur die Höhen- und Breiteninformationen benötigen, können Sie diese meiner Meinung nach allein durch Lesen der Kopfzeile erhalten.
– schrm
16. August 2013 um 2:01 Uhr
@mishr: Ich rede von
jpeg files
Im Algemeinen.– König der Löwen
16. August 2013 um 2:04 Uhr
Ich verstehe das, aber die Frage ist, wissen Sie, welches Format JPEG-Dateien haben? Oder möchten Sie, dass wir es für Sie finden?
– schrm
16. August 2013 um 2:06 Uhr
@mishr: Dies ist das erste Mal, dass ich mich mit Binärdateien wie JPEG befasse, und ich verstehe nichts davon.
– König der Löwen
16. August 2013 um 2:10 Uhr
Schau dir das an fastgraph.com/help/jpeg_header_format.html. Es besagt, dass der Header die Breiten- und Höheninformationen an den Offsets 2 bzw. 4 enthält. Alles, was Sie tun müssen, ist dieser Punkt
fread
zu diesen Offsets mitfseek
und lese 2 Bytes von jeder Stelle. Dann müssen Sie diese Bytes in ganze Zahlen umwandeln. Versuche es.– schrm
16. August 2013 um 2:16 Uhr