¿Cómo obtener el ancho/alto del archivo jpeg sin usar la biblioteca?
⏰ 11 minutos de lectura
En primer lugar, quiero decir que intenté muchas veces encontrar la respuesta usando la búsqueda de Google, y encontré muchos resultados, pero no entendí, porque no conozco la idea de leer un archivo binario y convertir el valor obtenido en valor legible.
Quiero una explicación simple con ejemplos, cómo obtener el ancho/alto del archivo jpeg desde su encabezado y luego convertir ese valor en un valor legible.
¿Tiene los detalles de lo que está contenido en los archivos jpeg? Si es así, inclúyalo en su pregunta. Dudo que su método anterior funcione, ya que generalmente hay un encabezado al principio y luego comienzan los valores de píxeles reales. Si solo necesita la información de alto y ancho, creo que puede obtenerla leyendo solo el encabezado.
– Shrm
16 de agosto de 2013 a las 2:01
@mishr: estoy hablando de jpeg files en general.
– Rey Leon
16 de agosto de 2013 a las 2:04
Lo entiendo, pero la pregunta es ¿sabes cuál es el formato de los archivos jpeg? ¿O quieres que te lo encontremos?
– Shrm
16 de agosto de 2013 a las 2:06
@mishr: Esta es la primera vez que trato con archivos binarios, como jpeg, y no entiendo nada al respecto.
– Rey Leon
16 de agosto de 2013 a las 2:10
Mira esto fastgraph.com/help/jpeg_header_format.html. Dice que el encabezado contiene la información de ancho y alto en los desplazamientos 2 y 4 respectivamente. Todo lo que necesita hacer es ese punto fread a estas compensaciones usando fseek y leer 2 bytes de cada ubicación. Luego, debe convertir estos bytes en números enteros. Darle una oportunidad.
– Shrm
16 de agosto de 2013 a las 2:16
jxh
Desafortunadamente, no parece ser simple para JPEG. Deberías mirar la fuente de la jhead herramienta de línea de comandos. Proporciona esta información. Al pasar por la fuente, verás la función ReadJpegSections. Esta función explora todos los segmentos contenidos en el archivo JPEG para extraer la información deseada. El ancho y alto de la imagen se obtiene al procesar los marcos que tienen un SOFn marcador.
Veo que la fuente es de dominio público, así que mostraré el fragmento que obtiene la información de la imagen:
Desde el código fuente, me queda claro que no hay un solo “encabezado” con esta información. Tiene que escanear el archivo JPEG, analizando cada segmento, hasta que encuentre el segmento con la información que desea. Esto se describe en el articulo de wikipedia:
Una imagen JPEG consta de una secuencia de segmentos, cada uno de los cuales comienza con un marcador, cada uno de los cuales comienza con un byte 0xFF seguido de un byte que indica qué tipo de marcador es. Algunos marcadores consisten solo en esos dos bytes; otros van seguidos de dos bytes que indican la longitud de los datos de carga útil específicos del marcador que siguen.
Un archivo JPEG consta de una secuencia de segmentos:
SEGMENT_0
SEGMENT_1
SEGMENT_2
...
Cada segmento comienza con un marcador de 2 bytes. El primer byte es 0xFF, el segundo byte determina el tipo del segmento. A esto le sigue una codificación de la longitud del segmento. Dentro del segmento hay datos específicos de ese tipo de segmento.
El ancho y la altura de la imagen se encuentran en un segmento de tipo SOFno “Inicio del cuadro [n]”, donde “n” es un número que significa algo especial para un decodificador JPEG. Debería ser lo suficientemente bueno para buscar solo un SOF0y su designación de byte es 0xC0. Una vez que encuentre este marco, puede decodificarlo para encontrar la altura y el ancho de la imagen.
Entonces, la estructura de un programa para hacer lo que quieres se vería así:
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, avíseme si la explicación no es clara o si necesita ayuda adicional.
– jxh
16 de agosto de 2013 a las 18:18
Gracias, pero no lo entiendo, quiero una forma y un ejemplo muy simple para poder entenderlo.
– Rey Leon
16 de agosto de 2013 a las 23:21
Apreciaría mucho una razón para el voto negativo. ¡Gracias!
– jxh
16 de agosto de 2013 a las 23:56
Lo siento mucho, pero esto ocurrió sin querer (incorrectamente), perdóname.
– Rey Leon
17 de agosto de 2013 a las 0:07
@LionKing: Realmente no hay problema. Solo para su información, los votos negativos son totalmente anónimos, por lo que no hay forma de que yo sepa quién me votó negativo. Solo quería una razón para poder mejorar la respuesta.
– jxh
17 de agosto de 2013 a las 4:12
usuario3614789
entonces tienes que encontrar el marcador de altura y ancho de jpeg que es [ffc0].
después de encontrar ffc0 en formato binario, los cuatro, cinco bytes son altos y seis y siete bytes son anchos.
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
la pregunta es antigua y las otras respuestas son correctas pero su formato no es el más fácil. solo uso getc para obtener rápidamente las dimensiones, mientras se saltan los marcadores irrelevantes (también admite JPEG progresivos):
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;
}
}
A menos que me esté perdiendo algo, esta y todas las demás respuestas que leen todos los bytes fallarán si el segmento ff c0 o ff c2 viene después de algún otro segmento donde la carga útil contiene ff c0 / ff c2.
– David S.
29 de noviembre de 2017 a las 3:31
@Dave S nunca escuchó sobre el relleno de bytes?
– Lucas
7 de agosto de 2018 a las 23:23
@Luca Cuando hojeé la entrada de wiki en la especificación, leí que decía que los segmentos solo rellenaban bytes para datos codificados en entropía, por lo que ff co / ff c2 podría ocurrir en otras cargas útiles.
– David S.
08/08/2018 a las 18:40
@DaveS ¿Conoce alguna otra forma más confiable de averiguar esta información?
– HRK44
13 de diciembre de 2018 a las 9:52
@HRK44 solo para hacer un análisis mínimo, leer los tamaños de registro y saltarlos hasta que vea el registro ff c0.
– David S.
13 dic 2018 a las 21:35
Apóstoles
Las dimensiones de la imagen en los archivos JPEG se pueden encontrar de la siguiente manera:
1) buscar FF C0
2) En las compensaciones +4 y +6 después de esta ubicación están el alto y el ancho (palabras), respectivamente.
En la mayoría de los casos, los desplazamientos absolutos de alto y ancho son A3 y A5, respectivamente.
Aquí hay un código simple que escribí que parece funcionar de manera confiable.
#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];
}
Gracias, es el ejemplo anterior usando C/C++?, que es Seek, Read ¿Funciones?, y ¿Cuál es el beneficio de esta función? MOTOSHORT ?, también que es iHandle variable ?.
– Rey Leon
17 de agosto de 2013 a las 17:17
Las funciones de búsqueda y lectura son E/S de archivos genéricos que deberían existir en todos los sistemas. El MOTOSHORT es una macro (vea la parte superior del código) que es conveniente para leer cortos Big Endian en cualquier sistema, independientemente de su endianess. La variable ihandle es el identificador de archivo que se supone que se abre antes de llamar a la función.
– BitBank
18 de agosto de 2013 a las 5:45
códigogeek
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;
}
Gracias, es el ejemplo anterior usando C/C++?, que es Seek, Read ¿Funciones?, y ¿Cuál es el beneficio de esta función? MOTOSHORT ?, también que es iHandle variable ?.
– Rey Leon
17 de agosto de 2013 a las 17:17
Las funciones de búsqueda y lectura son E/S de archivos genéricos que deberían existir en todos los sistemas. El MOTOSHORT es una macro (vea la parte superior del código) que es conveniente para leer cortos Big Endian en cualquier sistema, independientemente de su endianess. La variable ihandle es el identificador de archivo que se supone que se abre antes de llamar a la función.
– BitBank
18 de agosto de 2013 a las 5:45
Guilherme Campos Hazán
Aquí hay un código que escribí en Java. Funciona bien para jpegs tomados de una cámara. Escanea todo el código para encontrar el tamaño de imagen más grande. No pude mejorarlo para saltar las longitudes de cada bloque porque no funciona. Si alguien puede mejorar el código para hacer eso, sería genial.
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};
}
¿Ha sido útil esta solución?
Tu feedback nos ayuda a saber si la solución es correcta y está funcionando. De esta manera podemos revisar y corregir el contenido.
Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos.
Configurar y más información
¿Tiene los detalles de lo que está contenido en los archivos jpeg? Si es así, inclúyalo en su pregunta. Dudo que su método anterior funcione, ya que generalmente hay un encabezado al principio y luego comienzan los valores de píxeles reales. Si solo necesita la información de alto y ancho, creo que puede obtenerla leyendo solo el encabezado.
– Shrm
16 de agosto de 2013 a las 2:01
@mishr: estoy hablando de
jpeg files
en general.– Rey Leon
16 de agosto de 2013 a las 2:04
Lo entiendo, pero la pregunta es ¿sabes cuál es el formato de los archivos jpeg? ¿O quieres que te lo encontremos?
– Shrm
16 de agosto de 2013 a las 2:06
@mishr: Esta es la primera vez que trato con archivos binarios, como jpeg, y no entiendo nada al respecto.
– Rey Leon
16 de agosto de 2013 a las 2:10
Mira esto fastgraph.com/help/jpeg_header_format.html. Dice que el encabezado contiene la información de ancho y alto en los desplazamientos 2 y 4 respectivamente. Todo lo que necesita hacer es ese punto
fread
a estas compensaciones usandofseek
y leer 2 bytes de cada ubicación. Luego, debe convertir estos bytes en números enteros. Darle una oportunidad.– Shrm
16 de agosto de 2013 a las 2:16