Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   ¿Qué tipo de imagen es? (https://www.clubdelphi.com/foros/showthread.php?t=92090)

Angel.Matilla 21-07-2017 20:35:15

¿Qué tipo de imagen es?
 
Tengo una aplicación en BCB 6 con una base de datos en Firebird y en una de las tablas hay guardadas imágenes en un campo BLOB. A la hora de leer esa tabla y mostrar el contenido, ya sea en el formulario o en un impreso, ¿cómo puedo saber que tipo de imagen estoy leyendo? Porque dependiendo de si es un BMP o un JPG el tratamiento es diferente.

A ver: Si la imagen original es un JPG con este código
Código:

Imagen->Picture->Assign(Query->FieldByName("Imagen"));
me funicona bien, pero si es un BMP me da un error Bitmap image is not valid.

ecfisa 21-07-2017 23:02:01

Hola.

Si vas a almacenar distintos tipos de imágenes en tu tabla, lo mas simple es agregar un campo (SMALLINT por ej.) que indique de que tipo de imágen se trata, revisa este hilo.

Saludos :)

AgustinOrtu 21-07-2017 23:25:24

Podrias leer las cabeceras y detectar el tipo de imagen. En este blog esta explicado e implementado: https://delphihaven.wordpress.com/20...aphic-formats/

Angel.Matilla 24-07-2017 11:16:09

Gracias por vuestras respuestas. Me han dado la solución en otro foro.
Código:

//Añadir cabeceras:  #include <memory>  #include <jpeg.hpp>
std::auto_ptr<TMemoryStream> stream(new TMemoryStream);
TBlobField* blob = static_cast<TBlobField*>(Query->FieldByName("Imagen"));
blob->SaveToStream(stream.get());
stream->Position = 0;
DWORD* tipo = static_cast<DWORD*>(stream->Memory);
if (tipo && *tipo == 0xE0FFD8FF)
{
    std::auto_ptr<TJPEGImage> jpeg(new TJPEGImage);
    jpeg->LoadFromStream(stream.get());
    Imagen->Picture->Assign(jpeg.get());
}
else
    Imagen->Picture->Assign(blob);


ecfisa 24-07-2017 20:43:17

Hola.

Si, pero vale aclarar que ese código sólo funciona para los tipos BMP y JPG, no funcionará si desearas usar imágenes de tipo PNG, ICO, GIF, etc.

Para que soporte sólo esos dos tipos de imágen también se podría escribir así:
Código PHP:

...
{
  
TStream *Stream = new TMemoryStream;
  try {
    
static_cast<TBlobField*>(Query->FieldByName("IMAGE"))->SaveToStream(Stream);
    
Stream->Seek(0soFromBeginning);
    
Image1->Picture->Bitmap->LoadFromStream(Stream);
  }
  
__finally {
    
delete Stream;
  }


Saludos :)

_Leo 24-07-2017 22:33:52

Cita:

Empezado por ecfisa (Mensaje 519640)
Para que soporte sólo esos dos tipos de imágen también se podría escribir así:

Hola ecfisa, ¿lo has probado? no funciona, seguiría dando el mismo error que mencionaba Ángel en cuanto uses una imagen que no sea BMP. Pero siguiendo tu ejemplo, en las versiones más actuales (creo que Ángel utiliza BCB6) se podría hacer algo similar para cargar BMP, JPG, PNG, GIF, TIF, etc...

Código PHP:

std::unique_ptr<TWICImagewic(new TWICImage);
wic->Assign(Query->FieldByName("Imagen"));
Image1->Picture->Bitmap->Assign(wic.get()); 


ecfisa 24-07-2017 23:16:58

Hola _Leo.

Si, en Builder C++ 6 funciona sin problemas.

Una prueba sobre una tabla con imágenes JPG y BMP mezcladas:
Código PHP:

void __fastcall TForm1::DataSource1DataChange(TObject *Sender,
      
TField *Field)
{
  
TStream *Stream = new TMemoryStream;
  try {
    
static_cast<TBlobField*>(IBQuery1->FieldByName("IMAGE"))->SaveToStream(Stream);
    
Stream->Seek(0soFromBeginning);
    
Image1->Picture->Bitmap->LoadFromStream(Stream);
  }
  
__finally {
    
delete Stream;
  }


Salida:


Saludos :)

_Leo 24-07-2017 23:59:21

Cita:

Empezado por ecfisa (Mensaje 519652)
Si, en Builder C++ 6 funciona sin problemas.

¿Estás seguro de que los campos blob contienen realmente un archivo .jpg y no un .bmp convertido desde un .jpg pegado en un TDBImage?

Algo debo tener mal, porque lo he probado con ADO+Access, BDE+Paradox e IBX+Firebird, y si no es un BMP da el error que menciona Ángel. Son las mismas tablas donde he probado el resto de ejemplos sin problema.


Si no es mucho pedir, si tienes tu ejemplo a mano, ¿podrías añadir estas líneas justo antes del LoadFromStream para ver cada tipo según se cargan en el título de la ventana? (BMP=4D42, JPG=D8FF, PNG=5089, GIF=4947, TIF=4949)
Código PHP:

WORD tipo;
memcpy(&tipostatic_cast<TMemoryStream*>(Stream)->Memorysizeof(tipo));
Caption IntToHex(tipo4); 


ecfisa 25-07-2017 02:20:17

Hola _Leo
Cita:

Empezado por _Leo (Mensaje 519655)
¿Estás seguro de que los campos blob contienen realmente un archivo .jpg y no un .bmp convertido desde un .jpg pegado en un TDBImage?

Tenes razón ^\||/, las pruebas las hice sobre una tabla en que así se habían guardado las imágenes, de allí que no obtenía error.

Saludos :)

Angel.Matilla 25-07-2017 11:37:26

Cita:

Empezado por _Leo (Mensaje 519649)
Pero siguiendo tu ejemplo, en las versiones más actuales (creo que Ángel utiliza BCB6) se podría hacer algo similar para cargar BMP, JPG, PNG, GIF, TIF, etc...

¿Valdría en BCB 6? Si sigo usando BCB 6 es porque con XE3, que es el más moderno que tengo, no consigo aclararme en muchas cosas.

_Leo 25-07-2017 16:16:46

Cita:

Empezado por Angel.Matilla (Mensaje 519665)
¿Valdría en BCB 6? Si sigo usando BCB 6 es porque con XE3, que es el más moderno que tengo, no consigo aclararme en muchas cosas.

No, ese ejemplo con "TWICImage" no te serviría en el BCB6, pero si en el XE3.

En las versiones actuales el cambio que mas dificulta las cosas con respecto al BCB6 es el Unicode que al principio es lo que más despista, pero una vez lo entiendes bien no es un gran problema, aunque si cuesta un poco más cuando trabajas con un proyecto viejo que cuando empiezas uno nuevo directamente con Unicode.

Angel.Matilla 25-07-2017 18:20:50

Cita:

Empezado por _Leo (Mensaje 519684)
En las versiones actuales el cambio que mas dificulta las cosas con respecto al BCB6 es el Unicode que al principio es lo que más despista, pero una vez lo entiendes bien no es un gran problema, aunque si cuesta un poco más cuando trabajas con un proyecto viejo que cuando empiezas uno nuevo directamente con Unicode.

Eso es lo que me pasa, que con el Unicode me pierdo y como puedo dedicarme en exclusiva a aprender... ¡Seguriemos esforzándonos! Gracias Leo.

cloayza 25-07-2017 19:50:13

En algún momento tuve la necesidad de almacenar distintos formatos de imagenes en una base de datos, y no quice guardar extensión ni tipo de archivo almacenado.

Y encontré un componente (TimDBImage, http://www.marteens.com/ejemplos.htm) que después de estudiar su funcionamiento adapte a mis necesidades y lo deje en el ftp del club.

Esta es la dirección
Componente
CLDBImagen.zip

Ejemplo:
CLDBImagen_Sample.zip

Hasta ahora lo sigo utilizando con muy buenos resultados.

Es para Delphi, pero creo que te puede dar luces de como realizar lo que necesitas en C++Builder.

Saludos cordiales

ecfisa 25-07-2017 22:26:43

Hola.

Primero que nada me disculpo con _Leo por las pruebas que tuvo que realizar por mi desacierto.
Y para no dejar el caso inconcluso, este código muestra en un componente TImage los tipos de imagenes soportados y cuya firma sea evaluada y creada en consecuencia.
Código PHP:

void __fastcall TForm1::DataSource1DataChange(TObject *Sender,
      
TField *Field)
{
  
unsigned short us;
  
TBlobField *blob static_cast<TBlobField*>(IBDataSet1->FieldByName("IMAGE"));

  
CopyMemory(&us, &blob->Value[1], sizeof(us));
  
AnsiString st IntToHex(us4);

  
TGraphic *gr;
  try {
    if (
st == "4D42"gr = new Graphics::TBitmap;
    else if (
st == "D8FF"gr = new TJPEGImage;
    else if (
st == "0000"gr = new TIcon;
    else if (
st == "5089"gr = new TPNGObject;
    
// etc, etc, ...
    
gr->Assign(blob);
    
Image1->Picture NULL;
    
Image1->Picture->Bitmap->Height  gr->Height;
    
Image1->Picture->Bitmap->Width   gr->Width;
    
Image1->Picture->Bitmap->Canvas->Draw(00gr);
  } 
__finally {
    
delete gr;
  }


Saludos :)

Angel.Matilla 26-07-2017 11:33:22

Cita:

Empezado por ecfisa (Mensaje 519696)
Y para no dejar el caso inconcluso, este código muestra en un componente TImage los tipos de imagenes soportados y cuya firma sea evaluada y creada en consecuencia.
Código PHP:

void __fastcall TForm1::DataSource1DataChange(TObject *Sender,
      
TField *Field)
{
  
unsigned short us;
  
TBlobField *blob static_cast<TBlobField*>(IBDataSet1->FieldByName("IMAGE"));

  
CopyMemory(&us, &blob->Value[1], sizeof(us));
  
AnsiString st IntToHex(us4);

  
TGraphic *gr;
  try {
    if (
st == "4D42"gr = new Graphics::TBitmap;
    else if (
st == "D8FF"gr = new TJPEGImage;
    else if (
st == "0000"gr = new TIcon;
    else if (
st == "5089"gr = new TPNGObject;
    
// etc, etc, ...
    
gr->Assign(blob);
    
Image1->Picture NULL;
    
Image1->Picture->Bitmap->Height  gr->Height;
    
Image1->Picture->Bitmap->Width   gr->Width;
    
Image1->Picture->Bitmap->Canvas->Draw(00gr);
  } 
__finally {
    
delete gr;
  }


Saludos :)

Interesante código pero, al menos en BCB 6 tengo un probelma: Al compilar me da un error en la línea else if (st == "5089") gr = new TPNGObject; bueno para ser exactos da tres en la misma línea pero es evidente que resuelto, resueltos todos. Son estos:
  • [C++ Error] E2303 Type name expected
  • [C++ Error] E2034 Cannot convert 'int *' to 'TGraphic *'
  • [C++ Error] E2379 Statement missing ;
Está claro que en BCB 6 no sabe como tratar un PNG. Por otra parte, ¿dónde puedo encontrar las firmas de los diferentes tipos de gráfico?

ecfisa 26-07-2017 18:12:28

Hola.
Cita:

Empezado por Angel.Matilla (Mensaje 519717)
...
Por otra parte, ¿dónde puedo encontrar las firmas de los diferentes tipos de gráfico?


Saludos. :)

Angel.Matilla 26-07-2017 18:48:36

Muchas gracias.

ecfisa 26-07-2017 21:28:38

Hola.
Cita:

Empezado por Angel.Matilla (Mensaje 519717)
...Está claro que en BCB 6 no sabe como tratar un PNG.
...

Intenté con algunas opciones aconsejadas, adaptaciones de bibliotecas para Delphi, sin lograr resultados.

Sin embargo encontré esta que parece prometer algo:tendrías que probarla ...

Saludos :)

Angel.Matilla 27-07-2017 11:15:57

Probareos. Gracfias ecfisa.

bitbow 27-07-2017 21:37:07

Aqui reviviendo temas resueltos y por si a alguien le es de ayuda.

Tratando un problema similar pero cargando mis imagenes en base 64, al final la cebecera puede o no ir en el binario por lo que no se puede identificar que tipo de archivo es hasta que se intenta representar (jpg, png, bmp), mi mejor opcion fue detectar la extension del archivo (esto no garantiza al 100% que sea el tipo de archivo indicado) y agregar la cabecera a mi cadena base64 (en el problema mencionado aqui seria añadir la extension/tipo de archivo en otro campo), en resumen no hay soluciones infalibles.

Saludos.


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

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