Can I convert image/bitmap to writeablebitmap?

14,500

Here I am giving you the code to merge two images. WinRT's WriteableBitmap is different, the constructor of it takes height and width as argument. I have used WriteableBitmapEx for some functions.

XAML

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Canvas x:Name="BaseCanvas" Width="683" Height="768">
        <Image Source="Assets/img1.png" />
        <Image Source="Assets/img2.png" Canvas.Top="308" />
    </Canvas>
    <Image x:Name="imgTarget" Grid.Column="1" Stretch="None"/>
</Grid>

C#

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    StorageFile destiFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("Merged.png", CreationCollisionOption.ReplaceExisting);

    WriteableBitmap wb;

    wb = await Render();

    using (IRandomAccessStream stream = await destiFile.OpenAsync(FileAccessMode.ReadWrite))
    {
        BitmapEncoder encoder = await BitmapEncoder.CreateAsync(
            BitmapEncoder.PngEncoderId, stream);
        Stream pixelStream = wb.PixelBuffer.AsStream();
        byte[] pixels = new byte[pixelStream.Length];
        await pixelStream.ReadAsync(pixels, 0, pixels.Length);

        encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore,
            (uint)wb.PixelWidth, (uint)wb.PixelHeight, 96.0, 96.0, pixels);
        await encoder.FlushAsync();
    }

    var bitmp = new BitmapImage();
    using (var strm = await destiFile.OpenReadAsync())
    {
        bitmp.SetSource(strm);
        imgTarget.Source = bitmp;
    }
}

private async Task<WriteableBitmap> Render()
{
    var Assets = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync("Assets");

    StorageFile file1 = await Assets.GetFileAsync("img1.png");
    StorageFile file2 = await Assets.GetFileAsync("img2.png");

    BitmapImage i1 = new BitmapImage();
    BitmapImage i2 = new BitmapImage();

    using (IRandomAccessStream strm = await file1.OpenReadAsync())
    {
        i1.SetSource(strm);
    }

    using (IRandomAccessStream strm = await file2.OpenReadAsync())
    {
        i2.SetSource(strm);
    }

    WriteableBitmap img1 = new WriteableBitmap(i1.PixelWidth, i1.PixelHeight);
    WriteableBitmap img2 = new WriteableBitmap(i2.PixelWidth, i2.PixelHeight);
    using (IRandomAccessStream strm = await file1.OpenReadAsync())
    {
        img1.SetSource(strm);
    }

    using (IRandomAccessStream strm = await file2.OpenReadAsync())
    {
        img2.SetSource(strm);
    }


    WriteableBitmap destination = new WriteableBitmap((int)(img1.PixelWidth > img2.PixelWidth ? img1.PixelWidth : img2.PixelWidth), (int)(img1.PixelHeight + img1.PixelHeight));
    destination.Clear(Colors.White);
    destination.Blit(new Rect(0, 0, (int)img1.PixelWidth, (int)img1.PixelHeight),img1,new Rect(0, 0, (int)img1.PixelWidth, (int)img1.PixelHeight));
    destination.Blit(new Rect(0, (int)img1.PixelHeight, (int)img2.PixelWidth, (int)img2.PixelHeight), img2, new Rect(0, 0, (int)img2.PixelWidth, (int)img2.PixelHeight));
    return destination;
}

Please note you have to add System.Runtime.InteropServices.WindowsRuntime namespace.

UPDATE 1

Suppose if you have already two BitmapImage img1 and img2, then do like this

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    StorageFile destiFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("Merged.png", CreationCollisionOption.ReplaceExisting);

    WriteableBitmap wb;

    wb = await Render();

    using (IRandomAccessStream stream = await destiFile.OpenAsync(FileAccessMode.ReadWrite))
    {
        BitmapEncoder encoder = await BitmapEncoder.CreateAsync(
            BitmapEncoder.PngEncoderId, stream);
        Stream pixelStream = wb.PixelBuffer.AsStream();
        byte[] pixels = new byte[pixelStream.Length];
        await pixelStream.ReadAsync(pixels, 0, pixels.Length);

        encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore,
            (uint)wb.PixelWidth, (uint)wb.PixelHeight, 96.0, 96.0, pixels);
        await encoder.FlushAsync();
    }

    var bitmp = new BitmapImage();
    using (var strm = await destiFile.OpenReadAsync())
    {
        bitmp.SetSource(strm);
        imgTarget.Source = bitmp;
    }
}

private async Task<WriteableBitmap> Render()
{  
    WriteableBitmap destination = new WriteableBitmap((int)(img1.PixelWidth > img2.PixelWidth ? img1.PixelWidth : img2.PixelWidth), (int)(img1.PixelHeight + img1.PixelHeight));
    destination.Clear(Colors.White);
    destination.Blit(new Rect(0, 0, (int)img1.PixelWidth, (int)img1.PixelHeight),img1,new Rect(0, 0, (int)img1.PixelWidth, (int)img1.PixelHeight));
    destination.Blit(new Rect(0, (int)img1.PixelHeight, (int)img2.PixelWidth, (int)img2.PixelHeight), img2, new Rect(0, 0, (int)img2.PixelWidth, (int)img2.PixelHeight));
    return destination;
}
Share:
14,500
Tehreem
Author by

Tehreem

Updated on July 24, 2022

Comments

  • Tehreem
    Tehreem almost 2 years

    I have two bitmap images that i would like to merge together. I found that I can do that with writeablebitmap but how do I first convert these images to writeablebitmaps?

    UPDATE: I could not find out a way to convert bitmaps to writeable bitmap directly so what I did was to write my bitmap in isolated storage and read it again in a stream object. After which the code given below by Xyroid can be used to merge the images and convert the merged image to bitmap.

  • Tehreem
    Tehreem about 11 years
    I tried this and I am getting these two errors: 1. 'Windows.UI.Xaml.Media.Imaging.WriteableBitmap' is a 'type' but is used like a 'variable' 2. 'Windows.UI.Xaml.Media.Imaging.BitmapSource' is a 'type' but is used like a 'variable'
  • Tehreem
    Tehreem about 11 years
    The constructor you are talking about does not work. I don't know why.. I have already implemented the library you have given me link of.
  • James Wilkins
    James Wilkins about 11 years
    Ok, sorry, it figures that Microsoft would continue down the path of inconsistency. I know it works in Silverlight (also XAML). :/
  • Tehreem
    Tehreem about 11 years
    Thanks you so much for trying to help. I really appreciate that :)
  • Tehreem
    Tehreem about 11 years
    Thankyou so much for this code. It runs perfectly fine. I will be able to achieve what I want with some editing. Thanks again :)
  • Farhan Ghumra
    Farhan Ghumra about 11 years
    Your'e welcome, Tehreem. Please upvote my answer, I will feel glad.
  • Tehreem
    Tehreem about 11 years
    I would have done that without your saying it but I can't yet as I am a new user..
  • Tehreem
    Tehreem about 11 years
    In this example you are getting two images in file1 and file2 from assets folder. While the images I have are already stored in two BitmapImage objects by application. Any idea how can i convert them to writeablebitmap or stream of pixels or byte array?
  • Farhan Ghumra
    Farhan Ghumra about 11 years
    I am creating BitmapImage from StorageFile, so you can skip that part. What are you facing problem ?
  • Tehreem
    Tehreem about 11 years
    If I skip that part how will I convert bitmap to writeable bitmap? i.e. the following lines of code will not work: using (IRandomAccessStream strm = await file1.OpenReadAsync()) { img1.SetSource(strm); }
  • Tehreem
    Tehreem about 11 years
    What is file1 and file2 here?
  • Farhan Ghumra
    Farhan Ghumra about 11 years
    You first tell me how are you getting bitmaps ? What's the source of it ?
  • Tehreem
    Tehreem about 11 years
    I have image controls in my application which get images through some other function. I do not have access to the actual files anymore.
  • Tehreem
    Tehreem about 11 years
    It gives me this error: 'Windows.UI.Xaml.Media.Imaging.WriteableBitmap' does not contain a definition for 'Blit' and the best extension method overload 'Windows.UI.Xaml.Media.Imaging.WriteableBitmapExtensions.Bli‌​t(Windows.UI.Xaml.Me‌​dia.Imaging.Writeabl‌​eBitmap, Windows.Foundation.Rect, Windows.UI.Xaml.Media.Imaging.WriteableBitmap, Windows.Foundation.Rect)' has some invalid arguments
  • Tehreem
    Tehreem about 11 years
    I am giving up on conversion from Bitmap to WriteableBitmap... I think I should save the images in isolated storage when they are rendered the very first time so that I can retrieve them later and simply read them to writeableBitmaps
  • rism
    rism over 9 years
    @Xyroid I have to agree with Tehreem. The code you have supplied makes no sense because the Blit method takes a WritableBitMap as the second positional argument after Rectangle, not a BitMapImage. So for Update 1 when you say "Suppose if you have already two BitmapImage img1 and img2" it won't compile because "Argument type BitMapImage is not assignable to parameter type WritableBitMap". Have you actually tested this code or did you just write it off the cuff? If you have tested then pls advise how you managed to supply BitMapImages to the Blit method as per Update 1? thx
  • rism
    rism over 9 years
    Also note that in your first answer "WriteableBitmap img1" and in the Update 1 "BitMapImage img1. So you've mixed up your types and thus haven't actually answered the question which is why I think Tehreem was confused. He's asked how to convert a BitMapImage to a WritableBitmap and you've given him some code in the first pass to combine two WritableBitMaps into one larger WritableBitMap. That code runs but doesn't answer the question and in the Update 1 which looks like an answer to his question, you've mixed types such that it wont actually compile. Hope Im wrong becos I want to do this too.
  • hellodear
    hellodear over 6 years
    @Xyroid It is really helpful for me. I am stuck a problem which is very similar to the non availability of writablebitmap constructor for UIelement. I have Xaml control image which is created programtically not in UI. How can I convert it in writeablebitmap? Please help.