PDA

Ver la Versión Completa : Obtener info de un fichero JPG


jesusgandia1966
19-03-2015, 19:49:13
Como puedo obtener información de un fichero de imagen JPG.

El problema es que a veces un usuario intenta cargarme una imagen JPG de 32 bits de profundidad de colores y el TImage de Builder no lo acepta con el consecuente error y salida del programa.

También he intentado proteger el código que abre el cuadro de dialogo de las imágenes para controlar el error y responder con un mensaje al usuario, pero da la casualidad que se comete el error y el programa sigue sin ir al Catch(...) del try{}.

He buscado por todo el foro y en Google, pero sigo sin saber como obtengo esa información.

De ya muchas gracias.

Aunque el mi código está en C++, si alguien me puede ayudar en Delphi, yo ya pasaría la función a C++.

Código:


String Fichero = fV->SV->DatSetPCRutaTPV_Ncr + "Imagenes\\Logo.jpg";
if(!ForceCurrentDirectory)
{
ForceCurrentDirectory = true;
SetCurrentDir(fV->SV->DatSetPCRutaTPV_Ncr + "Galeria\\Logos");
OPDLogo->InitialDir = GetCurrentDir();
}
else
{
SetCurrentDir(ExtractFilePath(OPDLogo->FileName));
OPDLogo->InitialDir = GetCurrentDir();
}

try
{
if(OPDLogo->Execute())
{
if(ComparaExtension(OPDLogo->FileName,".jpg"))
{
ImagenLogo->Picture->LoadFromFile(OPDLogo->FileName);//Protegiendo esta linea conta posibles fallos de IMAGEN
if(ImagenLogo->Picture->Width <300>Picture->Height <150>IBSQLExec->ParamByName("P_NOMIMAGEN")->AsString = "Logo";
MDatos->IBSQLExec->ParamByName("P_FOTO")->LoadFromFile(OPDLogo->FileName);
MDatos->IBSQLExec->ExecQuery();
MDatos->IBSQLExec->Close();
MDatos->IBTransaction->CommitRetaining();

ImagenLogo->Picture->LoadFromFile(OPDLogo->FileName);
ImagenLogoTicket->Picture->LoadFromFile(OPDLogo->FileName);
ImagenLogo->Picture->SaveToFile(Fichero.w_str());
}
else
{
fV->MenDialogo(
"La imagen es demasiado grande\n"
"Máximo alto permitido = 150 Pixels\n"
"Maximo ancho permitido = 300 Pixels",'!');

if(FileExists(Fichero.w_str()))
{
ImagenLogo->Picture->LoadFromFile(Fichero.w_str());
ImagenLogoTicket->Picture->LoadFromFile(Fichero.w_str());
}
else
{
ImagenLogo->Picture = NULL;
ImagenLogoTicket->Picture = NULL;
}
}
}
else
fV->MenDialogo(
"Solo puede seleccionar archivos de imagen (*.JPG).\n"
"El archivo para el logo, no se cargará.");
}
else
fV->MenDialogo(
"Se ha cancelado la imagen.\n"
"El logo no se cambiará.");
}
catch(...)
{
fV->MenDialogo(
"La imagen que ha seleccionado, tiene una profundidad de color de más de 24 bits, o no es una fichero de imagen correcto.\n\n"
"Se cancela la operacion de cargar LogoTipo.",'!');
}

nlsgarcia
19-03-2015, 20:33:30
jesusgandia1966,

¡Bienvenido al Club Delphi! :D

Te sugiero revisar la Guía de estilo de los foros (http://www.clubdelphi.com/foros/guiaestilo.php), recomendada a todos los nuevos ingresos al Club Delphi.

¡Gracias por tu cooperación! :) ^\||/

Saludos,

Nelson.

ecfisa
19-03-2015, 22:39:21
Hola jesusgandia1966.

Revisa este enlace: Getting JPEG resolution without decoding the image (http://stackoverflow.com/questions/4001719/getting-jpeg-resolution-without-decoding-the-image)

Saludos :)

jesusgandia1966
20-03-2015, 19:39:05
El enlace que sugieres, muestra información sobre la cabecera de fichero JPG, pero no me dice si el fichero está guardado con 8, 16, 24 o 32 bits de profundidad de color.

Ya miré en todo el foro y no encontré respuesta.

jesusgandia1966
20-03-2015, 19:51:51
Esto Es Lo Que Quiero Obtener:

Casimiro Notevi
20-03-2015, 21:31:17
Haz una búsqueda por EXIF.
De todas formas, dices que el problema es que no puedes mostrar imágenes de 32 bits en un TImage, ¿es eso?

jesusgandia1966
20-03-2015, 21:50:19
NO, NO ES ESO. Abrir un JPG de 32 bits de color en un TImage no es lo que quiero.

El problema es que antes de abrir o cargar el fichero, quiero detectar si es de 32 bits o de 24 bits.

Casimiro Notevi
20-03-2015, 21:53:36
Haz una búsqueda por EXIF.




..............

ecfisa
20-03-2015, 22:16:46
Hola jesusgandia1966
El enlace que sugieres, muestra información sobre la cabecera de fichero JPG, pero no me dice si el fichero está guardado con 8, 16, 24 o 32 bits de profundidad de color.

Ya miré en todo el foro y no encontré respuesta.
Pues no has mirado lo suficientemente bién.

La función que presentan en el segundo mensaje,

function GetJpegSize(jpeg: TMemoryStream; out width, height, BitDepth: integer): boolean;

devuelve la profundidad del color en el parámetro BitDepth.

Saludos :)

Casimiro Notevi
20-03-2015, 22:21:53
La función que presentan en el segundo mensaje devuelve la profundidad del color en el parámetro BitDepth.
^\||/^\||/^\||/

jesusgandia1966
21-03-2015, 12:51:01
Gracias tienes toda la razón no vi el segundo mensaje.
Di por hecho que solo mostraba la cabecera del JPG y me salte ver la función.

jesusgandia1966
28-03-2015, 12:49:10
Esta función no obtiene la información de si la imagen es de 32, 24, 16 o 8 bits.
El valor obtenido no corresponde con lo mencionado en el post.
Pueden comprobarlo ustedes mismos.
Deje en un post mas arriba lo que quiero y lo que quiero es consultar un fichero JPG directamente en el archivo y comprobar si es de 32 bits, 24, 16 o 8 bits.
Tal como cuando hace Windows con las propiedades del fichero, que si es de IMAGEN muestra dichos valores de forma muy directa.

Casimiro Notevi
28-03-2015, 12:53:49
¿Puedes poner tu código?

jesusgandia1966
28-03-2015, 13:08:13
Supuestamente el valor Read, obtiene el valor de los Bits de color.
Esto está cogido basándose en el código sugerido mas arriba puesto por otros foreros.
El código está en Delphi, pero en C++ es muy parecido.
Este código no funciona:



String Fichero = fV->SV->DatSetPCRutaTPV_Ncr + "Imagenes\\Logo.jpg";
TJPEGImage* Imagen_JPG = new TJPEGImage();
TMemoryStream *StreamTmp = new TMemoryStream;

Imagen_JPG->LoadFromFile(Fichero.w_str());
Imagen_JPG->SaveToStream(StreamTmp);

wchar_t buffer[1024];
StreamTmp->Read(buffer, 0);
INT COLOR = buffer[0] * 8;

ShowMessage(COLOR);

Casimiro Notevi
28-03-2015, 13:26:35
¿Y en qué parte de ese código se leen los datos de la imagen?

jesusgandia1966
28-03-2015, 17:36:09
wchar_t buffer[1024];
StreamTmp->Read(buffer, 0);
INT COLOR = buffer[0] * 8;

ecfisa
28-03-2015, 19:14:11
Hola Jesus.


bool getJpegsize(TMemoryStream *jpeg, int &width, int &height, int &bitDepth) {
int n;
unsigned char b;
unsigned int w;
bool result = false;

n = jpeg->Size;
jpeg->Position = 0;
if (n <= 0) return false;
jpeg->Read(&w, 2);
if ( w < 0xD8FF ) return false;
jpeg->Read(&b, 1);
while (jpeg->Position < n && b==0xFF) {
jpeg->Read(&b, 1);
switch(b) {
case 0xC0: case 0xC1: case 0xC2: case 0xC3: {
jpeg->Seek(3, soFromCurrent);
jpeg->Read(&w, 2);
height = (w&0xFF)<<8|(w&0xFF00)>>8;
jpeg->Read(&w, 2);
width = (w&0xFF)<<8|(w&0xFF00)>>8;
jpeg->Read(&b, 1);
bitDepth = b * 8;
return true;
}; break;
case 0xFF: jpeg->Read(&b, 1); break;
case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4:
case 0xD5: case 0xD6: case 0xD7: case 0xD8: case 0xD9: {
jpeg->Seek(1, soFromCurrent);
jpeg->Read(&b, 1);
};
default: {
jpeg->Read(&w, 2);
jpeg->Seek(((w&0xFF)<<8|(w&0xFF00)>>8)-2, soFromCurrent);
jpeg->Read(&b,1);
}; break;
}
}
}


Ejemplo de uso:

void __fastcall TForm1::Button1Click(TObject *Sender){
if (OpenDialog1->Execute()) {
TMemoryStream *ms = new TMemoryStream;
int w,h,d;

ms->LoadFromFile(OpenDialog1->FileName);
getJpegsize(ms, w, h, d);
delete ms;
ShowMessage("Width: "+IntToStr(w)+
"\nHeight: "+IntToStr(h)+
"\nDepth: "+IntToStr(d));
}
}


Saludos :)

jesusgandia1966
28-03-2015, 19:16:05
Muchas gracias por tu aporte, lo probaré y te digo.

ecfisa
28-03-2015, 20:39:37
Hola Jesus.
Esta función no obtiene la información de si la imagen es de 32, 24, 16 o 8 bits.
El valor obtenido no corresponde con lo mencionado en el post.
Pueden comprobarlo ustedes mismos.
Deje en un post mas arriba lo que quiero y lo que quiero es consultar un fichero JPG directamente en el archivo y comprobar si es de 32 bits, 24, 16 o 8 bits.
Tal como cuando hace Windows con las propiedades del fichero, que si es de IMAGEN muestra dichos valores de forma muy directa.
No había leido este mensaje. :o

Te comento que en mis pruebas, la información que muestra la función traducida, se corresponde con la obtenida en el explorador de windows en las propiedades del archivo.

De todos modos se me ocurrió que también podrías probar de este modo:

TPixelFormat getColorbit(const char* &fileName) {
TPixelFormat pf;

Graphics::TBitmap *bmp = new Graphics::TBitmap;
TJPEGImage *jpg = new TJPEGImage;
jpg->LoadFromFile(fileName);
bmp->Assign(jpg);
pf = bmp->PixelFormat;
delete jpg;
delete bmp;

return pf;
}


Ej. de llamada:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
if (OpenDialog1->Execute())
switch (getColorbit(OpenDialog1->FileName.c_str())) {
case pfDevice: ShowMessage("Device-dependant bitmap");break;
case pf1bit : ShowMessage("One bit per pixel");break;
case pf4bit : ShowMessage("Uses a 16-color palette");break;
case pf8bit : ShowMessage("Uses a 256color palette"); break;
case pf15bit : ShowMessage("uses 15 bits per pixel (RGB compression)"); break;
case pf16bit : ShowMessage("uses 16 bits per pixel (bitfield compression)"); break;
case pf24bit : ShowMessage("uses 24 bits per pixel"); break;
case pf32bit : ShowMessage("uses 32 bits per pixel (RGB compression)"); break;
case pfCustom: ShowMessage("TBitmap does not support pfCustom"); break;
}
}


Saludos :)

jesusgandia1966
29-03-2015, 03:32:38
El problema es que con este código cuando la imagen JPG es de 32 bits de color sucede un error al asignárselo al TBitmap en la siguiente LINEA:


bmp->Assign(jpg);//Salta una excepción si la IMANGEN DEL jpg es de 32 bits de color



Sin embargo la solución de "ecfisa" funciona perfectamente en todos los casos.
MUCHISIMAS GRACIAS A TODOS, habéis aportado mucho a mi problema en la resolución.
GRACIAS, GRACIAS y GRACIAS.