Click here to Skip to main content
Click here to Skip to main content

PDF File Writer C# Class Library (Version 1.6)

, 9 Jul 2014
Rate this:
Please Sign up or sign in to vote.
PDF File Writer is a C# class library allowing .NET applications to create PDF files.
Prize winner in Competition "Best overall article of April 2013"
Prize winner in Competition "Best C# article of April 2013"

Article Example

1. Introduction

The PDF File Writer C# class library PdfFileWriter allows you to create PDF files directly from your .net application. The library shields you from the details of the PDF file structure. To use the library you need to: add a reference to the attached PdfFileWriter.dll class library, add a using PdfFileWriter statement in every source file that is using the library and include the PdfFileWriter.dll with your distribution. The PdfFileWriter.dll is only 90 KB long. Considering the small size of the library, you can include the source code of all the classes with your application and avoid the need to distribute a separate data link library file.

Version 1.6 changes: (1) The CreateFile method (step 6 below) resets the PdfDocument to its initial condition after file creation. (2) The PdfFont object releases the unmanaged code resources properly.

Creating a PDF is a six steps process.

  • Step 1: Create one document object PdfDocument.
  • Step 2: Create resource objects such as fonts or images (i.e. PdfFont or PdfImag).
  • Step 3: Create page object PdfPage.
  • Step 4: Create contents object PdfContents.
  • Step 5: Add text and graphics to the contents object (using PdfContents methods).
  • Repeat steps 3, 4 and 5 for additional pages
  • Step 6: Create your PDF document file by calling CreateFile method of PdfDocument.

Step 5 is where most of your programming effort will be spent. Adding contents is achieved by calling the methods of PdfContents class to render graphics and text. The contents class has a rich set (about 100) of methods for adding text and graphics to your document.

After Step 6, PdfDocument is restored to its initial conditions. You can reuse it to create another PDF document.

The demo program attached to this article is the test program developed to debug the library. The Test PDF File Writer TestPdfFileWriter has three buttons on the main screen. Two buttons to produce examples of PDF files and one button to display all fonts available on your computer. The first button “Article Example” creates the PDF file displayed at the top of this document.

The next three paragraphs point out three modules of the source code that can be used in other context.

PDF file is made out of objects. Some of the objects are streams of characters. To reduce PDF file size, streams are compressed by the ZLib Deflate compression method. The source module DeflateMethod.cs is self contained compression class that compresses byte array to byte array. The matching decompression class is available in "PDF File Analyzer With C# Parsing Classes" article. The original source code for both classes is taken from “Processing Standard ZIP Files with C# Compression/Decompression Classes” article by Uzi Granot published in website.

In order to make PDF files be truly portable, font files used in the document can be embedded in the PDF file. Three source modules: PdfFontFile.cs, PdfFontFileClasses.cs, and FontApi.cs have all the code necessary to read Windows font files and embed them in the PDF file. The embedded font file supports only these characters that were actually used in your document. Font files are made of tables. PDF readers only use 10 table types. The embedding process saves only these tables that are used by the PDF readers. Information about OpenType font embedding can be found at Microsoft Typography - OpenType Specification

The .net framework does not support all Windows API related to fonts and glyphs. The source module FontApi.cs allows C# program to access the following APIS: GetCharWidth32, GetGlyphOutline, GetKerningPairs, GetOutlineTextMetrics, GetTextMetrics, GetFontData, GetGlyphIndices, GetLastWin32Error and FormatMessage.

As stated before, the PdfFileWriter C# class library shields you from the complexities of the PDF file structure. However, good understanding of PDF file is always an advantage. Adobe PDF file specification document available from Adobe website: “PDF Reference, Sixth Edition, Adobe Portable Document Format Version 1.7 November 2006”. It is an intimidating 1310 pages document. I would strongly recommend reading Chapter 4 Graphics and sections 5.2 and 5.3 of the Text chapter 5.

If you want to analyze the PDF files created by this project, or if you want to understand PDF file structure in general, you can use the demo program attached to my previous article "PDF File Analyzer With C# Parsing Classes". This article provides a concise overview of the PDF specifications.

2. PDF File Writer Library General Notes

2.1. Coordinate system and Unit of Measure

The PDF coordinate system origin is at the bottom left corner of the page. The X-axis is pointing to the right. The Y-axis is pointing in upward direction.

The PDF unit of measure is points. There are 72 points in one inch. The PDF File writer allows you to select your own unit of measure. All methods arguments representing position, width or height must be in your unit of measure. Font size is the only exception. It is always in points. The PDF File Writer converts all input arguments to points. All internal measurement values and calculations are done with double precision. At the final step when the PDF file is created, the values are converted to text strings. The conversion precision is six digits. The conversion formula used is:

String Result = ((Single) Math.Round(DoubleValue, 6, MidpointRounding.AwayFromZero)).ToString();

2.2. Decimal separator

PDF readers such as Adobe Acrobat expect real numbers with a fraction to use period as the decimal separator. Some of the world regions use other decimal separators such as comma. Since Version 1.1 of the PDF File Writer library will use period as decimal separator regardless of regional setting of your computer.

2.3. Language support, fonts and character sets

The PDF File Writer library is using TrueType fonts. Please note Section 5.5 Simple Fonts of the PDF specifications. TrueType fonts are defined as simple fonts with the property "Glyphs in the font are selected by single-byte character codes obtained from a string that is shown by the text-showing operators.". In other words this library is limited to one byte encoding, 0 to 255. Not all values within this range are available. Control codes 0 to 31 and 128 to 159 are excluded. The result is that this class library supports characters in the range 32 to 126 and 160 to 255. These characters are encoded using WinAnsiEncoding. It is Windows Code Page 1252, often called the “Windows ANSI” encoding. This is the standard Windows encoding for Latin text in Western writing systems.

Most TrueType fonts such as Arial supports character values greater than 255. The PDF File Library allows you to perform a substitution. You can use any Unicode character and map it into the available one byte range. It is performed by CharSubstitution method of the PdfFont class. Two characters within the allowable range: space (32) and non breaking space (160) cannot be replaced.

PdfFont.CharSubstitution(int OriginStart, int OriginEnd, int DestStart);

For example, Unicode Greek low case letters are encoded starting with 945. To use the first 6 letters we will map them to position 161.

ArialNormal = new PdfFont(Document, "Arial", FontStyle.Regular, true);
ArialNormal.CharSubstitution(945, 950, 161);

To print them:

Contents.DrawText(ArialNormal, FontSize, TextPos, BaseLine, "aß?de?");

In versions prior to 1.4, the characters in the text string had to be recalculated. Starting with Version 1.4 you just put the Unicode string as is. If the text string contains characters that were not substituted, the program will fail with exception.

Another example, Unicode Hebrew letters are encoded in a block from 1488 to 1514. To use Hebrew letters we map them again to 161.

ArialNormal.CharSubstitution(1488, 1514, 161);

Hebrew is a right to left language. PDF readers print left to right. If we print in the same way as Greek the result will be reversed string. To get the correct result, the PDF File Writer has a new method PdfContents.ReverseString(String Text).

Contents.DrawText(ArialNormal, FontSize, TextPos, BaseLine, Contents.ReverseString("?????");

The support for right to left languages of this package is limited. You can print single lines. To understand the complexities of Bidi support refer to Unicode Bidirectional Algorithm. You can draw text but you have to remember that PDF prints left to right and text position is to the left of the string by default. Using DrawText with TextJustify.Right option will be more natural for Hebrew.

Contents.DrawText(ArialNormal, FontSize, TextPos, BaseLine, TextJustify.Right, Contents.ReverseString("?????");

The ReverseString method reverses the character order. It does not know the language. In other words you cannot reverse a string that contains the letters of right to left language together with numbers or English words or even brackets ()[]<>{}. Another limitation is TextBox class cannot be used.

2.4. Image File Support

The following code illustrates how to include image file in a PDF document.

// Define image resource object
PdfImage Image = new PdfImage(Document, ImageFileName);

// Set image conversion quality

// Adjust image size in user units making sure aspect ratio of the image is maintained
// Set required resolution for output device in pixels per user unit of measure
SizeD ImageSize = Image.ImageSizeAndDensity(DisplayImageWidth, DisplayImageHeight, Resolution);

// draw image
Contents.DrawImage(Image, ImagePosX, ImagePosY, ImageSize.Width, ImageSize.Height);

Image file type can be any type acceptable to Bitmap class. Most common file types are JPG and PNG. The library always saves the image within the PDF file in jpeg format.

You can control the quality of the image with SetImageQuality method. This method was introduced in Version 1.4. Better quality means larger file. The quality is an integer 0 to 100. Best quality is 100. If SetImageQuality method is not used, the library sets it to 100.

Adjust image size area in user units to maintain the aspect ratio of the image. This can be done with either ImageSize(Double Width, Double Height) method or by ImageSizeAndDensity(Double Width, Double Height, Double Resolution) method (Version 1.4).

Set required resolution for output device in pixels per user unit of measure. If your image is photograph 2304 by 3072 pixels and you want to print it in an area 2" by 2.7" on an inkjet printer with 150 pixels per inch it would make sense to change the resolution of the picture to 300 by 405 pixels. This makes the PDF document file considerably smaller. It is done by specifying resolution as 150.0 in the ImageSizeAndDensity method.

Image quality and density are optional. If not used, the program will copy the image file as is into the output file. You need to experiment with both to find the best compromise between quality and size.

2.5. Barcode

The code below illustrates how to include UPC-A barcode in a PDF document.

// create barcode object
BarcodeEAN13 Barcode = new BarcodeEAN13("123456789010");

// draw the barcode including text under the barcode
Contents.DrawBarcode(PosX, PosY, BarWidth, BarcodeHeight, Barcode, Font, FontSize);

In this case the class is BarcodeEAN13 with 12 digits input string. The result is UPC-A barcode.

The PDF File Writer library includes a base class Barcode. For each supported barcode one needs a derived class. The class library includes three derived classes: Barcode128, Barcode39 and BarcodeEAN13. The BarcodeEAN13 produces EAN-13 barcode if the input string is 13 digits and UPC-A if the input string is 12 digits. Input string with 13 digit and a leading zero is considered UPC-A.

The DrawBarcode method has a number of overloads. You specify the position of the bottom left corner of the barcode, the width of the narrow bar, the height of the barcode and the derived barcode class. There are optional arguments: justification (left, center, right) color and font to display the text. Quiet zone around the barcode is your responsibility. Optional text is displayed below the barcode. If you select color other than black you should make sure the contrast to the background is significant. Usage examples are given in ArticleExample.cs and OtherExample.cs.

If you want to create a derived class for another barcode, use the source code for the three included classes as an example.

2.6. Installation

Integrating PdfFileWriter to your application requires the following steps. Install the attached PdfFileWriter.dll file in your development area. Start the Visual C# program and open your application. Go to the Solution Explorer, right click on References and select Add Reference. Select the Browse tab and navigate your file system to the location of the PdfFileWriter.dll. When your application is published, the PdfFileWriter.dll must be included.

If you want access to the source code of the PdfFileWriter project, install the PdfFileWriter project in your development area. The PdfFileWriter.dll will be in PdfFileWriter\bin\Release directory.

Add the following statement to all source modules using this library.

using PdfFileWriter;

3. Development Guide by Example

This section describes the integration of the PDF File Writer C# class library to your application. The test program TestPdfFileWriter program is a simulation of your own application. When you press on the “Article Example” button, the program executes the code in ArticleExample.cs source file. The image above displays the resulted PDF file. This method demonstrates the creation of one page document with some text and graphics. After going through this example, you should have a good understanding of the process. The "Other Example" button produces a second PDF document with 5 pages of examples.

The Debug check box, if checked, will create a PDF file that can be viewed with a text editor but cannot be loaded to a PDF reader. The resulted file is not compressed and images and font file are replaced with text place holder. The Debug check box should be used for debugging only.

The TestPdfFileWriter program was developed using Microsoft Visual C# 2012. It was tested for Windows XP, Vista, 7 and 8.

Article Example

3.1. Document Creation Overview

The Test method below demonstrates the six steps described in the introduction for creating a PDF file. The method will be executed when you press on the “Article Example” button of the demo program. The following subsections describe in detail each step.

// Create &ldquo;article example&rdquo; test PDF document
public void Test(Boolean Debug, String FileName)
// Step 1: Create empty document
// Arguments: page width: 8.5&rdquo;, page height: 11&rdquo;, Unit of measure: inches
// Return value: PdfDocument main class
PdfDocument Document = new PdfDocument(8.5, 11.0, UnitOfMeasure.Inch);

// Debug property
// By default it is set to false. Use it for debugging only.
// If this flag is set to true, PDF objects will not be compressed,
// font and images will be replaced by text place holder.
// You can view the file with a text editor but you cannot open it with a PDF reader.
Document.Debug = Debug;

// Step 2: create resources
// define font resources

// define tiling pattern resource

// Step 3: Add new empty page
PdfPage Page = new PdfPage(Document);

// Step 4: Add contents object to the page object
PdfContents Contents = new PdfContents(Page);

// Step 5: add graphics and text contents to the contents object
DrawBrickPattern(Document, Contents);
DrawFlower(Document, Contents);

// Step 6: create pdf file
// argument: PDF file name

// Optional step (very useful during development)
// start default PDF reader and display the file
// Note: To use Process class you need "using System.Diagnostics" statement
Process Proc = new Process();
Proc.StartInfo = new ProcessStartInfo(FileName);

// exit

3.2. Font Resources

The DefineFontResources method creates all the font resources used in this example. In addition, you will find an example of one character substitution. Arial character 9679 (decimal) is a full circle glyph is being mapped into character 164 (decimal). The full circle glyph is used as a separator within the text at the bottom left of the PDF example document. To see all the characters available for any font, press the third button “Font Families”. Select a family and view the glyphs defined for each character. To view individual glyph press view or double click.

// Define Font Resources
private void DefineFontResources(PdfDocument Document)
// Define font resources
// Arguments: PdfDocument class, font family name, font style, embed flag
// Font style (must be: Regular, Bold, Italic or Bold | Italic) All other styles are invalid.
// Embed font. If true, the font file will be embedded in the PDF file.
// If false, the font will not be embedded.
ArialNormal = new PdfFont(Document, "Arial", FontStyle.Regular, true);
ArialBold = new PdfFont(Document, "Arial", FontStyle.Bold, true);
ArialItalic = new PdfFont(Document, "Arial", FontStyle.Italic, true);
ArialBoldItalic = new PdfFont(Document, "Arial", FontStyle.Bold | FontStyle.Italic, true);
TimesNormal = new PdfFont(Document, "Times New Roman", FontStyle.Regular, true);
Comic = new PdfFont(Document, "Comic Sans MS", FontStyle.Bold, true);

// substitute one character for another
// this program supports characters 32 to 126 and 160 to 255
// if a font has a character outside these ranges that is required by the application,
// you can replace an unused character with this character.
ArialNormal.CharSubstitution(9679, 9679, 161); // dot
ArialNormal.CharSubstitution(1488, 1514, 162); // hebrew
ArialNormal.CharSubstitution(1040, 1045, 189); // russian (6 letters)
ArialNormal.CharSubstitution(945, 950, 195); // greek (6 letters)

3.3. Tiling Pattern Resource

The DefineTilingPatternResource method defines background pattern resource for the example area. The pattern is the word “PdfFileWriter” in white over light blue background. The pattern is made of two lines of repeating the key word. The two lines are skewed by half word length.

If you want to find interesting patterns, search the internet for catalogs of companies making floor or wall tiles.

// Define Tiling Pattern Resource
private void DefineTilingPatternResource(PdfDocument Document)
// create empty tiling pattern
WaterMark = new PdfTilingPattern(Document);

// the pattern will be PdfFileWriter laid out in brick pattern
String Mark = "PdfFileWriter";

// text width and height for Arial bold size 18 points
Double FontSize = 18.0;
Double TextWidth = ArialBold.TextWidth(FontSize, Mark);
Double TextHeight = ArialBold.LineSpacing(FontSize);

// text base line
Double BaseLine = ArialBold.DescentPlusLeading(FontSize);

// the overall pattern box (we add text height value as left and right text margin)
Double BoxWidth = TextWidth + 2 * TextHeight;
Double BoxHeight = 4 * TextHeight;
WaterMark.SetTileBox(BoxWidth, BoxHeight);

// save graphics state

// fill the pattern box with background light blue color
WaterMark.SetColorNonStroking(Color.FromArgb(230, 244, 255));
WaterMark.DrawRectangle(0, 0, BoxWidth, BoxHeight, PaintOp.Fill);

// set fill color for water mark text to white

// draw PdfFileWriter at the bottom center of the box
WaterMark.DrawText(ArialBold, FontSize, BoxWidth / 2, BaseLine, TextJustify.Center, Mark);

// adjust base line upward by half height
BaseLine += BoxHeight / 2;

// draw the right half of PdfFileWriter shifted left by half width
WaterMark.DrawText(ArialBold, FontSize, 0.0, BaseLine, TextJustify.Center, Mark);

// draw the left half of PdfFileWriter shifted right by half width
WaterMark.DrawText(ArialBold, FontSize, BoxWidth, BaseLine, TextJustify.Center, Mark);

// restore graphics state

3.4. Draw Frame with Background Pattern

The DrawFrameAndBackgroundWaterMark method draws a frame around the example area with background water mark pattern. The pattern resource was define in the previous subsection.

// Draw frame around example area
private void DrawFrameAndBackgroundWaterMark(PdfContents Contents)
// save graphics state

// Set frame&rsquo;s line width to 0.02"

// set frame&rsquo;s color to dark blue

// use water mark tiling pattern to fill the frame

// Draw the frame
// Rectangle position: x=1.0", y=1.0", width=6.5", height=9.0"
Contents.DrawRectangle(1.0, 1.0, 6.5, 9.0, PaintOp.CloseFillStroke);

// restore graphics sate

// Draw article name under the frame
// Note: the \u25cf character is a solid circle. It was substituted during font resource definition.
// This character is at position 161. To paint it you can call it either as \u00a1 or \u25cf.
Contents.DrawText(ArialNormal, 9.0, 1.1, 0.85,
    "PdfFileWriter \u25cf PDF File Writer C# Class Library \u25cf Author: Uzi Granot");

3.5. Draw Two Lines of Heading

The DrawTwoLinesOfHeading method draws two heading lines at the center of the page. The first line is drawing text with outline special effect.

// Draw heading
private void DrawTwoLinesOfHeading(PdfContents Contents)
// Page heading
// Arguments: Font: ArialBold, size: 36 points, Position: X = 4.25", Y = 9.5"
// Text Justify: Center (text center will be at X position)
// Stoking color: R=128, G=0, B=255 (text outline)
// Nonstroking color: R=255, G=0, B=128 (text body)
// Note: this method preserves the graphics state.
Contents.DrawText(Comic, 40.0, 4.25, 9.25, TextJustify.Center, 0.02,
    Color.FromArgb(128, 0, 255), Color.FromArgb(255, 0, 128), "PDF FILE WRITER");

// save graphics state

// change nonstroking (fill) color to purple

// Draw second line of heading text
// arguments: Handwriting font, Font size 30 point, Position X=4.25", Y=9.0"
// Text Justify: Center (text center will be at X position)
Contents.DrawText(Comic, 30.0, 4.25, 8.75, TextJustify.Center, "Example");

// restore graphics sate (non stroking color will be restored to default)

3.6. Draw Happy Face

The DrawHappyFace method is an example of drawing oval and constructing path from a line and Bezier curve.

// Draw Happy Face
private void DrawHappyFace(PdfContents Contents)
// save graphics state

// translate coordinate origin to the center of the happy face
Contents.Translate(4.25, 7.5);

// change nonstroking (fill) color to yellow

// draw happy face yellow oval
Contents.DrawOval(-1.5, -1.0, 3.0, 2.0, PaintOp.Fill);

// set line width to 0.2" this is the black circle around the eyes

// eye color is white with black outline circle

// draw eyes
Contents.DrawOval(-0.75, 0.0, 0.5, 0.5, PaintOp.CloseFillStroke);
Contents.DrawOval(0.25, 0.0, 0.5, 0.5, PaintOp.CloseFillStroke);

// mouth color is black

// draw mouth by creating a path made of one line and one Bezier curve 
Contents.MoveTo(-0.6, -0.4);
Contents.LineTo(0.6, -0.4);
Contents.DrawBezier(0.0, -0.8, 0, -0.8, -0.6, -0.4);

// fill the path with black color

// restore graphics sate

3.7. Draw Barcodes

The DrawBarcode method is an example of drawing two barcodes EAN-13 and Code-128

// Draw Barcode
private void DrawBarcode
        PdfContents Contents
    // save graphics state

    // create EAN-13 barcode object
    BarcodeEAN13 Barcode1 = new BarcodeEAN13("1234567890128");

    // draw barcode with text
    Contents.DrawBarcode(1.2, 6.675, 0.012, 0.75, Barcode1, ArialNormal, 8.0);

    // create Code-128 barcode object
    Barcode128 Barcode2 = new Barcode128("ABC123456");

    // draw barcode with text
    Contents.DrawBarcode(7.3, 6.8, TextJustify.Right, 0.012, 0.5, Color.Black, Barcode2, ArialNormal, 8.0);

    // restore graphics sate

3.8. Draw Rectangle with Rounded Corners and Filled with Brick Pattern

The DrawBrickPattern method draws a rectangle with rounded corners. The area is filled with a brick pattern. The PdfTillingPattern class is a general class to define tiling patterns. The class has two static methods to create specific patterns. SetBrickPattern to draw a brick wall pattern and SetWeavePattern to draw a weaving pattern.

// Draw rectangle with rounded corners and filled with brick pattern
private void DrawBrickPattern(PdfDocument Document, PdfContents Contents)
// Define brick tilling pattern resource
// Arguments: PdfDocument class,
// Scale factor (0.25),
// Stroking color (lines between bricks) LightYellow,
// Nonstroking color (brick) SandyBrown.
// Return value: tilling pattern resource
PdfTilingPattern BrickPattern = PdfTilingPattern.SetBrickPattern(Document, 0.25,
    Color.LightYellow, Color.SandyBrown);

// save graphics state

// set outline width 0.04"

// set outline color to purple

// set fill pattern to brick

// draw rounded rectangle filled with brick pattern
Contents.DrawRoundedRectangle(1.13, 5.0, 1.4, 1.4, 0.2, PaintOp.CloseFillStroke);

// restore graphics sate

3.9. Draw Image and Clip it to a Circle Shape

The DrawFlower method is an example of drawing an image. The PdfFileWriter support drawing images stored in all image files supported by Bitmap class. The ImageFormat class defines all image types. The JPEG image file type is the native image format of the PDF file. If you call the PdfImage constructor with JPEG file, the program copies the file as is into the PDF file. If you call the PdfImage constructor with any other type of image file, the program converts it into JPEG file. The result is stored in a temporary file. For example if your file is path\picture.png the temporary file will be path\picture~temp~.jpg. The converted file is included in the PDF output file. After the copy process, the temporary file is deleted. In order to keep the PDF file size as small as possible, make sure your image file resolution is not unreasonably high.

The PdfImage class loads the image and calculates maximum size that can fit a given image size in user coordinates and preserve the original aspect ratio. Before drawing the image we create an oval clipping path to clip the image.

// Draw image of a flower and clip it
private void DrawFlower(PdfDocument Document, PdfContents Contents)
// define local image resources
PdfImage Image1 = new PdfImage(Document, "Flower.jpg");

// change quality to 50%
// Note: Image quality can be set 0 to 100

// image size will be limited to 1.4" by 1.4"
// The PDF file will be printed on a printer with 150 dots per inch resolution
SizeD ImageSize = Image1.ImageSizeAndDensity(1.4, 1.4, 150.0);

// save graphics state

// translate coordinate origin to the center of the picture
Contents.Translate(3.55, 5.7);

// clipping path
Contents.DrawOval(-ImageSize.Width / 2, -ImageSize.Height / 2,
    ImageSize.Width, ImageSize.Height, PaintOp.ClipPathEor);

// draw image
Contents.DrawImage(Image1, -ImageSize.Width / 2, -ImageSize.Height / 2,
    ImageSize.Width, ImageSize.Height);

// restore graphics state

3.10. Draw Heart

The DrawHeart method displays a heart shape by defining the two ends of the center line. The DrawHeart method of the PdfContents class is a special case of drawing two symmetric Bezier curves forming a path.

// Draw heart
private void DrawHeart(PdfContents Contents)
// save graphics state

// draw heart
// The first argument are the coordinates of the centerline of the heart shape.
// The DrawHeart is a special case of DrawDoubleBezierPath method.
Contents.DrawHeart(new LineD(new PointD(5.14, 5.1), new PointD(5.14, 6.0)),

// restore graphics state

3.11. Draw Six Sided Polygon

The DrawStar method is an example of polygon with all equal sides but not equal angles. There are two variations of the DrawStar method. One, with two radii for alternating corners. The second one (as in this example), has one radius for the outer points. The inside corners are calculated such that the first and fourth line are continuation of each other.

// Draw six sided polygon in the shape of a star
private void DrawStar(PdfContents Contents)
// save graphics state

// Regular polygon
// Coordinate of center point is PosX=6.67" PosY=5.7"
// Radius of end points is 0.7"
// First drawing point is at 30 degrees (in radians PI / 6).
// Number of sides is 6 
Contents.DrawStar(6.67, 5.7, 0.7, Math.PI / 6, 6, PaintOp.CloseFillStroke);

// restore graphics state

3.12. Draw Text Box

The DrawTextBox method is an example of using the TextBox class. The TextBox class formats text to fit within a column. The text can be drawn using a verity of fonts styles and sizes.

// Draw example of a text box
private void DrawTextBox(PdfContents Contents)
// save graphics state

// translate origin to PosX=1.1" and PosY=1.1"
// this is the bottom left corner of the text box example
Contents.Translate(1.1, 1.1);

// Define constants
// Box width 3.25"
// Box height is 3.65"
// Normal font size is 9.0 points.
const Double Width = 3.15;
const Double Height = 3.65;
const Double FontSize = 9.0;

// Create text box object width 3.25"
// First line indent of 0.25"
TextBox Box = new TextBox(Width, 0.25);

// add text to the text box
Box.AddText(ArialNormal, FontSize,
    "This area is an example of displaying text that is too long to fit within a " +
    "fixed width area. The text is displayed justified to right edge. You define a &ldquo; +
    &ldquo;text box with the required width and first line indent. You add text to this &ldquo; +
    &ldquo;box. The box will divide the text into lines. Each line is made of segments &ldquo; +
    &ldquo;of text. For each segment, you define font, font size, drawing style and color. &ldquo; +
    &ldquo;After loading all the text, the program will draw the formatted text.\n");
Box.AddText(TimesNormal, FontSize + 1.0, "Example of multiple fonts: Times New Roman, ");
Box.AddText(Comic, FontSize, "Comic Sans MS, ");
Box.AddText(ArialNormal, FontSize, "Example of regular, ");
Box.AddText(ArialBold, FontSize, "bold, ");
Box.AddText(ArialItalic, FontSize, "italic, ");
Box.AddText(ArialBoldItalic, FontSize, "bold plus italic. ");
Box.AddText(ArialNormal, FontSize - 2.0, "Arial size 7, ");
Box.AddText(ArialNormal, FontSize - 1.0, "size 8, ");
Box.AddText(ArialNormal, FontSize, "size 9, ");
Box.AddText(ArialNormal, FontSize + 1.0, "size 10. ");
Box.AddText(ArialNormal, FontSize, DrawStyle.Underline, "Underline, ");
Box.AddText(ArialNormal, FontSize, DrawStyle.Strikeout, "Strikeout. ");
Box.AddText(ArialNormal, FontSize, "Subscript H");
Box.AddText(ArialNormal, FontSize, DrawStyle.Subscript, "2");
Box.AddText(ArialNormal, FontSize, "O. Superscript A");
Box.AddText(ArialNormal, FontSize, DrawStyle.Superscript, "2");
Box.AddText(ArialNormal, FontSize, "+B");
Box.AddText(ArialNormal, FontSize, DrawStyle.Superscript, "2");
Box.AddText(ArialNormal, FontSize, "=C");
Box.AddText(ArialNormal, FontSize, DrawStyle.Superscript, "2");
Box.AddText(ArialNormal, FontSize, "\n");
Box.AddText(Comic, FontSize, Color.Red, "Lets add some color, ");
Box.AddText(Comic, FontSize, Color.Green, "green, ");
Box.AddText(Comic, FontSize, Color.Blue, "blue, ");
Box.AddText(Comic, FontSize, Color.Orange, "orange, ");
Box.AddText(Comic, FontSize, DrawStyle.Underline, Color.Purple, "and purple.\n");

// Draw the text box
// Text left edge is at zero (note: origin was translated to 1.1") 
// The top text base line is at Height less first line ascent.
// Text drawing is limited to vertical coordinate of zero.
// First line to be drawn is line zero.
// After each line add extra 0.015".
// After each paragraph add extra 0.05"
// Stretch all lines to make smooth right edge at box width of 3.15"
// After all lines are drawn, PosY will be set to the next text line
// after the box's last paragraph
Double PosY = Height;
Contents.DrawText(0.0, ref PosY, 0.0, 0, 0.015, 0.05, true, Box);

// Create text box object width 3.25"
// No first line indent
Box = new TextBox(Width);

// Add text as before.
// No extra line spacing.
// No right edge adjustment
Box.AddText(ArialNormal, FontSize,
    "In the examples above this area the text box was set for first line indent of " +
    "0.25 inches. This paragraph has zero first line indent and no right justify.");
Contents.DrawText(0.0, ref PosY, 0.0, 0, 0.1, 0.05, false, Box);

// Create text box object width 2.75
// First line hanging indent of 0.5"
Box = new TextBox(Width - 0.5, -0.5);

// Add text
Box.AddText(ArialNormal, FontSize,
    "This paragraph is set to first line hanging indent of 0.5 inches. " +
    "The left margin of this paragraph is 0.5 inches.");

// Draw the text
// left edge at 0.5"
Contents.DrawText(0.5, ref PosY, 0.0, 0, 0.1, 0.05, false, Box);

// restore graphics state

3.13. Draw Book Order Form

The DrawBookOrderForm method is an example of order entry form or an invoice. It has a form made of lines. It has heading. Each item is made of four columns: description, item price, quantity and total item price. The description cannot fit within one line. We use TextBox class to format it to column width. For the other three columns we use draw text on one line. After printing all items, we calculate total and tax and print it in the bottom of the form.

// Draw example of order form
private void DrawBookOrderForm(PdfContents Contents)
// Order form simulation
// Define constants to make the code readable
// Define constants
const Double Width = 3.05;
const Double Height = 3.65;
const Double Margin = 0.04;
const Double FontSize = 9.0;
Double LineSpacing = ArialNormal.LineSpacing(FontSize);
Double Descent = ArialNormal.Descent(FontSize);
Double ColWidth1 = ArialNormal.TextWidth(FontSize, "9999.99") + 2 * Margin;
Double ColWidth2 = ArialNormal.TextWidth(FontSize, "Qty") + 2 * Margin;
Double Col4LinePosX = Width - ColWidth1;
Double Col3LinePosX = Col4LinePosX - ColWidth2;
Double Col2LinePosX = Col3LinePosX - ColWidth1;
Double Col1TextPosX = Margin;
Double Col2TextPosX = Col3LinePosX - Margin;
Double Col3TextPosX = Col4LinePosX - Margin;
Double Col4TextPosX = Width - Margin;

// save graphics state

// form line width 0.01"

// Initial vertical position for contents
Double PosY1 = Height - LineSpacing - 2 * Margin;

// bottom of the contents area of the form
Double PosY2 = 2 * Margin + 3 * LineSpacing;

// shift origin, bottom left of the form to X=4.35" and Y=1.1"
Contents.Translate(4.35, 1.1);

// draw outline rectangle
Contents.DrawRectangle(0.0, 0.0, Width, Height, PaintOp.CloseStroke);

// draw two horizontal lines. under table heading and above total
Contents.DrawLine(0, PosY1, Width, PosY1);
Contents.DrawLine(0, PosY2, Width, PosY2);

// draw three vertical lines separating the columns
Contents.DrawLine(Col2LinePosX, Height, Col2LinePosX, PosY2);
Contents.DrawLine(Col3LinePosX, Height, Col3LinePosX, PosY2);
Contents.DrawLine(Col4LinePosX, Height, Col4LinePosX, 0);

// draw table heading
Double PosY = PosY1 + Margin + Descent;
Contents.DrawText(ArialNormal, FontSize, Col1TextPosX, PosY, "Description");
Contents.DrawText(ArialNormal, FontSize, Col2TextPosX, PosY, TextJustify.Right, "Price");
Contents.DrawText(ArialNormal, FontSize, Col3TextPosX, PosY, TextJustify.Right, "Qty");
Contents.DrawText(ArialNormal, FontSize, Col4TextPosX, PosY, TextJustify.Right, "Total");

// reset order total
Double Total = 0;

// define text box for book title and author
TextBox Box = new TextBox(Col2LinePosX - 2 * Margin);

// initial vertical position
PosY = PosY1 - Margin;

// loop for all items in the order
// Order class is a atabase simulation for this example
foreach(Order Book in Order.OrderList)
    // clear the text box

    // add book title and authors to the box
    Box.AddText(ArialNormal, FontSize, Book.Title);
    Box.AddText(ArialNormal, FontSize, ". By: ");
    Box.AddText(ArialNormal, FontSize, Book.Authors);

    // draw the title and authors.
    // on exit, PosY will be for next line
    Contents.DrawText(Col1TextPosX, ref PosY, PosY2, 0, Box);

    // move PosY up to allow drawing cost on the same line as the last text line of the box
    PosY += Descent;

    // draw price quantity and item's total
    Contents.DrawText(ArialNormal, FontSize, Col2TextPosX, PosY, TextJustify.Right,
    Contents.DrawText(ArialNormal, FontSize, Col3TextPosX, PosY, TextJustify.Right,
    Contents.DrawText(ArialNormal, FontSize, Col4TextPosX, PosY, TextJustify.Right,

    // update PosY for next item
    PosY -= Descent + 0.5 * LineSpacing;

    // accumulate total
    Total += Book.Total;

// draw total before tax
PosY = PosY2 - Margin - ArialNormal.Ascent(FontSize);
Contents.DrawText(ArialNormal, FontSize, Col3TextPosX, PosY,
    TextJustify.Right, "Total before tax");
Contents.DrawText(ArialNormal, FontSize, Col4TextPosX, PosY,
    TextJustify.Right, Total.ToString("#.00"));

// draw tax (Ontario Canada HST)
PosY -= LineSpacing;
Contents.DrawText(ArialNormal, FontSize, Col3TextPosX, PosY,
    TextJustify.Right, "Tax (13%)");
Double Tax = Math.Round(0.13 * Total, 2, MidpointRounding.AwayFromZero);
Contents.DrawText(ArialNormal, FontSize, Col4TextPosX, PosY,
    TextJustify.Right, Tax.ToString("#.00"));

// draw final total
PosY -= LineSpacing;
Contents.DrawText(ArialNormal, FontSize, Col3TextPosX, PosY,
    TextJustify.Right, "Total payable");
Total += Tax;
Contents.DrawText(ArialNormal, FontSize, Col4TextPosX, PosY,
    TextJustify.Right, Total.ToString("#.00"));

// restore graphics state

4. References

5. Other Open Source Software by This Author

6. History

  • 2013/04/01: Version 1.0 Original Version.
  • 2013/04/09: Version 1.1 Support for countries with decimal separator other than period.
  • 2013/07/21: Version 1.2 The original revision supported image resources with jpeg file format only. Version 1.2 support all image files acceptable to Bitmap class. See ImageFormat class. The program was tested with: Bmp, Gif, Icon, Jpeg, Png and Tiff. See Section 2.3 and Section 3.8 above.
  • 2014/02/07: Version 1.3 Fix bug in PdfContents.DrawBezierNoP2(PointD P1, PointD P3).
  • 2014/03/01: Version 1.4 Improved support for character substitution. Improved support for image inclusion. Some fixes related to PdfXObject.
  • 2014/05/05: Version 1.5 Barcode support without use of fonts. Four barcodes are included: Code-128, Code-39, UPC-A and EAN-13. See Section 2.5 and Section 3.7.
  • 2014/07/09: Version 1.6 (1) The CreateFile method resets the PdfDocument to initial condition after file creation. (2) The PdfFont object releases the unmanaged code resources properly.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Uzi Granot
President Granotech Limited
Canada Canada
No Biography provided

Comments and Discussions

QuestionI want to use several characters of korean languge, but I got an error ... PinmemberMember 1030775619-Aug-14 13:35 
AnswerRe: I want to use several characters of korean languge, but I got an error ... PinpremiumUzi Granot20-Aug-14 2:00 
QuestionRe: I want to use several characters of korean languge, but I got an error ... PinmemberMember 1030775621hrs 40mins ago 
AnswerRe: I want to use several characters of korean languge, but I got an error ... PinpremiumUzi Granot8hrs 59mins ago 
QuestionTransparent color PinmemberMember 109956518-Aug-14 4:47 
AnswerRe: Transparent color PinpremiumUzi Granot8-Aug-14 8:44 
GeneralRe: Transparent color PinmemberMember 109956519-Aug-14 0:34 
GeneralRe: Transparent color PinpremiumUzi Granot9-Aug-14 3:58 
QuestionHow to implement auto page break ? PinmemberMember 109893413-Aug-14 20:49 
AnswerRe: How to implement auto page break ? PinpremiumUzi Granot4-Aug-14 0:09 
GeneralRe: How to implement auto page break ? PinmemberMember 109956518-Aug-14 5:56 
GeneralRe: How to implement auto page break ? PinpremiumUzi Granot8-Aug-14 8:48 
QuestionImage in a TextBox? PinmemberNick D1-Aug-14 1:05 
AnswerRe: Image in a TextBox? PinpremiumUzi Granot1-Aug-14 2:38 
GeneralRe: Image in a TextBox? PinmemberNick D1-Aug-14 3:26 
QuestionCannot get PDFFileWriter.dll to Register Correctly in VB.NET 2012 (4.5) PinmemberSoonerArrow24-Jul-14 6:32 
AnswerRe: Cannot get PDFFileWriter.dll to Register Correctly in VB.NET 2012 (4.5) PinpremiumUzi Granot24-Jul-14 7:46 
GeneralRe: Cannot get PDFFileWriter.dll to Register Correctly in VB.NET 2012 (4.5) PinmemberSoonerArrow24-Jul-14 10:22 
GeneralRe: Cannot get PDFFileWriter.dll to Register Correctly in VB.NET 2012 (4.5) PinpremiumUzi Granot24-Jul-14 10:52 
GeneralRe: Cannot get PDFFileWriter.dll to Register Correctly in VB.NET 2012 (4.5) PinmemberSoonerArrow24-Jul-14 11:45 
GeneralRe: Cannot get PDFFileWriter.dll to Register Correctly in VB.NET 2012 (4.5) PinmemberSoonerArrow25-Jul-14 3:32 
GeneralRe: Cannot get PDFFileWriter.dll to Register Correctly in VB.NET 2012 (4.5) PinpremiumUzi Granot25-Jul-14 6:48 
GeneralMy vote of 5 Pinmembersunriseyuen21-Jul-14 0:08 
QuestionEncryption support ? PinmemberYehudaK20-Jul-14 2:32 
AnswerRe: Encryption support ? PinpremiumUzi Granot20-Jul-14 2:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140814.1 | Last Updated 9 Jul 2014
Article Copyright 2013 by Uzi Granot
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid