DotNetCurry Logo

WinRT: Creating an Image Collage in C#

Posted by: Sumit Maitra , on 9/10/2012, in Category Windows Store Apps
Views: 53034
Abstract: In this post we create a picture collage in a Windows 8 application on the WinRT runtime. We will see how we can stitch together multiple images using the WritableBitmap class.

For my ‘Twittelytics’ twitter client that I introduced in the ‘Free DNC Magazine, Issue 2’ I wanted to do something different from the standard landing pages of the available Twitter clients on Windows 8. I thought it would be cool to stitch together a collage of the avatars from the last few tweets in my timeline.

Collage - is a technique of art production, primarily used in the visual arts, where the artwork is made from an assemblage of different forms, thus creating a new whole. ~ Source Wikipedia

I imagined the process would be straightforward but the fact is I found a couple of gotchas that I was able to overcome eventually. In this post, we will see how we can stitch together a series of images to build a collage. Let’s jump right in.

The Design

We use the blank template for a Windows 8 store application. We will allow the user to pick multiple images and build the collage. The Collage is displayed on the screen. Once the Collage is built, we will allow users to save it as a JPEG in any folder they want to.

 

Implementation

Starting off and XAML

Step 1: Create a new Blank Windows Store Application Project (Visual Studio 2012 RTM)

Step 2: Add a Grid layout with two rows and two columns

Step 3: In the first row, add a TextBlock and Two buttons. The TextBlock has the application label – ‘Collage-ER’. One button is for loading files and the other one is for saving files. Wire up an event handler for each button.

Step 4: In the second row, add an image to span across both columns and occupy the entire width and remaining height of the page. Set the margins such that the image expands for bigger screens.

That’s about all the changes required on the UI. XAML for the view is as follows:

Xaml

 

Now let’s get to the logic.

Building the Collage

The algorithm for building the collage is as follows:

1. Take the number of images in total and get the square root value. That’s the number of rows and columns we will have. For decimal values, we use the “Ceiling” function to fetch the next higher number.

2. Based on the number above and the size of the Collage Image, we calculate the size of each tile in the collage

number-and-size-of-tile

3. Next we load each image from the disk and decode it (from its JPEG/PNG or other encoding) into raw pixels. This involves the following

  • a. Create a RandomAccessStream instance using the file handle
  • b. Initialize a BitmapDecoder from the Image stream. The BitmapDecoder identifies the image type and decodes it. This is still raw data stream.
  • c. After decoding it extracts the data pixel data
  • d. The pixel data has image characteristics like height and width.
  • e. Now we initialize the in-memory Bitmap to the size of the source image and copy the pixels into it.

The code for this is as follows.

decode-tile-and-create-in-memory-bitmap

4. Now resize it into the size of the tile and paste this resized image into the correct (row, col) position of the destination slide.

5. We increment the row/col positions based on the current values. If current column value is == the square root value, then we increment the row (and set column to zero) else we just increment the column. So each tile is placed left to right and top to bottom.

resize-and-paste

Selecting Files for the Collage

We use the Windows.Storage.Pickers.FileOpenPicker object for launching the Windows 8 file select dialog. The new File open dialog is rather cool. For an image folder, it looks as follows.

file-open-dialog

 

You click on a thumbnail to select the file. Clicking on a selected file de-selects it. The code to launch and retrieve the files is as follows.

open-file-dialog-code

In the code above, we have added a filter to show only .jpg files. We also setup the ViewMode as Thumbnail because we know we want to see thumbnails of the images we are picking up. The SuggestedStartLocation is a setting that’s used as a ‘first time’ hint. Once a FilePicker is used, next time around the same location is used as the starting location. We can customize the text of the ‘Open’ button and as we can see, we have set it to “Select for Collage”. Finally the async call to PickMultipleFileAsync() tells the picker to allow selection of multiple files. Once the files have been picked, we call the CreateCollage method that builds the tile for us.

Saving the Collage

   

Saving the collage is split up into two steps.

save-file-code

Step 1: Use the FileSavePicker to pick a file name and location. The picker then returns a File handle.

Step 2: Save the file as follows:

  1. Open a RandomAccessStream using the file handle provided.
  2. Create a JpegEncoder
  3. Convert image into a pixel stream and retrieve a byte array.
  4. Pass the byte array to the Encoder.
  5. Flush the encoder to save to disk.

And that’s a wrap. We were able to load multiple images, resize them in memory and create a collage out of them. We also gave users the option to save the Collage as a Jpeg.

Tricks and Gotchas to be aware of

WriteableBitmapEx

If you are a seasoned Silverlight/XAML dev, the WriteableBitmapEx will make you right at home with the extensions available. If you are a new to WinRT, the extension methods provide hours of time saving when dealing with images in memory. So it’s a must have. Big thanks to the authors of the library. The code is on Codeplex

Hidden Extensions

Some WinRT streaming extensions are hidden in the System.Runtime.InteropServices.WindowsRuntime; namespace. Don’t forget to include it when dealing with Buffers and Stream conversions. In our case, the PixelBuffer.AsStream() conversion wouldn’t be possible if we didn’t include this extension.

Conclusion

Aim of the article was to introduce basic image manipulation in WinRT. We have learnt how to load, save, resize and blit (combining two pixels one over the other) multiple images.

Along the way we discovered the WriteableBitmapEx library and some other useful extensions.

You can download the code at https://github.com/dotnetcurry/CollageER

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Author
Sumit is a .NET consultant and has been working on Microsoft Technologies since his college days. He edits, he codes and he manages content when at work. C# is his first love, but he is often seen flirting with Java and Objective C. You can follow him on twitter at @sumitkm or email him at sumitkm [at] gmail


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by Guiterman on Tuesday, September 18, 2012 3:14 AM
Nice tutorials you got here. For a metro style lightweight image processing api check this

http://code.msdn.microsoft.com/windowsdesktop/Metro-Style-lightweight-24589f50
Comment posted by Sumit on Wednesday, September 19, 2012 3:51 PM
Thanks Guiterman,

That is indeed a very nice sample application.

Regards,
Sumit.
Comment posted by Rin on Monday, October 22, 2012 1:19 PM
That's really cool...can i reach sumit if i need any help in .net in his mail id?
Comment posted by Suprotim Agarwal on Monday, October 22, 2012 3:57 PM
@Rin: If you have a twitter account, ping him at @sumitkm, else use the Contact Page http://www.dotnetcurry.com/Contact.aspx
Comment posted by Rin on Monday, November 12, 2012 3:40 PM
If model = 65 Then
            Call RRVBGRID65(NDATA, IOKey(1), DATAA(1), NX, IOkeyX, X(1), NY, IOkeyY, Iokeyd, ymin, ymax, nIOreq, IOreq(1), w(0, 0, 0), iw(1), IX, IY, status)
        ElseIf model = 67 Then
            Call RRVBGRID67(NDATA, IOKey(1), DATAA(1), NX, IOkeyX, X(1), NY, IOkeyY, Iokeyd, ymin, ymax, nIOreq, IOreq(1), w(0, 0, 0), iw(1), IX, IY, status)
        End If


In the above code , i am trying to get parameters from Fortran dll. The call is proper and i am getting proper parameters till W(0,0,0). In W(0,0,0) the value is not fetched properly as its a 3 dimensional array and Fortran and .net has a different mode of handling 3 dimensional arrays. Please help me out so that i can get the values in .net without touching the fortran dll.
Comment posted by Rin on Tuesday, November 13, 2012 12:02 PM
Please help me with the above code asap
Comment posted by Mihaela on Tuesday, April 2, 2013 9:37 AM
Hello. I downloaded the code but I get the following error
"An exception of type 'System.ArgumentException' occurred in mscorlib.dll but was not handled in user code

WinRT information: pixelWidth

Additional information: The parameter is incorrect.

If there is a handler for this exception, the program may be safely continued."
I haven't modified anything and I have the WriteableBitmapEx library. Can you help me?
Thanks,
Mihaela

Comment posted by Sumit on Tuesday, April 23, 2013 9:39 AM
Hi Mihaela,

I just downloaded the Zip from GitHub, did a clean build, ran the application, selected a bunch of images and Created a collage. Didn't have any issues.
What image types are you selecting? I've not checked for all image types so the image type jpeg/png/bmp/gif could be causing the issue.

Thanks and Regards,
Sumit.
Comment posted by sheat on Monday, July 15, 2013 4:10 PM
We cannot copy, it's a fucking sheat!
Comment posted by Sumit on Saturday, July 20, 2013 10:01 AM
Dear Sheat,
To 'copy' click on the link at the bottom of the article to navigate to Github. Now if you want the entire code to copy, download the Zip, if you want to copy parts of code, feel free to walk around the excellent code browser in GitHub and 'copy' to your heart's content!