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'):
No comments:
Post a Comment