Serializeand deserialize wxImage

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
dkaip
Super wx Problem Solver
Super wx Problem Solver
Posts: 334
Joined: Wed Jan 20, 2010 1:15 pm

Serializeand deserialize wxImage

Post by dkaip »

Hello. In code bellow i am try in first place to serialize the wxImage to wxString...

Code: Select all

ool wxImageToMemoryBuffer(const wxImage& image, wxMemoryBuffer& buffer)
{
    wxCHECK(image.IsOk(), false);

    wxMemoryOutputStream stream;

    if ( !image.SaveFile(stream, wxBITMAP_TYPE_ANY) )
        return false;

    buffer.SetBufSize(stream.GetSize());
    buffer.SetDataLen(stream.GetSize());
    stream.CopyTo(buffer.GetData(), buffer.GetDataLen());

    return true;
}

wxString wxImageSerialize(const wxImage& source)
{
    wxMemoryBuffer buffer;
    if(wxImageToMemoryBuffer(source,buffer))
        return wxMemoryBufferToString(buffer);
}

void test(  )
{
    wxInitAllImageHandlers() ;
    wxBitmap bmp("omega.png");
    wxImage img=bmp.ConvertToImage();
    wxString str=wxImageSerialize(img);
    wxMessageBox(str);
}
I am taking..
No image handler for type 50 defined.
and in wxmessagebox nothing.
If instead wxBITMAP_TYPE_ANY use wxBITMAP_TYPE_BMP i am taking only wxMessageBox with null string.
Any idea why?
Thank you
Jim.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Serializeand deserialize wxImage

Post by doublemax »

When saving a file, you need to explicitly tell what image format you want, so wxBITMAP_TYPE_ANY won't work.

Without knowing what wxMemoryBufferToString does, it's hard to tell why you get an empty string.

BTW: If this is related to your other posts regarding wxSQLite, you don't need to convert an image to a string in order to store it in a database. There is a BLOB column type for that and the "minimal" sample that comes with wxSQLite shows how to use it.
Use the source, Luke!
dkaip
Super wx Problem Solver
Super wx Problem Solver
Posts: 334
Joined: Wed Jan 20, 2010 1:15 pm

Re: Serializeand deserialize wxImage

Post by dkaip »

Hello, thank you.
I have try wxBITMAP_TYPE_PNG and don’t work.
Sorry, i forgot code ...

Code: Select all

wxString wxMemoryBufferToString(const wxMemoryBuffer& buffer)
{
    wxString mystring(buffer, wxConvUTF8);
    return mystring;
}
Yes this is related to your other posts regarding wxSQLite.
It is old problem for me.
As i see in minimal the code is as bellow ...

Code: Select all

db.ExecuteUpdate("create table bindata(desc char(10), data blob);");


int binSize = 256;
unsigned char* binData = new unsigned char[binSize];
for (i = 0; i < binSize; i++)
{
binData[i] = i;
}
wxSQLite3Statement stmt = db.PrepareStatement("insert into bindata values ('testing', ?);");
stmt.Bind(1, binData, binSize);
stmt.ExecuteUpdate();
cout << "Stored binary Length: " << binSize << endl;

q = db.ExecuteQuery("select data from bindata where desc = 'testing';");

const unsigned char* pbin = binData;
if (q.NextRow())
{
int blobLen;
const wxString columnName(wxS("data"));
pbin = q.GetBlob(wxString(wxS("data")),blobLen);
cout << "Retrieved binary Length: " << blobLen << endl;
}

for (i = 0; i < sizeof binData; i++)
{
if (pbin[i] != i)
{
cout << "Problem: i: ," << i << " bin[i]: " << pbin[i] << endl;
}
}
q.Finalize();
delete[] binData;
How to make a file, not only an image , but other types, like .doc or .pdf to binary, with safe way and then store in db?
As i see in net the codes bellow maybe are working for me...

Code: Select all

bmp to text

#include <stdio.h>

int main(int argc, char*argv[]){

FILE *ptr_bmp_in;
FILE *ptr_text_out;
int c;

ptr_bmp_in=fopen("panda_input.bmp","rb");
ptr_text_out=fopen("panda_to_text.txt","w");

if(!ptr_bmp_in)
{
    printf("Unable to open file\n");
    return 1;
}

while((c=fgetc(ptr_bmp_in)) != EOF)
    {
        for(int i=0;i<=7;i++)
        {
            if(c&(1<<(7-i)))
            {
                fputc('1',ptr_text_out);
            }
            else
            {
                fputc('0',ptr_text_out);
            }
        }
    }


    fclose(ptr_bmp_in);
    fclose(ptr_text_out);
    printf("Writing done\n");

    return 0;
}

and text to bmp

#include <stdio.h>


char bytefromtext(unsigned char* text)
{   
    char result = 0;
    for(int i=0;i<8;i++)
    {
        if(text[i]=='1')
        {
            result |= (1 << (7-i));
        }
    }
    return result;
}

int main(int argc, char*argv[]){

FILE *ptr_txt_in;
FILE *ptr_bmp_out;
unsigned char buf[8];
int c;
int j = 0;

ptr_txt_in=fopen("panda_to_text.txt","r");
ptr_bmp_out=fopen("panda_output.bmp","wb");

if(!ptr_txt_in)
{
    printf("Unable to open file\n");
    return 1;
}

while((c=fgetc(ptr_txt_in)) != EOF)
    {
        buf[j++] = c;
        if(j==8)
        {
            fputc(bytefromtext(buf),ptr_bmp_out);
            j=0;
        }
    }
    fclose(ptr_txt_in);
    fclose(ptr_bmp_out);
    printf("Writing done\n");
    return 0;
}
I must find some time to check out...
Thank you.
Jim
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4204
Joined: Sun Jan 03, 2010 5:45 pm

Re: Serializeand deserialize wxImage

Post by PB »

Not sure if those are any useful for blob in SQLite but I have recently shown you two pieces of working code that convert wxImage to (1) void pointer and (2) wxString.

You did not respond but it seems that the code in the OP is very similar to the code I referred you to, except you replaced a concrete image format with an invalid constant which made it not work.

I have just tried the code for converting wxImage to and from wxString and wxMemoryBuffer (slightly modified, added a function for loading wxImage from wxString) , still works as expected:

Code: Select all

#include <wx/wx.h>
#include <wx/mstream.h>
#include <wx/sstream.h>

bool wxImageToString(const wxImage& image, wxString& imageString)
{
    wxCHECK(image.IsOk(), false);

    wxStringOutputStream stream(&imageString, wxConvISO8859_1);

    return image.SaveFile(stream, wxBITMAP_TYPE_PNG);
}

bool wxStringToImage(const wxString& imageString, wxImage& image)
{
    wxMemoryInputStream stream(imageString.mb_str(wxConvISO8859_1), imageString.size());

    return image.LoadFile(stream);
}

bool wxImageToMemoryBuffer(const wxImage& image, wxMemoryBuffer& buffer)
{
    wxCHECK(image.IsOk(), false);

    wxMemoryOutputStream stream;

    if ( !image.SaveFile(stream, wxBITMAP_TYPE_PNG) )
        return false;

    const size_t copied = stream.CopyTo(buffer.GetWriteBuf(stream.GetSize()), stream.GetSize());
    buffer.UngetWriteBuf(copied);

    return buffer.GetDataLen() == stream.GetSize();
}

bool wxMemoryBufferToImage(const wxMemoryBuffer& buffer, wxImage& image)
{
    wxCHECK(!buffer.IsEmpty(), false);

    wxMemoryInputStream stream(buffer.GetData(), buffer.GetDataLen());

    return image.LoadFile(stream);
}


class MyApp : public wxApp
{
public:
    bool OnInit() override
    {
        wxInitAllImageHandlers();
        wxImage image;

        if ( !image.LoadFile("toucan.png") )
            return false;

        wxImage imageFromString;
        wxString imageString;

        if ( wxImageToString(image, imageString)
             && wxStringToImage(imageString, imageFromString) )
        {
            imageFromString.SaveFile("toucan from string.png", wxBITMAP_TYPE_PNG);
        }
        else
            wxLogError("Could not convert wxImage to wxString and back!");

        wxImage imageFromBuffer;
        wxMemoryBuffer imageBuffer;

        if ( wxImageToMemoryBuffer(image, imageBuffer)
             && wxMemoryBufferToImage(imageBuffer, imageFromBuffer) )
        {
            imageFromBuffer.SaveFile("toucan from buffer.png", wxBITMAP_TYPE_PNG);
        }
        else
            wxLogError("Could not convert wxImage to wxMemoryBuffer and back!");

        return false;
    }
}; wxIMPLEMENT_APP(MyApp);
Out of curiousity, what is the exact problem, saying "does not work" is not of much use.
Last edited by PB on Sun Jun 14, 2020 6:09 pm, edited 2 times in total.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Serializeand deserialize wxImage

Post by doublemax »

Code: Select all

wxString wxMemoryBufferToString(const wxMemoryBuffer& buffer)
{
    wxString mystring(buffer, wxConvUTF8);
    return mystring;
}
That can't work, because the binary data does not represent an UTF8 byte sequence.

The easiest way would be to Base64 encode the binary data:

Code: Select all

#include <wx/base64.h>
wxString wxMemoryBufferToString(const wxMemoryBuffer& buffer)
{
   return wxBase64Encode(buffer);
}
This will increase the size of the data by about 33%.
https://docs.wxwidgets.org/trunk/group_ ... 6e580d4861
Use the source, Luke!
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4204
Joined: Sun Jan 03, 2010 5:45 pm

Re: Serializeand deserialize wxImage

Post by PB »

BTW, this could be how to get any data from a file (assuming the file fits into the memory at once) to a SQLite database as a blob using wxSQLite

Code: Select all

#include <wx/buffer.h>
#include <wx/wfstream.h>

bool GetFileAsBlob(const wxString& fileName, wxMemoryBuffer& blob)
{
    wxFFileInputStream file(fileName);

    if ( !file.IsOk() )
        return false;

    const size_t fileSize = file.GetSize();

    if ( !file.ReadAll(blob.GetWriteBuf(fileSize), fileSize) )
    {
        blob.UngetWriteBuf(0);
        return false;
    }

    blob.UngetWriteBuf(fileSize);
    return true;
}
and then (based on the wxSQLite minimal sample) do something like this

Code: Select all

        wxMemoryBuffer blob;
       
        if ( GetFileAsBlob("toucan.png", blob) )
        {
            wxSQLite3Statement stmt = db.PrepareStatement("insert into bindata values ('testing', ?);");
            stmt.Bind(1, blob);
            stmt.ExecuteUpdate();
        }
Please notice that wxSQLite seems to have direct support for wxMemoryBuffer, so there is no need to use raw pointers.

And just for the sake of completeness, here is a function to create a file from a blob

Code: Select all

bool CreateFileFromBlob(const wxString& fileName, const wxMemoryBuffer& blob)
{
    wxFFileOutputStream file(fileName);

    if ( !file.IsOk() )
        return false;

    if ( blob.IsEmpty() )
        return true; // nothing to write

    return file.WriteAll(blob.GetData(), blob.GetDataLen());
}
dkaip
Super wx Problem Solver
Super wx Problem Solver
Posts: 334
Joined: Wed Jan 20, 2010 1:15 pm

Re: Serializeand deserialize wxImage

Post by dkaip »

Hello, sorry if i am not respond. Too many things in my mind, and little time.
Thank you for the code.
As i see with code works just fine, thank you.
Jim
dkaip
Super wx Problem Solver
Super wx Problem Solver
Posts: 334
Joined: Wed Jan 20, 2010 1:15 pm

Re: Serializeand deserialize wxImage

Post by dkaip »

Hello. maybe i must start a new subject?
After that code works perfect, a new idea to my mind.
From clipboard all data as binary, to blob and vise versa.
Is that possible?
For example, copy a web page or doc file to clip and put in blob.
Any time we can have it without have a file in hard disk.
Thank you.
Jim
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4204
Joined: Sun Jan 03, 2010 5:45 pm

Re: Serializeand deserialize wxImage

Post by PB »

I have no idea what are you trying to say here? I assume you mean to use the Clipboard to store some data there instead of using a file system?

The clipboard is not for the programmer to decide what it put there when he wants, what is put there is strictly the user's choice. I would be very upset if I Cut something to the Clipboard, expecting to use it later and some unbehaved program overwrote it...

If you do not want to store data on a permanent storage such as a hard drive (why not?), store it in the memory space allocated to your application. As I wrote above, the clipboard contains the data to be transferred between applications based on the user's actions (Cut or Copy) not as a storeroom for temporary data.
dkaip
Super wx Problem Solver
Super wx Problem Solver
Posts: 334
Joined: Wed Jan 20, 2010 1:15 pm

Re: Serializeand deserialize wxImage

Post by dkaip »

Yes you have right. That is my question. Is that possible?
In question
permanent storage such as a hard drive (why not?),
just for fun.
There is no need to do that, but only for knowledge and curiosity.
Thank you.
Jim
Post Reply