1

I want to get the base64 string from WriteableBitmap. I believe the byte[] to be incorrect.

Because:

The code for creating image from base64 is working. Tested this when sending base64 string from file. However i can't see anything when i'm using my function for WriteableBitmap to base64.

My attempts so far.

   public static string GetByteArrayFromImage(WriteableBitmap writeableBitmap)
        {
             Stream stream = writeableBitmap.PixelBuffer.AsStream();
             MemoryStream memoryStream = new MemoryStream();
             stream.CopyTo(memoryStream);
             Byte[] bytes = memoryStream.ToArray();
             return Convert.ToBase64String(bytes);
        }

   public static string GetByteArrayFromImage(WriteableBitmap writeableBitmap)
        {
             Byte[] bytes = writeableBitmap.PixelBuffer.ToArray();
             return Convert.ToBase64String(bytes);
        }

Test example:

   public static async Task<string> GetBase64StringFromFileAsync(StorageFile storageFile)
        {
            Stream ms = await storageFile.OpenStreamForReadAsync();
            byte[] bytes = new byte[(int)ms.Length];
            ms.Read(bytes, 0, (int)ms.Length);
            return Convert.ToBase64String(bytes);
        }

Is the byte[] in the wrong format? If so how do i correct it?

My new attempt

        Stream stream = writeableBitmap.PixelBuffer.AsStream();
        byte[] pixels = new byte[(uint)stream.Length];
        await stream.ReadAsync(pixels, 0, pixels.Length);

        using (var writeStream = new InMemoryRandomAccessStream())
        {
            var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, writeStream);
            encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, (uint)writeableBitmap.PixelWidth, (uint)writeableBitmap.PixelHeight, 96, 96, pixels);
            await encoder.FlushAsync();
        }
        return Convert.ToBase64String(pixels);

This attempt doesn't change my byte[] to the correct fromat.

Developer
  • 59
  • 7
  • 1
    `Tested this when sending base64 string from file.` Well files are usually encoded (jpeg, gif, png, etc.) you just converted a bunch of raw pixel data to a base64 string. What's your final goal? Saving an image as bytes and convert those to base64? What does your Test case look like? (The one that works) – Manfred Radlwimmer May 04 '16 at 10:20
  • Thanks for the response. Added my test example. I want to convert my image to base64. The backend will make a image for it. I read this image from url. I can create image in backend from my test code. However i don't get a image from my byte[] from my image. – Developer May 04 '16 at 10:29
  • In your new attempt you are never using the encoded buffer in writeStream. See my answer. – Clemens May 05 '16 at 20:46

2 Answers2

2

The method below creates a BitmapEncoder that operates on an InMemoryRandomAccessStream, adds a SoftwareBitmap that is created from a WriteableBitmap, reads the stream content into a byte array, and finally converts that byte array into a base64 string:

public async Task<string> ToBase64String(WriteableBitmap writableBitmap)
{
    using (var stream = new InMemoryRandomAccessStream())
    {
        var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);

        encoder.SetSoftwareBitmap(SoftwareBitmap.CreateCopyFromBuffer(
            writableBitmap.PixelBuffer,
            BitmapPixelFormat.Bgra8,
            writableBitmap.PixelWidth,
            writableBitmap.PixelHeight));

        await encoder.FlushAsync();

        var bytes = new byte[stream.Size];
        await stream.AsStream().ReadAsync(bytes, 0, bytes.Length);

        return Convert.ToBase64String(bytes);
    }
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
0

If you want to convert an image to a base64 stream, the best way would be to encode it first.

public static string GetByteArrayFromImage(BitmapSource writeableBitmap)
{
    JpegBitmapEncoder encoder = new JpegBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(writeableBitmap));
    MemoryStream stream = new MemoryStream();
    encoder.Save(stream);
    Byte[] bytes = stream.ToArray();
    return Convert.ToBase64String(bytes);
}

public static BitmapSource GetImageFromByteArray(string base64String)
{
    byte[] bytes = Convert.FromBase64String(base64String);
    MemoryStream stream = new MemoryStream(bytes);
    JpegBitmapDecoder decoder = new JpegBitmapDecoder(stream, 
        BitmapCreateOptions.None, BitmapCacheOption.Default);
    return decoder.Frames[0];
}

Test case to show it works:

BitmapImage originalImage = new BitmapImage(new Uri(@"Path to any picture", UriKind.Absolute));

string encoded = GetByteArrayFromImage(originalImage);
BitmapSource decoded = GetImageFromByteArray(encoded);

image1.Source = decoded;
Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
  • JpegBitmapEncoder doesn't exist. BitmapFrame.Create doesn't exist either. – Developer May 04 '16 at 10:50
  • Include `using System.Windows.Media.Imaging;` that's the namespace where those classes are. – Manfred Radlwimmer May 04 '16 at 10:51
  • using System.Windows.Media doesn't exist. Is this for UWP8.1? i'm making a app for windows universal 10. – Developer May 04 '16 at 10:53
  • 1
    Oh, yeah WU10 is based on WinRT i guess so this might be a bit more complicated than in the backend. The encoder is not included afaik, but this framework has a way to do it: http://winrtxamltoolkit.codeplex.com/SourceControl/changeset/view/0657c67a93d5#WinRTXamlToolkit/Imaging/WriteableBitmapSaveExtensions.cs – Manfred Radlwimmer May 04 '16 at 10:59
  • It seems this one is writing it to file first. Not really what i wanted as i already have the image. Is there a way i can do this from my existing image? – Developer May 04 '16 at 11:05
  • Sure, you just need to adapt the part at the bottom of the file. Instead of writing it into a filestream, you could just save the image to a memorystream and call ToArray() to get the encoded image as a byte array – Manfred Radlwimmer May 04 '16 at 11:22
  • i added my latest attempt. it doesn't work. The byte[] is still the same. – Developer May 04 '16 at 12:39