| Ver tema anterior :: Ver tema siguiente |
| Autor |
Mensaje |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Mar 26 Oct, 2004 3:07 am Asunto: TDBImage con formato JPEG sin instalar componentes |
|
|
Este truco permite, sin instalar ningún nuevo componente, hacer que TDBImage guarde las imágenes en formato JPEG en vez de BMP, ahorrando así muchísimo espacio en disco.
Solo tenemos que añadir el siguiente código tal y como esta, sin modificar nada, en cualquier parte de nuestro programa:
(No tenemos que llamar a estas funciones desde nuestro programa en ningún momento, solo copiarlas y seguir trabajando de manera normal con el TDBImage)
| Código: | #include <memory>
#include <jpeg.hpp>
/////CARGA IMAGEN DE LA BASE DE DATOS////////////////////////////////////////
void __fastcall TDBImage::LoadPicture(void)
{
if (!FPictureLoaded && (!FDataLink->Field
#if __BORLANDC__ >= 0x0560
|| FDataLink->Field->IsBlob(__classid(TField))))
#else
|| FDataLink->Field->IsBlob()))
#endif
{
std::auto_ptr<TStream> stream(FDataLink->Field->DataSet
->CreateBlobStream(FDataLink->Field, bmRead));
DWORD tipo;
stream->Read(&tipo, sizeof(tipo));
stream->Position = 0;
if (tipo == 0xE0FFD8FF)
{
std::auto_ptr<TJPEGImage> jpeg(new TJPEGImage);
jpeg->LoadFromStream(stream.get());
Picture->Assign(jpeg.get());
}
else
{
stream.reset();
Picture->Assign(FDataLink->Field);
}
}
}
/////GUARDA LA IMAGEN EN LA BASE DE DATOS////////////////////////////////////
void __fastcall TDBImage::UpdateData(TObject* Sender)
{
if (dynamic_cast<Graphics::TBitmap*>(Picture->Graphic))
{
FDataLink->Field->Assign(Picture->Graphic);
std::auto_ptr<TStream> stream(FDataLink->Field->DataSet
->CreateBlobStream(FDataLink->Field, bmWrite));
std::auto_ptr<TJPEGImage> jpeg(new TJPEGImage);
jpeg->CompressionQuality = 90;
jpeg->Assign(Picture->Graphic);
jpeg->SaveToStream(stream.get());
}
else if (dynamic_cast<TJPEGImage*>(Picture->Graphic))
{
std::auto_ptr<TStream> stream(FDataLink->Field->DataSet
->CreateBlobStream(FDataLink->Field, bmWrite));
TJPEGImage* jpeg = static_cast<TJPEGImage*>(Picture->Graphic);
jpeg->SaveToStream(stream.get());
}
else
FDataLink->Field->Clear();
} |
Si lo añadimos a un programa en el que ya teníamos una base de datos con imágenes en formato BMP no habrá problema, las anteriores se quedaran en formato BMP y las nuevas que añadamos lo harán en formato JPEG.
Tanto si cargamos un BMP usando “DBImage1->Picture->LoadFromFile()“ como si usamos el portapeles para pegar una imagen sobre el componente, a la hora de guardarse en disco se convertirá siempre en JPEG. Y si la imagen ya estaba en formato JPEG simplemente la guardara sin volver a hacer ninguna recompresión con perdida de calidad.
Lo he probado en BCB4 y BCB6 que son las versiones que tengo instaladas, con el BDE+Paradox y con ADO+Access. Si alguien lo prueba en otras versiones de BCB con otros motores de base de datos me gustaría que lo comentase mas abajo.
* Solo hay un pequeño error, y es que evidentemente en tiempo de _diseño_ el TDBImage no podrá leer un JPEG, por lo que si activamos la tabla en tiempo de diseño recibiremos el mensaje “Bitmap image is not valid.”, pero en tiempo de ejecución funcionara correctamente.
¡ATENCION!: Esto solo funciona si tenemos enlazados estáticamente los packages con el ejecutable. O sea:
Ir al menú: Project -> Options... Dentro de ese dialogo ir a la pestaña: "Packages". Y dentro de esa pestaña desmarcar el Checkbox: "Build with runtime packages". |
|
| Volver arriba |
|
 |
cecito Capt

Registrado: 25 Nov 2003Mensajes: 164Ubicación: Arequipa - Perú
|
Publicado: Mar 26 Oct, 2004 12:29 pm Asunto: |
|
|
Hola _Leo, por lo que entiendo estas sobreescibiendo los métodos LoadPicture(void) y
UpdateData(TObject* Sender) de un componente TDBImage, ahora ¿se podia hacer esto sin heredar de una nueva clase? ¿Como es posible esto? ¿Se pude sobreescribir otros métodos de otros controles?
y es posible echar mano de "Clases Interpuestas" como algunos hacen en Delphi? |
|
| Volver arriba |
|
 |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Mar 26 Oct, 2004 4:39 pm Asunto: |
|
|
| Cita: | ...por lo que entiendo estas sobreescibiendo los métodos LoadPicture(void) y
UpdateData(TObject* Sender) de un componente TDBImage... |
Si.
| Cita: | | ¿se podia hacer esto sin heredar de una nueva clase? |
Si.
| Cita: | | ¿Como es posible esto? |
El compilador sobreescribe las funciones que tengan el mismo nombre con las mas recientes.
| Cita: | | ¿Se pude sobreescribir otros métodos de otros controles? |
Si.
| Cita: | | y es posible echar mano de "Clases Interpuestas" como algunos hacen en Delphi? |
No lo se, habría que probarlo. Buscando en Google por ese termino solo he encontrado una página en español y tres en ingles, todas en referencia a Delphi, así que supongo que no debe ser algo muy común. |
|
| Volver arriba |
|
 |
wersens54 Cdt

Registrado: 03 Mar 2004Mensajes: 3Ubicación: Barinas
|
Publicado: Mar 02 Nov, 2004 10:00 pm Asunto: Uso de un TDBImage |
|
|
Primero que nada un saludo al amigo Leo. Quisiera hacerle una pregunta:
Yo tengo montado en mi màquina, BORLAND C++ BUILDER 5, y he usado el codigo que usted ha puesto para la convesion de imàgenes a jpg y postterior cara a la base de datos.
/---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::BtnAgregarClick(TObject *Sender)
{
ADOTable1->Insert();
ADOTable1->FieldValues ["cedula"]= Cedula->Text;
ADOTable1->FieldValues ["Nombre"]= Nombre->Text;
ADOTable1->FieldValues ["cargo"]= Cargo->Text;
ADOTable1->FieldValues ["placa_veh"]= Placa->Text;
Nombre->Text = "";
Cedula->Text = "";
Cargo->Text = "";
Placa->Text = "";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::BtnSiguienteClick(TObject *Sender)
{
ADOTable1->Next ();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::BtnSalirClick(TObject *Sender)
{
Application->Terminate ();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::BtnBorrarClick(TObject *Sender)
{
Nombre->Text = "";
Cedula->Text = "";
Cargo->Text = "";
Placa->Text = "";
ADOTable1->Insert();
Nombre->SetFocus();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::BtnAnteriorClick(TObject *Sender)
{
ADOTable1->Prior();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Form2->Show();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
if (OpenPictureDialog1->Execute())
{
if (!ADOTable1->State == dsInsert || ADOTable1->State == dsEdit)
ADOTable1->Edit();
ADOTable1->LoadFromFile(OpenPictureDialog1->FileName);
}
}
/////CARGA IMAGEN DE LA BASE DE DATOS////////////////////////////////////////
void __fastcall TDBImage::LoadPicture(void)
{
if (!FPictureLoaded && (!FDataLink->Field
#if __BORLANDC__ >= 0x0560
|| FDataLink->Field->IsBlob(__classid(TField))))
#else
|| FDataLink->Field->IsBlob()))
#endif
{
std::auto_ptr<TStream> stream(FDataLink->Field->DataSet
->CreateBlobStream(FDataLink->Field, bmRead));
DWORD tipo;
stream->Read(&tipo, sizeof(tipo));
stream->Position = 0;
if (tipo == 0xE0FFD8FF)
{
std::auto_ptr<TJPEGImage> jpeg(new TJPEGImage);
jpeg->LoadFromStream(stream.get());
Picture->Assign(jpeg.get());
}
else
{
stream.reset();
Picture->Assign(FDataLink->Field);
}
}
}
/////GUARDA LA IMAGEN EN LA BASE DE DATOS////////////////////////////////////
void __fastcall TDBImage::UpdateData(TObject* Sender)
{
if (dynamic_cast<Graphics::TBitmap*>(Picture->Graphic))
{
FDataLink->Field->Assign(Picture->Graphic);
std::auto_ptr<TStream> stream(FDataLink->Field->DataSet
->CreateBlobStream(FDataLink->Field, bmWrite));
std::auto_ptr<TJPEGImage> jpeg(new TJPEGImage);
jpeg->CompressionQuality = 90;
jpeg->Assign(Picture->Graphic);
jpeg->SaveToStream(stream.get());
}
else if (dynamic_cast<TJPEGImage*>(Picture->Graphic))
{
std::auto_ptr<TStream> stream(FDataLink->Field->DataSet
->CreateBlobStream(FDataLink->Field, bmWrite));
TJPEGImage* jpeg = static_cast<TJPEGImage*>(Picture->Graphic);
jpeg->SaveToStream(stream.get());
}
else
FDataLink->Field->Clear();
}
//---------------------------------------------------------------------------
El código anterior da el siguiente error. A quien me pueda ayudar se lo agradecería.
"No se puede crear un recordset desde el origen especificado. El archivo o la secuencia deben tener Datos Recordset en formato XML o ADTG"
lE AGRADECERÌA CUALQUIER AYUDA [/b] _________________ Wersens54 |
|
| Volver arriba |
|
 |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Mar 02 Nov, 2004 10:53 pm Asunto: |
|
|
Si se fija en el evento OnClick del Button2, la línea siguiente:
ADOTable1->LoadFromFile(OpenPictureDialog1->FileName);
lo que hace realmente es cargar un recordset desde un archivo, cuando lo que se intenta realmente, supongo, es cargar una imagen en un campo de la base de datos.
Si tenemos enlazado nuestro campo de imagen con un componente TDBImage, cambiaríamos esa línea por:
DBImage1->Picture->LoadFromFile(OpenPictureDialog1->FileName);
bien por el nombre del campo si los hemos cargado pulsando sobre el componente TADOTable:
NombreQueLeHemosDato->LoadFromFile(OpenPictureDialog1->FileName);
o bien si usamos FieldByName para acceder a los campos:
TBlobField* campoImagen = static_cast<TBlobField*>(ADOTable1->FieldByName("MI_CAMPO"));
campoImagen->LoadFromFile(OpenPictureDialog1->FileName); |
|
| Volver arriba |
|
 |
overnat Cdt

Registrado: 29 Ene 2005Mensajes: 1
|
Publicado: Sab 29 Ene, 2005 7:49 am Asunto: Jpeg en base de datos |
|
|
Hola soy nuevo por aki , y dando un paseillo por los post me encontre este y me llamo mucho la atencion .
Estoy haciendo un programa en el que cargo y guardo las imagenes que me llegan desde la webcam .
¿ Me preguntaba si es mejor cargar la imagen a la base de datos ó de lo contrario seria mejor cargar la direccion de la imagen dentro del disco duro , que solo serian letras y ocupan menos . ? ¿ no ? .
o que utilidad tiene aparte de guardar imagenes dentro para que otros no las cojan.
Salu2. |
|
| Volver arriba |
|
 |
Crandel Lt


Registrado: 31 May 2005Mensajes: 94Ubicación: Argentina
|
Publicado: Vie 16 Sep, 2005 7:03 am Asunto: |
|
|
Hola Leo, pero la verdad es que no me funciona tus dos métodos, en realidad no es que no funciona sino que ni siquiera los compila.
A que puede deberse?
Las pegas en el .cpp asi directamente sin declararlas antes en ninguna lado?
No hay que avisar en ningun lado que se estan redeclarando estos métodos? _________________ Crandel
"hay 10 tipos de personas, las que ven en binario y las que no"
Angel Zeitoune - Artículo: Generación de eventos en C++Builder |
|
| Volver arriba |
|
 |
Crandel Lt


Registrado: 31 May 2005Mensajes: 94Ubicación: Argentina
|
Publicado: Sab 17 Sep, 2005 7:03 am Asunto: |
|
|
Solucionado !!! Hay que leer el cartel en ROJO
En realidad lo tenia deschekeado, pero despues comence una nueva aplicación de prueba y me olvide
Esta muy bueno LEO _________________ Crandel
"hay 10 tipos de personas, las que ven en binario y las que no"
Angel Zeitoune - Artículo: Generación de eventos en C++Builder |
|
| Volver arriba |
|
 |
Angel Master


Registrado: 15 Abr 2003Mensajes: 2311Ubicación: Toledo (España)
|
|
| Volver arriba |
|
 |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Mar 03 Oct, 2006 9:25 pm Asunto: |
|
|
| Hola Angel, no entiendo bien lo que deseas conseguir con el TImage, ya que este si lee directamente imágenes JPEG. |
|
| Volver arriba |
|
 |
Angel Master


Registrado: 15 Abr 2003Mensajes: 2311Ubicación: Toledo (España)
|
Publicado: Mie 04 Oct, 2006 7:57 am Asunto: |
|
|
Estoy preparando una aplicación en la que la información no está directamente conectada a las tablas de una base de datos mediante elementos DBEdit, DBImage y similares ya que va a ser transmitida a través de servidores y clientes. _________________ Un saludo
Necesitamos tu ayuda: Envía AI al 27595 (Coste 1,20 euros + IVA) |
|
| Volver arriba |
|
 |
Angel Master


Registrado: 15 Abr 2003Mensajes: 2311Ubicación: Toledo (España)
|
|
| Volver arriba |
|
 |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Jue 16 Nov, 2006 7:35 pm Asunto: |
|
|
Hola Angel, siento no poder ayudarte ya que en las pruebas que yo hago me funciona correctamente. Tendria que tener tu codigo para poder reproducir el problema o que me muestres un ejemplo lo mas pequeño posible que permita reproducir el error para poder corregirlo.
Que versión de C++Builder utilizas? Que componentes de datos? Que base de datos? .. para ir haciendo alguna prueba más. |
|
| Volver arriba |
|
 |
Angel Master


Registrado: 15 Abr 2003Mensajes: 2311Ubicación: Toledo (España)
|
|
| Volver arriba |
|
 |
Carlos J. Fernandez Master


Registrado: 27 Oct 2004Mensajes: 574
|
Publicado: Mie 29 Abr, 2009 5:20 pm Asunto: |
|
|
Leo,
Ya se que este mensaje tiene mucho tiempo, pero a ver si me puedes echar una mano.
Todo va perfecto usando componentes TDBImage, el problema es cuando quiero utilizar un TDBCtrlGrid, como sabes dentro de el puedes poner un TDBImage y pensaba que todo funcionaria igual, pero parece que no, por alguna razon sale un mensaje de que no en un BMP correcto, osea que no pasa por la funcion que has puesto.
Sabes cual es el problema?, el TDBCtrlGrid utiliza otras funciones diferentes?
Un abrazo.
Carlos |
|
| Volver arriba |
|
 |
|