Dynamically Add Text to Images Retrieved from the Database using an ASP.NET Http Handler
We often create applications where we retrieve images from the database and display it on the page. At times, we may need to add some text or a copyright notice dynamically on the images. This article discusses how to do so using an ASP.NET Http Handler.
We will be using the data from the Employees table of the Northwind database since it contains images.
Note: I am using Visual Studio 2008 and I have targeted the application to use .NET 3.5
Step 1: Open VS 2008. Click File > New > Website. Choose ASP.NET Website from the list of installed template, choose target platform as .NET Framework 3.5, choose the desired language and enter the location where you would like to store the website on your FileSystem. I have created a folder called VS2008 Projects, so the location over here is C:\VS2008 Projects\AddTextToImages. After typing the location, click OK.
Step 2: Since we are retrieving the images from the database, we would need a connection string. Add the following connection string to your web.config
<connectionStrings>
<add name="NorthwindConnectionString" connectionString="Data Source=(local);Initial Catalog=Northwind;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
Step 3: We will be using an HttpHandler to pull images and then add some text to the retrieved images. I just love using handlers to handle scenarios like these as they provide me with a lot of flexibility while accessing server-side resources. To create an Http handler, right click project > Add New Item > Generic Handler > TextOnImageHandler.ashx. Add the following code to the handler.
C#
<%@ WebHandler Language="C#" Class="TextOnImageHandler" %>
using System;
using System.Web;
using System.Drawing;
using System.Configuration;
using System.ComponentModel;
using System.Drawing.Imaging;
using System.Data;
using System.Data.SqlClient;
public class TextOnImageHandler : IHttpHandler {
byte[] empPic = null;
long seq = 0;
public void ProcessRequest(HttpContext context)
{
Int32 empno;
if (context.Request.QueryString["id"] != null)
empno = Convert.ToInt32(context.Request.QueryString["id"]);
else
throw new ArgumentException("No parameter specified");
// Convert Byte[] to Bitmap
Bitmap newBmp = ConvertToBitmap(ShowEmpImage(empno));
// Watermark Text to be added to image
string text = "Code from dotnetcurry";
if(newBmp != null)
{
Bitmap convBmp = AddTextToImage(newBmp, text);
convBmp.Save(context.Response.OutputStream, ImageFormat.Jpeg);
convBmp.Dispose();
}
newBmp.Dispose();
}
// Add Watermark Text to Image
protected Bitmap AddTextToImage(Bitmap bImg, string msg)
{
// To void the error due to Indexed Pixel Format
Image img = new Bitmap(bImg, new Size(bImg.Width, bImg.Height));
Bitmap tmp = new Bitmap(img);
Graphics graphic = Graphics.FromImage(tmp);
// Watermark effect
SolidBrush brush = new SolidBrush(Color.FromArgb(120, 255, 255, 255));
// Draw the text string to the Graphics object at a given position.
graphic.DrawString(msg, new Font("Times New Roman", 14, FontStyle.Italic),
brush, new PointF(10, 30));
graphic.Dispose();
return tmp;
}
// Convert byte array to Bitmap (byte[] to Bitmap)
protected Bitmap ConvertToBitmap(byte[] bmp)
{
if(bmp != null)
{
TypeConverter tc = TypeDescriptor.GetConverter(typeof(Bitmap));
Bitmap b = (Bitmap)tc.ConvertFrom(bmp);
return b;
}
}
public byte[] ShowEmpImage(int empno)
{
string conn = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
SqlConnection connection = new SqlConnection(conn);
string sql = "SELECT photo FROM Employees WHERE EmployeeID = @ID";
SqlCommand cmd = new SqlCommand(sql, connection);
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("@ID", empno);
connection.Open();
SqlDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
seq = dr.GetBytes(0, 0, null, 0, int.MaxValue) - 1;
empPic = new byte[seq + 1];
dr.GetBytes(0, 0, empPic, 0, Convert.ToInt32(seq));
connection.Close();
}
return empPic;
}
public bool IsReusable
{
get
{
return false;
}
}
}
VB.NET
<%@ WebHandler Language="vb" Class="TextOnImageHandler" %>
Imports System
Imports System.Web
Imports System.Drawing
Imports System.Configuration
Imports System.ComponentModel
Imports System.Drawing.Imaging
Imports System.Data
Imports System.Data.SqlClient
Public Class TextOnImageHandler
Implements IHttpHandler
Private empPic() As Byte = Nothing
Private seq As Long = 0
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim empno As Int32
If context.Request.QueryString("id") IsNot Nothing Then
empno = Convert.ToInt32(context.Request.QueryString("id"))
Else
Throw New ArgumentException("No parameter specified")
End If
' Convert Byte[] to Bitmap
Dim newBmp As Bitmap = ConvertToBitmap(ShowEmpImage(empno))
' Watermark Text to be added to image
Dim text As String = "Code from dotnetcurry"
Dim convBmp As Bitmap = AddTextToImage(newBmp, text)
convBmp.Save(context.Response.OutputStream, ImageFormat.Jpeg)
newBmp.Dispose()
convBmp.Dispose()
End Sub
' Add Watermark Text to Image
Protected Function AddTextToImage(ByVal bImg As Bitmap, ByVal msg As String) As Bitmap
' To void the error due to Indexed Pixel Format
Dim img As Image = New Bitmap(bImg, New Size(bImg.Width, bImg.Height))
Dim tmp As New Bitmap(img)
Dim graphic As Graphics = Graphics.FromImage(tmp)
' Watermark effect
Dim brush As New SolidBrush(Color.FromArgb(120, 255, 255, 255))
' Draw the text string to the Graphics object at a given position.
graphic.DrawString(msg, New Font("Times New Roman", 14, FontStyle.Italic), brush, New PointF(10, 30))
graphic.Dispose()
Return tmp
End Function
' Convert byte array to Bitmap (byte[] to Bitmap)
Protected Function ConvertToBitmap(ByVal bmp() As Byte) As Bitmap
If bmp IsNot Nothing Then
Dim tc As TypeConverter = TypeDescriptor.GetConverter(GetType(Bitmap))
Dim b As Bitmap = CType(tc.ConvertFrom(bmp), Bitmap)
Return b
End If
Return Nothing
End Function
Public Function ShowEmpImage(ByVal empno As Integer) As Byte()
Dim conn As String = ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString
Dim connection As New SqlConnection(conn)
Dim sql As String = "SELECT photo FROM Employees WHERE EmployeeID = @ID"
Dim cmd As New SqlCommand(sql, connection)
cmd.CommandType = CommandType.Text
cmd.Parameters.AddWithValue("@ID", empno)
connection.Open()
Dim dr As SqlDataReader = cmd.ExecuteReader()
If dr.Read() Then
seq = dr.GetBytes(0, 0, Nothing, 0, Integer.MaxValue) - 1
empPic = New Byte(seq){}
dr.GetBytes(0, 0, empPic, 0, Convert.ToInt32(seq))
connection.Close()
End If
Return empPic
End Function
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
The steps for adding some text to the image, using the handler are as follows:
1. The EmployeeID whose image is to be retrieved, is passed to the handler via query string. We use the Request.QueryString[“id”] to retrieve the EmployeeID(emp_id) from the handler url. The ID is then passed to the ‘ShowEmpImage()’ method where the image is fetched from the database using SqlDataReader and returned in a byte[] object.
2. We pass this byte[] to the ConvertToBitmap() function where we use the TypeConverter class to convert a byte array to bitmap.
3. We then pass the bitmap and the text to be written on the Bitmap, to the AddTextToImage() method. If the image has an indexed pixel format, then directly calling the method Graphics.ShowImage() would throw an exception with the message, "A Graphics object cannot be created from an image that has an indexed pixel format”. A workaround is to create a temporary bitmap with the same width and height as that of the original bitmap and then create a new Graphics object from the Image.
4. We then use the Graphics.DrawString() to draw the specified string at the specified location. The watermark effect is achieved using an alpha component of 120 provided in the Color.FromArgb() method.
5. The last step is to save the image to the page's output stream and indicate the image format as shown here convBmp.Save(context.Response.OutputStream, ImageFormat.Jpeg)
You can call this handler in the following way:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Write Text On Image</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<img alt="Image" id="img1" src="TextOnImageHandler.ashx?id=2" />
</div>
</form>
</body>
</html>
The image with the watermark text will look similar to the following (Notice the watermark text 'Code from dotnetcurry'):
The entire source code of the article in C# and VB.NET can be downloaded from here. I hope you liked the article and I thank you for viewing it.
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Suprotim Agarwal, MCSD, MCAD, MCDBA, MCSE, is the founder of
DotNetCurry,
DNC Magazine for Developers,
SQLServerCurry and
DevCurry. He has also authored a couple of books
51 Recipes using jQuery with ASP.NET Controls and
The Absolutely Awesome jQuery CookBook.
Suprotim received the prestigious Microsoft MVP award for 17 consecutive years, until he resigned from the program in 2025. In a professional capacity, he is the CEO of A2Z Knowledge Visuals Pvt Ltd, a digital group that offers Digital Marketing and Branding services to businesses, both in a start-up and enterprise environment.
Get in touch with him on Twitter @suprotimagarwal or at LinkedIn