Chapter 5: Drawing & Typing


5.1 Canvas Object

AspJpeg 1.2+ offers the Canvas property, which returns an instance of the Canvas object associated with the image. The Canvas object offers a variety of methods, such as PrintText and DrawCircle, that enable you to programmatically write text and draw geometric figures over an image.

Various drawing parameters such as text sizes, fonts, colors, pens, brushes, etc., are specified via Canvas's 2nd-level objects Font, Pen, and Brush.

The following code snippet demonstrates the usage of this hierarchy of objects:

Set Jpeg = Server.CreateObject("Persits.Jpeg")

Jpeg.Canvas.Font.Color = &HFF0000
Jpeg.Canvas.Font.Family = "Courier New"

Jpeg.Canvas.Pen.Color = &H000000
Jpeg.Canvas.Pen.Width = 2

Jpeg.Canvas.Brush.Solid = False

Jpeg.Canvas.PrintText 10, 10, "Some Text"
Jpeg.Canvas.DrawBar 1, 1, 100, 100


5.2 Drawing Graphics and Text

The following code sample prints the text "Copyright (c) XYZ, Inc." on an image in red color and Courier New font (default size 24) in the lower-left corner. It also draws a 2-pixel-wide black frame around the image. The font quality is set to 4 (antialiased) and background mode to "Opaque" to make antialiasing work properly.

Set Jpeg = Server.CreateObject("Persits.Jpeg")

' Open source image
Jpeg.Open Server.MapPath("../images/dodge_viper.jpg")

' Resizing is optional. None in this code sample.

' Draw text

Jpeg.Canvas.Font.Color = &HFF0000 ' Red
Jpeg.Canvas.Font.Family = "Courier New"
Jpeg.Canvas.Font.Bold = True
Jpeg.Canvas.Font.Quality = 4 ' Antialiased
Jpeg.Canvas.Font.BkMode = "Opaque" ' to make antialiasing work
Jpeg.Canvas.Print 10, 572, "Copyright (c) XYZ, Inc."

' Draw frame: black, 2-pixel width
Jpeg.Canvas.Pen.Color = &H000000 ' Black
Jpeg.Canvas.Pen.Width = 2
Jpeg.Canvas.Brush.Solid = False ' or a solid bar would be drawn
Jpeg.Canvas.DrawBar 1, 1, Jpeg.Width, Jpeg.Height

Jpeg.Save Server.MapPath("dodge_viper_framed.jpg")
ASPJPEGLib.IASPJpeg objJpeg;
objJpeg = new ASPJPEGLib.ASPJpeg();

// Compute path to source image
String strPath = Server.MapPath("../images/dodge_viper.jpg");

// Open source image
objJpeg.Open( strPath );

// Resizing is optional. None in this code sample.

// Draw text
objJpeg.Canvas.Font.Color = 0xFF0000; // red
objJpeg.Canvas.Font.Family = "Courier New";
objJpeg.Canvas.Font.Bold = 1; // True
objJpeg.Canvas.Font.Quality = 4; // Antialiased
objJpeg.Canvas.Font.BkMode = "Opaque"; // For antialiasing work
objJpeg.Canvas.Print( 10, 572, "Copyright (c) XYZ, Inc.", Missing.Value );

// Draw frame: black, 2-pixel width
objJpeg.Canvas.Pen.Color = 0x000000; // Black
objJpeg.Canvas.Pen.Width = 2;
objJpeg.Canvas.Brush.Solid = 0; // false, to avoid solid bar
objJpeg.Canvas.DrawBar( 1, 1, objJpeg.Width, objJpeg.Height );

objJpeg.Save( Server.MapPath("dodge_viper_framed.jpg") );

FramedImage.Src = "dodge_viper_framed.jpg";

Click the links below to run this code sample:

5.3 Advanced Text Drawing with PrintTextEx

Starting with Version 1.8, AspJpeg provides a more versatile method for text drawing than PrintText. The new method, PrintTextEx, uses the FreeType™ open-source library to produce high-quality anti-aliased text rendering on any background, in any color and size, and at any angle. PrintTextEx offers the following new features:

  • Text rendering with PrintTextEx is always anti-aliased regardless of background. Font.Quality and Font.BkMode properties are ignored. (the old PrintText requires the background to be solid for anti-aliasing to work.)
  • The font to be used is specified via a physical path. Therefore, the font does not have to be properly registered on the machine as long as a path to the font file is known. Both TrueType/OpenType and Type 1 fonts are supported.
  • Automatic word wrapping. CR/LF characters can be used in the text string for hard line breaks.
  • Text alignment to the left, right, center, and justified.
  • Adjustable opacity for image watermarking.
  • Text can be rotated around the origin.
  • For multi-line text, line spacing can be adjusted.
  • The method returns the width of the string being drawn, and the height of the text paragraph (the latter via a separare property Canvas.ParagraphHeight.)

PrintTextEx expects 4 parameters: the Unicode text string to draw, the x and y coordinates, and the physical path to a TrueType/OpenType or Type 1 font to draw it with. The coordinates specify the position of the lower-left corner of the first character of the first line of text to be drawn, in the image coordinate system. Text size (in pixels) and color are specified via Font.Size and Font.Color properties, respectively. For example:

Jpeg.Canvas.Font.Size = 20
Jpeg.Canvas.Font.Color = &HFFFF0000 'Red
Jpeg.Canvas.PrintTextEx "ABC", 10, 50, "c:\Windows\Fonts\Arial.ttf"

If the location of the Windows directory is not known in advance, the property Jpeg.WindowsDirectory (added in Version 1.8) should be used, so the last line may be rewritten as follows:

Jpeg.Canvas.PrintTextEx "ABC", 10, 50, Jpeg.WindowsDirectory & "\Fonts\Arial.ttf"

As mentioned above, PrintTextEx supports automatic word wrapping. This functionality is enabled by setting the property Font.Width to a non-zero value (in pixels). The text to be drawn can also contain CR/LF characters for hard line breaks.

If Font.Width is specified, text alignment can also be specified via Font.Align. The supported values are 0 (left, default), 1 (right), 2 (center) and 3 (justified). You can also adjust the distance (in pixels) between the lines via Font.Spacing. A positive value increases the default line spacing, a negative one decreases it.

The justified text on the image below was produced by the following code snippet:

Text = "There is some confusion about the number of ..."
jpeg.Canvas.Font.Color = &HFFFFFFFF ' white
jpeg.Canvas.Font.Align = 3 'justify
jpeg.Canvas.Font.Width = 300
jpeg.Canvas.Font.Size = 15
jpeg.Canvas.Font.Spacing = 2
jpeg.Canvas.PrintTextEx Text, 210, 160, "c:\Windows\Fonts\Arial.ttf"

For image watermarking purposes, text opacity can be modified by setting the Font.Opacity property to a value between 0 (fully transparent) and 1 (fully opaque). The image below was created via the following code:

Text = "Copyright © 2007 John Smith Stock Photography, Inc."
jpeg.Canvas.Font.Size = 18
jpeg.Canvas.Font.Opacity = 0.5
jpeg.Canvas.PrintTextEx Text, 160, 230, "c:\Windows\Fonts\Arial.ttf"

Text rotation is activated by setting the Font.Rotation property (in degrees). Text is rotated around the point specified by the x and y coordinates described above. A positive Rotation value produces a counter-clockwise rotation.

As of Version 2.1, PrintTextEx also supports text underlining. To enable this feature, set the property Font.Underlining to True. The width and color of the line used for the underlining are specified via the properties Pen.Width and Pen.Color, respectively.

PrintTextEx returns the width of the text string being drawn (in pixels) or, in case of multi-line text, the width of the longest line in the paragraph. Starting with version 1.9, the height of the text paragraph rendered by the most recent call to PrintTextEx can be obtained from the read-only property Canvas.ParagraphHeight.

The following code sample displays a text string in a round-about manner.

' Directory with images
Path = Server.MapPath("../images")

Set Jpeg = Server.CreateObject("Persits.Jpeg")

' Font path
FontPath = Jpeg.WindowsDirectory & "\fonts\courbd.ttf"

Jpeg.Open Path & "\apple.jpg"

' Text to draw

Jpeg.Canvas.Font.Color = &HFFFFFF00
Jpeg.Canvas.Font.Size = 60

' Draw letters in a round-about manner
Angle = -275
For i = 1 To Len(Txt)
  x = 280 * cos( Angle * 3.141592 / 180 ) + Jpeg.Width / 2
  y = 280 * sin( Angle * 3.141592 / 180 ) + Jpeg.Height / 2
  Jpeg.Canvas.Font.Rotation = 270 - Angle
  w = Jpeg.Canvas.PrintTextEx(Mid(txt, i, 1), x, y, FontPath)
  Angle = Angle + w / 3.85

Jpeg.Save Server.MapPath("text.jpg")
<%@ Import Namespace="System.Web" %>
<%@ Import Namespace="System.Reflection" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="ASPJPEGLib" %>

// Source directory with images
String strPath = Server.MapPath("../images");

IASPJpeg objJpeg;
objJpeg = new ASPJpeg();

// Font path
String strFontPath = objJpeg.WindowsDirectory + "\\fonts\\courbd.ttf";

objJpeg.Open( strPath + "\\apple.jpg" );

// Text to draw

objJpeg.Canvas.Font.Color = 0xFFFF00;
objJpeg.Canvas.Font.Size = 60;

// Draw letters in a round-about manner
double fAngle = -275;
for( int i = 0; i < strTxt.Length; i++ )
  int x = (int)(280 * Math.Cos( fAngle * Math.PI / 180.0 ) + objJpeg.Width / 2);
  int y = (int)(280 * Math.Sin( fAngle * Math.PI / 180.0 ) + objJpeg.Height / 2);
  objJpeg.Canvas.Font.Rotation = 270 - (int)fAngle;
  float w = objJpeg.Canvas.PrintTextEx( strTxt.Substring(i, 1), (int)x, (int)y, strFontPath );
  fAngle = fAngle + w / 3.85;

objJpeg.Save( Server.MapPath("text.jpg") );

TextImage.Src = "text.jpg";

Click the links below to run this code sample:

5.4 Anti-aliased Drawing Routines

As of Version 2.1, AspJpeg offers several drawing routines with anti-aliasing (smooth-edging) support. These routines, all part of the Canvas object, are:

  • DrawLineEx

  • FillPolyEx

  • DrawPolyEx

  • FillEllipseEx
  • In addition to smooth edging, these routines also support partial transparency.

    The usage of DrawLineEx method is almost identical to that of DrawLine except it is also subject to the Pen.Opacity property which specifies the line's opacity.

    The FillPolyEx method fills a polygon defined by multiple points using the current brush. To specify a path of points, the methods MoveTo and LineTo should be used. To clear the current path, use the ClearPath method. MoveTo clears the existing path and starts a new path.

    The following code snippet fills a red semi-transparent 5-point polygon:

    Jpeg.Canvas.Brush.Color = &HFFFF0000' red
    Jpeg.Canvas.Brush.Opacity = 0.5
    Jpeg.Canvas.MoveTo 100, 60
    Jpeg.Canvas.LineTo 306, 600
    Jpeg.Canvas.LineTo 512, 60
    Jpeg.Canvas.LineTo 20, 400
    Jpeg.Canvas.LineTo 592, 400

    The DrawPolyEx method strokes (but does not fill) a polygon using the current pen. The usage of this method is exactly the same as with FillPolyEx.

    The FillEllipseEx fills an ellipse or circle or, optionally, a sector (slice) of an ellipse or circle using the current brush. Its arguments are: the coordinates of the center, horizontal and vertical radii, and the start and end angles (in degrees) of the sector, if applicable. If the last two arguments are 0, a full ellipse or circle is drawn.

    The yellow "pacman" shape on the image above is drawn using the following script:

    Jpeg.Canvas.Brush.color = &HFFFFE000
    Jpeg.Canvas.Brush.Opacity = 0.7
    Jpeg.Canvas.FillEllipseEx 200, 100, 70, 70, 34, 340