WinRT: Creating an Image Collage in C#
Posted by: Sumit Maitra
in Category WinRT
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.
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.
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:
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
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.
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.
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.
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.
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 is split up into two steps.
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:
- Open a RandomAccessStream using the file handle provided.
- Create a JpegEncoder
- Convert image into a pixel stream and retrieve a byte array.
- Pass the byte array to the Encoder.
- 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
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
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.
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