I have an application that stores images as a blob in a MySQL database. This database can be either on the local machine, or on a remote host. I store the image in the database using MySQL's load file, which works with the database engine either local or remote by using LOCAL. What I want to be able to do is retreive the image and display it in a window. If I am retreiving the image on the local host with the database engine, I can use MySQL's dump file, then use LoadFile to load the image, however, if the database engine is on a remote host, the dump file statement puts the image file on the remote host. Since I can use SELECT to get the blob to the local machine from a remote host, and since I can put the blob in a wxString, how do I get the image into either a wxBitmap, or a wxImage?
Thanks for the help.
Retreiving images stored in MySQL
-
- Earned a small fee
- Posts: 10
- Joined: Mon Feb 05, 2007 7:01 pm
You'll need to store more than just the image data. You will also need the width and height of the image. Once you have that it is quite easy to do:
that's all there is to it. Now you can use the image to do your painting in your Paint handler.
Chris Hodges
Code: Select all
//imagedata is defined as unsigned char*
wxImage img(width,height,imagedata,true);
Chris Hodges
-
- Earned a small fee
- Posts: 10
- Joined: Mon Feb 05, 2007 7:01 pm
Thaks for the quick reply Chris. It sent me off on a couple day of different attempts, but I still don't have it working. Here is what I'm doing. I am using the wxVillaLib graphics library. I like it for the scrolled window, the popup menu, the ability to scale the image, and I don't have to deal with dc and all that. As I mentioned before, my main problem is the ability to store the image in the MySQL database so that each client machine does not have to have the images on the local hard drive. The wxImageBox library only has LoadFile capabilities, and that seems to be from the local drive, which the MySQL dumpfile can only do if the database engine is on the local machine.
Based on your earlier reply, I have tried several ways to create the image from the blob returned from a MySQL SELECT statement. The problem I'm haveing is two fold. First converting the string returned by the SELECT statement to an unsigned char*. I finally figured out how to do this, I think, by doing some type casting, one character at a time, which is probably not the best way. but then the second problem, WxImageBox doesn't have a way to take an wxImage. I tried modifying the library to make m_image public, then assigining my converted image to it. This seemed to work, but when I compile my project, when the window is opened, the widgets are displayed, but the imagebox outline is drawn, and the app crashes. All i get is the Microsoft crash window. Oking it put me back in WxDevCpp. Next I trying making a function in the wxVillaLib library that takes a wxImage object and assinging it to m_image. Yhis is compiled and the new .a put in my lib directory, and I ge the same crash. One of the WxWidgets error dialogs talks of corrupted image files for .png and .jpg, and so on. So I'm thinking that my conversion from the string returned by MySQL to a wxImage is wrong, or the way that I'm putting it into the imagebox object is wrong. I beleive the blob stored in MySQL is good, as I can load my MySQL tool, and view the images in it's blob viewer.
Sorry for the long post, but hopefully someone can give me a hand.
Based on your earlier reply, I have tried several ways to create the image from the blob returned from a MySQL SELECT statement. The problem I'm haveing is two fold. First converting the string returned by the SELECT statement to an unsigned char*. I finally figured out how to do this, I think, by doing some type casting, one character at a time, which is probably not the best way. but then the second problem, WxImageBox doesn't have a way to take an wxImage. I tried modifying the library to make m_image public, then assigining my converted image to it. This seemed to work, but when I compile my project, when the window is opened, the widgets are displayed, but the imagebox outline is drawn, and the app crashes. All i get is the Microsoft crash window. Oking it put me back in WxDevCpp. Next I trying making a function in the wxVillaLib library that takes a wxImage object and assinging it to m_image. Yhis is compiled and the new .a put in my lib directory, and I ge the same crash. One of the WxWidgets error dialogs talks of corrupted image files for .png and .jpg, and so on. So I'm thinking that my conversion from the string returned by MySQL to a wxImage is wrong, or the way that I'm putting it into the imagebox object is wrong. I beleive the blob stored in MySQL is good, as I can load my MySQL tool, and view the images in it's blob viewer.
Sorry for the long post, but hopefully someone can give me a hand.
-
- Super wx Problem Solver
- Posts: 424
- Joined: Tue Jul 12, 2005 8:44 pm
- Location: Alabama, USA
I would suggest two things here. First, try using the DatabaseLayer library from the wxCode website. It works with many different databases (including MySQL) and handles loading and saving blob values easily. Second, once you have loaded the blob into memory, use a wxMemoryInputStream to allow wxImage::LoadFile to retrieve the file from memory.
-Scott
-Scott
wxMSW 2.6.2, VS 2002, 2003 and 2005, Code::Blocks and mingw, Windows XP Pro
The ODBC component that is coming with wxWidgets is enough to handle most database activities. I have been using it in my application.
The Image may be stored in the database as a BLOB. A real life example is quoted below. Here is the size is fixed. If you need, you could store the image size also in the database, then retrive the size first, and then define the storage dynamically based on the retrived size.
wxChar Image_ID[20+1]; //
wxChar Image_data[32765+1]; // buffer for the image data
//Bind the columns that are to be retrieved.
table->SetColDefs(0, "IMAGE_ID", DB_DATA_TYPE_VARCHAR, Image_ID, SQL_C_CHAR, sizeof(Image_ID), TRUE, FALSE);
table->SetColDefs(1, "IMAGE", DB_DATA_TYPE_BLOB, Image_data,
SQL_C_BINARY, sizeof(Image_data), FALSE, TRUE);
//Construct the where predicate.
where_predicate = "IMAGE_ID = '" + mImage_ID + "'";
I have two functions that will convert BLOB data into image files and vice versa. These may not be the most efficient. But it is working and you will get the idea.
bool mpcImage::ConvertImageToCharArray(char *image_data)
{
bool continue_flag = true;
//Since the saving to memory stream does not seems to be writing the file correctly,
//we are forced to write it into a real file and then read it back.
wxString file_name;
file_name += "./temp/temp1.jpg";
mpImage->SaveFile(file_name, wxBITMAP_TYPE_JPEG);
//mpImage.Destroy(); //delete the image in memory.
//Open the image file
wxFile file(file_name);
if (!(file.IsOpened()))
{
continue_flag = false;
wxMessageBox(wxT("Unable to open the temporary image processing file"), wxT("File Access Error"), wxOK | wxICON_EXCLAMATION);
}
//Read the image file
if (continue_flag)
{
if (file.Read(image_data, (size_t)file.Length()) != file.Length())
{
continue_flag = false;
wxMessageBox(wxT("Unable to Read the temporary image processing file"), wxT("File Access Error"), wxOK | wxICON_EXCLAMATION);
}
file.Close();
}
//delete the temporary image file
::wxRemoveFile(file_name);
return (continue_flag);
}
bool mpcImage::ConvertToFile(char *image_data)
{
bool continue_flag = true;
//Since the saving to memory stream does not seems to be writing the file correctly,
//we are forced to write it into a real file and then read it back.
wxString file_name;
file_name += "./temp/temp2.jpg";
wxFile file(file_name, wxFile::write);
if (!(file.IsOpened()))
{
continue_flag = false;
wxMessageBox(wxT("Unable to open the temporary image for writing"), wxT("File Access Error"), wxOK | wxICON_EXCLAMATION);
}
//Read the image file
if (continue_flag)
{
if (file.Write(image_data, 4468) != 4468)
{
continue_flag = false;
wxMessageBox(wxT("Unable to Write the temporary image processing file"), wxT("File Access Error"), wxOK | wxICON_EXCLAMATION);
}
file.Close();
}
::wxRemoveFile(file_name);
return (continue_flag);
}
The Image may be stored in the database as a BLOB. A real life example is quoted below. Here is the size is fixed. If you need, you could store the image size also in the database, then retrive the size first, and then define the storage dynamically based on the retrived size.
wxChar Image_ID[20+1]; //
wxChar Image_data[32765+1]; // buffer for the image data
//Bind the columns that are to be retrieved.
table->SetColDefs(0, "IMAGE_ID", DB_DATA_TYPE_VARCHAR, Image_ID, SQL_C_CHAR, sizeof(Image_ID), TRUE, FALSE);
table->SetColDefs(1, "IMAGE", DB_DATA_TYPE_BLOB, Image_data,
SQL_C_BINARY, sizeof(Image_data), FALSE, TRUE);
//Construct the where predicate.
where_predicate = "IMAGE_ID = '" + mImage_ID + "'";
I have two functions that will convert BLOB data into image files and vice versa. These may not be the most efficient. But it is working and you will get the idea.
bool mpcImage::ConvertImageToCharArray(char *image_data)
{
bool continue_flag = true;
//Since the saving to memory stream does not seems to be writing the file correctly,
//we are forced to write it into a real file and then read it back.
wxString file_name;
file_name += "./temp/temp1.jpg";
mpImage->SaveFile(file_name, wxBITMAP_TYPE_JPEG);
//mpImage.Destroy(); //delete the image in memory.
//Open the image file
wxFile file(file_name);
if (!(file.IsOpened()))
{
continue_flag = false;
wxMessageBox(wxT("Unable to open the temporary image processing file"), wxT("File Access Error"), wxOK | wxICON_EXCLAMATION);
}
//Read the image file
if (continue_flag)
{
if (file.Read(image_data, (size_t)file.Length()) != file.Length())
{
continue_flag = false;
wxMessageBox(wxT("Unable to Read the temporary image processing file"), wxT("File Access Error"), wxOK | wxICON_EXCLAMATION);
}
file.Close();
}
//delete the temporary image file
::wxRemoveFile(file_name);
return (continue_flag);
}
bool mpcImage::ConvertToFile(char *image_data)
{
bool continue_flag = true;
//Since the saving to memory stream does not seems to be writing the file correctly,
//we are forced to write it into a real file and then read it back.
wxString file_name;
file_name += "./temp/temp2.jpg";
wxFile file(file_name, wxFile::write);
if (!(file.IsOpened()))
{
continue_flag = false;
wxMessageBox(wxT("Unable to open the temporary image for writing"), wxT("File Access Error"), wxOK | wxICON_EXCLAMATION);
}
//Read the image file
if (continue_flag)
{
if (file.Write(image_data, 4468) != 4468)
{
continue_flag = false;
wxMessageBox(wxT("Unable to Write the temporary image processing file"), wxT("File Access Error"), wxOK | wxICON_EXCLAMATION);
}
file.Close();
}
::wxRemoveFile(file_name);
return (continue_flag);
}