Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Gráficos (https://www.clubdelphi.com/foros/forumdisplay.php?f=8)
-   -   Obtener info de un fichero JPG (https://www.clubdelphi.com/foros/showthread.php?t=87926)

jesusgandia1966 19-03-2015 19:49:13

Obtener info de un fichero JPG
 
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:

Código PHP:

    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, 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

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

Ok
 
1 Archivos Adjunto(s)
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

Cita:

Empezado por Casimiro Notevi (Mensaje 490249)
Haz una búsqueda por EXIF.





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

ecfisa 20-03-2015 22:16:46

Hola jesusgandia1966
Cita:

Empezado por jesusgandia1966 (Mensaje 490242)
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,
Código Delphi [-]
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

Cita:

Empezado por ecfisa (Mensaje 490258)
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:

Código:


            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

Código:

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


ecfisa 28-03-2015 19:14:11

Hola Jesus.

Código PHP:

bool getJpegsize(TMemoryStream *jpegint &widthint &heightint &bitDepth) {
  
int n;
  
unsigned char b;
  
unsigned int w;
  
bool result false;

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


Ejemplo de uso:
Código PHP:

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

    
ms->LoadFromFile(OpenDialog1->FileName);
    
getJpegsize(mswhd);
    
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.
Cita:

Empezado por jesusgandia1966 (Mensaje 490618)
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:
Código PHP:

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:
Código PHP:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  if (
OpenDialog1->Execute())
    switch (
getColorbit(OpenDialog1->FileName.c_str())) {
      case 
pfDeviceShowMessage("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 
pfCustomShowMessage("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:
Código:


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.


La franja horaria es GMT +2. Ahora son las 11:14:12.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi