views:

254

answers:

2

I have an application, currently written in C#, which can take a Base64-encoded string and turn it into an Image (a TIFF image in this case), and vice versa. In C# this is actually pretty simple.

    private byte[] ImageToByteArray(Image img)
    {
        MemoryStream ms = new MemoryStream();
        img.Save(ms, System.Drawing.Imaging.ImageFormat.Tiff);
        return ms.ToArray();
    }

    private Image byteArrayToImage(byte[] byteArrayIn)
    {
        MemoryStream ms = new MemoryStream(byteArrayIn);
        BinaryWriter bw = new BinaryWriter(ms);
        bw.Write(byteArrayIn);
        Image returnImage = Image.FromStream(ms, true, false);
        return returnImage;
    }

    // Convert Image into string
    byte[] imagebytes = ImageToByteArray(anImage);
    string Base64EncodedStringImage = Convert.ToBase64String(imagebytes);

    // Convert string into Image
    byte[] imagebytes = Convert.FromBase64String(Base64EncodedStringImage);
    Image anImage = byteArrayToImage(imagebytes);

(and, now that I'm looking at it, could be simplified even further)

I now have a business need to do this in C++. I'm using GDI+ to draw the graphics (Windows only so far) and I already have code to decode the string in C++ (to another string). What I'm stumbling on, however, is getting the information into an Image object in GDI+.

At this point I figure I need either

a) A way of converting that Base64-decoded string into an IStream to feed to the Image object's FromStream function

b) A way to convert the Base64-encoded string into an IStream to feed to the Image object's FromStream function (so, different code than I'm currently using)

c) Some completely different way I'm not thinking of here.

My C++ skills are very rusty and I'm also spoiled by the managed .NET platform, so if I'm attacking this all wrong I'm open to suggestions.

UPDATE: In addition to the solution I've posted below, I've also figured out how to go the other way if anyone needs it.

+1  A: 

This should be a two-step process. Firstly, decode the base64 into pure binary (the bits you would have had if you loaded the TIFF from file). The first Google result for this looks to be pretty good.

Secondly, you'll need to convert those bits to a Bitmap object. I followed this example when I had to load images from a resource table.

Ben Straub
OK, this is basically the answer. I kept running across these pages when I would Google things but since I'm dealing with strings or byte arrays I didn't know how to merge the two concepts (that second article is looking for resources from a table). I just figured out how and I'll post the code/answer on Monday.
Schnapple
See my answer below - that's how I did it but I figure I'll give someone else the rep for answering it :)
Schnapple
+1  A: 

OK, using the info from the Base64 decoder I linked and the example Ben Straub linked, I got it working

using namespace Gdiplus; // Using GDI+

Graphics graphics(hdc); // Get this however you get this

std::string encodedImage = "<Your Base64 Encoded String goes here>";

std::string decodedImage = base64_decode(encodedImage); // using the base64 
                                                        // library I linked

DWORD imageSize = decodedImage.length();
HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE, imageSize);
LPVOID pImage = ::GlobalLock(hMem);
memcpy(pImage, decodedImage.c_str(), imageSize);

IStream* pStream = NULL;
::CreateStreamOnHGlobal(hMem, FALSE, &pStream);

Image image(pStream);

graphics.DrawImage(&image, destRect);

pStream->Release();
GlobalUnlock(hMem);
GlobalFree(hMem);

I'm sure it can be improved considerably, but it works.

Schnapple