JLION.COM - Create or modify an image on-the-fly
06/25/06 ASP.NET, Images, VB.NET

Create or modify an image on-the-fly

A few months ago a friend mentioned a problem that he was having with one of his sites. He wanted to prevent visitors to the site from copying his images. I told him that this was pretty easy to do with Dot Net -- "but there's a problem," he told me -- "My site is an ASP classic site and I don't have the time to convert it right now."

Still no problem, I thought. When I want to include an image generated in real time in a web site, I create an ASPX page that returns the image as a stream. I then use the <IMG SRC> tag to reference it. I told my friend that I would create an ASP.NET page that he could reference from his ASP site.

When I looked into what he was doing in greater depth, I found that he had done something on the site that was pretty neat. He had created generic picture frame images that could be used to surround any image. He did this by scanning pictures of picture frames then creating eight JPG images for each picture frame, as shown here:

upper left corner upper middle upper right corner
left middle right middle
lower left corner lower middle lower right corner

One JPG image represents each frame corner. These are not stretched. Four additional JPG images are used for the horizontal and vertical parts of the frame and these are stretched to fit the framed image. It works wonderfully. He was determining the dimensions of each frame component by hand for each image on his site that he wished to frame. I offered to have the web page add both a frame and a watermark to the image that he passed to it.

A few hours later, I had the code shown below. This code can be used to display any GIF or JPG image in one of three frame types, with a watermark across the center of the image. To use the code, place it in an ASPX page then reference the page from an <IMG SRC> tag. Pass the URL of the image in the query string as "U" and the type of frame to use as "M", where "simple-light brown" = 0, "Barn" = 1, or "Gold/Silver" = 2.

Many thanks to Ted Tyree for sharing the frame technique and graphics with me.

A sample image:
Unframed image

Now, the same image with a frame and watermark:
Framed image

Here's the code:
Imports System.Drawing
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Uri
Imports System.Net

Partial Class Tools_PictureFrame
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'Put user code to initialize the page here

        Dim sURLOfImageToBeFramed As String = Request.QueryString("U")
        Dim iFrameType As String = Val(Request.QueryString("M"))

        'Get the picture image
        Dim oPicture As Image = GetImage(sURLOfImageToBeFramed)

        '---Frame parts

        Dim oTL As Image
        Dim oML As Image
        Dim oBL As Image

        Dim oTM As Image
        Dim oBM As Image

        Dim oTR As Image
        Dim oMR As Image
        Dim oBR As Image

        Dim sFrameName() As String = {"Simple-LightBrown1", "Barn2", "GoldSilver1"}

        'Get the frame parts
        Dim sURLBase As String = "HTTP://www.jlion.com/images/frames/"

        oTL = GetImage(sURLBase & sFrameName(iFrameType) & "-TL.jpg")
        oML = GetImage(sURLBase & sFrameName(iFrameType) & "-ML.jpg")
        oBL = GetImage(sURLBase & sFrameName(iFrameType) & "-BL.jpg")

        oTM = GetImage(sURLBase & sFrameName(iFrameType) & "-TM.jpg")
        oBM = GetImage(sURLBase & sFrameName(iFrameType) & "-BM.jpg")

        oTR = GetImage(sURLBase & sFrameName(iFrameType) & "-TR.jpg")
        oMR = GetImage(sURLBase & sFrameName(iFrameType) & "-MR.jpg")
        oBR = GetImage(sURLBase & sFrameName(iFrameType) & "-BR.jpg")

        'New image that consists of original picture + frame

        '---How big does it need to be?
        Dim iFrameHeight As Integer = oPicture.Height
        Dim iFrameWidth As Integer = oPicture.Width

        Dim iWidth As Integer = oTL.Width + iFrameWidth + oTR.Width
        Dim iHeight As Integer = oTM.Height + iFrameHeight + oBM.Height

        '---Create new image for composite
        Dim oFramedImage As Bitmap = New Bitmap(iWidth, iHeight, PixelFormat.Format24bppRgb)

        '---Paste in the parts
        Dim oG As Graphics = Graphics.FromImage(oFramedImage)

        '---Initialize graphic
        oG.FillRectangle(New SolidBrush(Color.White), New Rectangle(0, 0, iWidth, iHeight))

        '---Draw picture
        oG.DrawImage(oPicture, oML.Width, oTM.Height, oPicture.Width, oPicture.Height)

        '---Draw frame edges

        '---Left side
        oG.DrawImage(image:=oML, x:=0, y:=0, width:=oML.Width, height:=iHeight)

        '---Right side
        oG.DrawImage(image:=oMR, x:=iWidth - oMR.Width, y:=0, width:=oMR.Width, height:=iHeight)

        oG.DrawImage(image:=oTM, x:=oTL.Width, y:=0, width:=iWidth, height:=oTM.Height)

        oG.DrawImage(image:=oBM, x:=0, y:=iHeight - oBM.Height, width:=iWidth, height:=oBM.Height)

        '---Draw frame corners

        '---Upper Left
        oG.DrawImage(image:=oTL, x:=0, y:=0, width:=oTL.Width, height:=oTL.Height)

        '---Lower left
        oG.DrawImage(image:=oBL, x:=0, y:=iHeight - oBL.Height, width:=oBL.Width, height:=oBL.Height)

        '---Upper right
        oG.DrawImage(image:=oTR, x:=iWidth - oTR.Width, y:=0, width:=oTR.Width, height:=oTR.Height)

        '---Lower right
        oG.DrawImage(image:=oBR, x:=iWidth - oBR.Width, y:=iHeight - oBR.Height, width:=oBR.Width, height:=oBR.Height)

        '---Write out watermark text.
        DrawText( _
            oG, _
            iFrameWidth + 2 * oML.Width, _
            iFrameHeight + 2 * oTM.Height, _
            14, _

        Response.ContentType = "image/JPEG"
        oFramedImage.Save(Response.OutputStream, ImageFormat.Jpeg)


    End Sub

    Private Function GetImage(ByVal sURL As String) As Image
        'Get the image
        Dim oBase As New Uri(URLtoBase(sURL))
        Dim oImage As New Uri(oBase, sURL)
        Dim oRequest As WebRequest = WebRequest.Create(oImage)
        Dim oResponse As WebResponse = oRequest.GetResponse()
        Dim oPicture As Image = Bitmap.FromStream(oResponse.GetResponseStream())


        Return oPicture
    End Function

    Private Function URLtoBase(ByVal sURL As String) As String
        Dim iLastSlash As Integer = 0

        If InStr(1, sURL, "http://", CompareMethod.Text) = 1 Then
            If Len(sURL) > 8 Then
                iLastSlash = InStr(8, sURL, "/", CompareMethod.Text)
            End If

            iLastSlash = InStr(1, sURL, "/", CompareMethod.Text)
        End If

        Dim sResult As String = ""

        If iLastSlash > 0 Then
            sResult = Left$(sURL, iLastSlash)
        End If

        Return sResult
    End Function

    Private Sub DrawText( _
        ByRef oGraphic As Graphics, _
        ByVal iImageWidth As Integer, _
        ByVal iImageHeight As Integer, _
        ByVal iFontSize As Integer, _
        ByVal sText As String)

        Dim whiteBrush As New SolidBrush(Color.White)
        Dim FontBrush As New System.Drawing.SolidBrush(Color.Gray)

        Dim fFont As New Font("Arial", iFontSize, FontStyle.Bold)

        Dim oStringSize As New SizeF
        oStringSize = oGraphic.MeasureString(sText, fFont)

        Dim iX As Integer = iImageWidth / 2 - oStringSize.Width / 2
        Dim iY As Integer = iImageHeight / 2 - oStringSize.Height / 2

        oGraphic.DrawString(sText, _
                              fFont, _
                              FontBrush, _
                              iX, iY, _

     End Sub

End Class