Club Builder - Foros de discusión Club Builder
Foro de C++Builder en español
 
 FAQFAQ   BuscarBuscar   MiembrosMiembros   Grupos de UsuariosGrupos de Usuarios   RegistrarseRegistrarse 
 PerfilPerfil   Entra para ver tus mensajes privadosEntra para ver tus mensajes privados   EntrarEntrar 

TDBImage con formato JPEG sin instalar componentes
Ir a página 1, 2, 3  Siguiente
 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Tips & Tricks
Ver tema anterior :: Ver tema siguiente  
Autor Mensaje
Mensaje    Asunto: TDBImage con formato JPEG sin instalar componentes Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Uso de un TDBImage Responder citando

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 Wink [/b]
_________________
Wersens54
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email Dirección AIM Yahoo Messenger MSN Messenger
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Jpeg en base de datos Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado Visitar sitio web del autor MSN Messenger
Mensaje    Asunto: Responder citando

Solucionado !!! Hay que leer el cartel en ROJO Very Happy

En realidad lo tenia deschekeado, pero despues comence una nueva aplicación de prueba y me olvide Embarassed

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
Ver perfil de usuario Enviar mensaje privado Visitar sitio web del autor MSN Messenger
Mensaje    Asunto: Responder citando

Sólo una pregunta: En vez de para un TDBImage, ¿valdría también para un TImage a secas? En este caso ¿qué cambios habría que hacer en el código que has puesto?
_________________
Un saludo

Necesitamos tu ayuda: Envía AI al 27595 (Coste 1,20 euros + IVA)
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email
Mensaje    Asunto: Responder citando

Hola Angel, no entiendo bien lo que deseas conseguir con el TImage, ya que este si lee directamente imágenes JPEG.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado Enviar email
Mensaje    Asunto: Responder citando


Compila bien, pero em da este error cuando hago Close() de la tabla donde va grabada la imagen. Cuando ejecuto la orden comienza a ejecutar el LoadPicture y no veo la razón.
_________________
Un saludo

Necesitamos tu ayuda: Envía AI al 27595 (Coste 1,20 euros + IVA)
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Leo: Descargate aquí el proyecto. Está hecho en Builder 5 con una tabla Paradox. El campo Carátula, que es donde guardo el gráfico, está vacío en todas las fichas; por eso he añadido la carpeta carteles con algunas de las imágenes para que puedas hacer alguna prueba. Ya me comentarás alguna cosa.
_________________
Un saludo

Necesitamos tu ayuda: Envía AI al 27595 (Coste 1,20 euros + IVA)
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado Enviar email
Mostrar mensajes de anteriores:   
Cambiar a:  
No puedes publicar temas nuevos en este foro
No puedes responder a temas en este foro
No puedes editar tus mensajes en este foro
No puedes borrar tus mensajes en este foro
No puedes votar en las encuestas de este foro


Hosting WordPress Indedmedia desde 3,99 €
© 2002–2026 Club Builder · Funciona con phpBB.