Hackathon #1: Composite Image

My company recently had a Hackathon day, where the IT dept. was split into teams and had one day to develop something amazing to present to a panel of judges.

Over the next couple of posts I’d like to just show some things that my team hacked together, as I found them quite interesting, if not amazingly applicable to a real-world app!

First up is a very quick hack I created to generate a composite image on the fly given several other images. Apologies that this is in vb.net and not C#, but I was forced to work within our legacy environment! Assumption: all images to composite are of the same dimensions

Here is a function to take an arraylist of image URLs, merge them, and return the byte array:

Public Function BuildMergedImage(ByVal imgsToMerge As ArrayList) As Byte()

    'build image array, loading each image from a stream into the image array
    Dim imagesToMerge As ArrayList = New ArrayList
    Dim webClient As System.Net.WebClient = New System.Net.WebClient()
    Dim imgStream As Stream

    For Each imgToMerge As String In imgsToMerge
        imgStream = webClient.OpenRead(imgToMerge.ToString())
        imagesToMerge.Add(System.Drawing.Image.FromStream(imgStream))
    Next

    'get composite dimensions
    Dim height As Integer = CType(imagesToMerge(0), System.Drawing.Image).Height
    Dim width As Integer = (CType(imagesToMerge(0), System.Drawing.Image).Width * imagesToMerge.Count())

    'init composite image
    Dim mergedImage As Bitmap = New Bitmap(width, height)
    Dim g As Graphics = Graphics.FromImage(mergedImage)

    'create composite image
    For i As Integer = 0 To (imagesToMerge.Count() - 1)
        g.DrawImage(imagesToMerge(i), (CType(imagesToMerge(i), System.Drawing.Image).Width * i), 0)
    Next

    'save merged image to mem stream
    Dim imgMemStream As New System.IO.MemoryStream
    mergedImage.Save(imgMemStream, ImageFormat.Jpeg)

    'convert stream to byte array
    Dim bytes(imgMemStream.Length() - 1) As Byte
    imgMemStream.Position = 0
    imgMemStream.Read(bytes, 0, bytes.Length)
    imgMemStream.Close()

    'return byte array
    Return bytes
End Function

Then to use this method, build up a string arraylist of image urls, pass it to a new function, and output the returned byte array to the response buffer (I used mine in the Page Load, hence the obligatory postback check):

If Not IsPostBack Then
    Response.Buffer = True
    Response.ContentType = "image/jpeg" 'match to the imageformat in the composite image function
    Response.BinaryWrite(BuildMergedImage(taggedImg))
End If

You’ll need these at the top of your file to get it working though. I realise the “option strict off” is a horrid hack, but it was for a hackathon..

Option Strict Off

Imports System.IO
Imports System.Drawing.Imaging

Bit random, I know, but I found it quite interesting. Have a go with something similar to (but hopefully cleaner than) this:

Dim imageArrayList As ArrayList = new ArrayList

For Each imageUrl As String In Request.QueryString("i").Split(CChar("-"))
    If Not IsNothing(imageUrl) AndAlso Not String.IsNullOrEmpty(imageUrl) Then
        imageArrayList.Add(imageUrl)
    End If
Next

If Not IsPostBack Then
    Response.Buffer = True
    Response.ContentType = "image/jpeg" 'match to the imageformat in the composite image function
    Response.BinaryWrite(BuildMergedImage(imageArrayList))
End If

Example usage (although in this example it’s not pulling the correct dimensions through, which is odd):

http://localhost/combinedimages.aspx?i=http://www.docdatastorage.co.uk/Live/flyfiftythree/ProductImages/savage_white_1_medium.jpg-http://www.docdatastorage.co.uk/Live/flyfiftythree/ProductImages/checkit_green_1_medium.jpg-http://www.docdatastorage.co.uk/Live/flyfiftythree/ProductImages/telemaniacs_navy_1_medium.jpg