The PDF File Writer C# class library gives .NET applications the ability to produce PDF documents. The library shields the application from the details of the PDF file structure. The library supports: forms, text, images, tables, graphics, barcodes, web links, charts, sticky notes, encryption and more. The article together with the attached source code provides detailed documentation.
Introduction
The PDF File Writer II C# class library allows you to create PDF files directly from your .net application. The library shields you from the details of the PDF file structure. This version of the PDF File Writer library was developed using Visual Studio 2022 with Target framework of .NET 6.0, Target OS is Windows and Enable windows form for this project is checked.
New features
- Interactive forms, also known as AcroForm. You will be able to define text fields, buttons, combo boxes, list boxes, check boxes, and radio buttons.
- Rewrite all classes related to annotation to include the new interactive forms that are part of the annotation family.
- Simplify the calling sequence to drawing of text lines. All input parameters are handled by one class
PdfDrawTextCtrl
. - Simplify the calling sequence to drawing of common graphics objects: rectangles, rounded rectangles, inverted rounded rectangles, and oval. The graphics object can have optional border. Background can be solid color, image, tailing, and pattern. All input parameters are handled by one class.
PdfDrawCtrl
. - Simplify the calling sequence of one dimension bar codes. All input parameters are handled by one class.
PdfDrawBarcodeCtrl
. - Support for type-one fonts, the standard 14 fonts that are built into the Adobe Acrobat Reader. This support is mainly for the interactive forms.
- Support for drawing single character as graphics. See
PdfSymbol
. - Some of the classes and methods were renamed to provide consistent look.
Features of PdfFileWriter 1.28.0 that were not included
- WPF graphics. It is not supported by .NET 6.0.
- Charts are not supported by .NET 6.0. If you need this feature, within your application, convert your chart to an image and draw the image.
- .CHM help file. Sandcastle the software that produces the help file does not support the .NET 6.0.
Note for developers using PDF File Writer version 1.28.0 and before. Upgrading to the new version 2.0.0 requires modifications to your source code. For more details see Upgrade section below.
To integrate the library to your application, you need to add the PdfFileWriter.dll
as a dependency to your project. Click on your project dependencies in solution explorer and add a reference to the attached PdfFileWriter.dll
class library file. Add a using PdfFileWriter
statement in every source file that uses the library and include the PdfFileWriter.dll
with your distribution. For more details go to Installation.
The PDF File Writer II C# class library supports the following PDF document's features:
- Page drawing coordinate system. Section Coordinate System.
- Decimal separators. For developers in world regions using comma to denote fraction. Section Decimal Separator.
- Language support, fonts, and character sets. Section Language Support.
- Graphic symbols such as drawing lines, rectangles, polygons, Bezier curves, foreground and background color, patterns, and shading. Section Draw Graphics.
- Draw single line of text. Section Single Line of Text.
- Draw long string of text in a box. Section Text Box.
- Drawing images: drawing raster (Bitmap) images and vector (Metafile) images. Section Image Support.
- Single dimension barcode: support for Barcode 128, Barcode 39, Barcode interleaved 2 of 5, Barcode EAN13 and Barcode UPC-A. Section Barcode Support.
- QR Code: Support for two-dimensional barcode QR code. Section QR Code Support.
- PDF417 barcode. Support for two dimensional PDF417 barcode. Section PDF417 Barcode.
- Weblink: Interactive weblink support. Section Weblink Support.
- PDF form document or AcroForm. Section PDF form.
- Bookmarks: Support for document outlines. Section Bookmark Support.
- Print to PDF: Create a PDF document from
PrintDocument
process. Section Print Document Support. - Display data tables. Section Data Table Support
- Play video files. Section Play Video Files
- Play sound files. Section Play Sound Files
- Attach data files. Section Attach Data Files
- Reorder pages. Section Reorder Pages
- PDF document output to a file or to a stream. Section PDF Document Output.
- PDF document information dictionary. The PDF reader displays this information in the Description tab of the document properties. The information includes title, author, subject, keywords, created date and time, modified date and time, application that produced the file, PDF Producer. Section Document Information Dictionary .
- Memory control: Write contents information of completed pages to output file and free unused memory with garbage collector. Section Memory Control.
- Transparency or opaqueness is available for painting shapes, lines, text and images. Your application can set the alpha component of color for all graphics and text. Section Transparency, Opacity, Alpha Color Component and Blending
- Blend. The library supports the PDF color blending scheme. Blending defines how the color of a new item painted over a previous item is handled. Section Transparency, Opacity, Alpha Color Component and Blending
- Document Links and Named Destination. Section Document Links and Named Destination.
- Encryption: support for AES-128 encryption. Section Encryption Support.
- Sticky Notes Sticky Notes or Text Annotation.
- Layers or Optional Content. Layers or Optional Content.
- Initial document display. Initial Document Display.
- XMP Metadata. XMP Metadata.
Creating a PDF is a six steps process.
- Step 1: Create one document object
PdfDocument
. - Step 2: Create common resources such as fonts or images (i.e.,
PdfFont
or PdfImage
). - 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.
PdfDocument
implements the IDisposable
interface to release unmanaged resources. The CreateFile
method calls Document.Dispose()
after the PDF file is created. However, to ensure the release of resources you should wrap the PdfDocument
creation and the final CreateFile
with either a using
statement or a try/catch
block.
The demo program attached to this article is a collection of test programs. These programs were developed to test and debug the library. The TestPdfFileWriter
has buttons at the bottom of the main screen. Pressing on these buttons will produce the examples of the PDF files. The right most button will display all the fonts available on your computer. The first button “Article Example” creates the PDF file displayed at the top of this article. The source code of each of these demo programs is well documented with comments. These modules should be your first source of information as how to interface to the library.
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 article "PDF File Analyzer with C# Parsing Classes". This article provides a concise overview of the PDF specifications.
Hello PDF File Writer program
A very simple example of creating a PDF document with one line of text and one image.
public void CreatePdfDocument()
{
using(PdfDocument Document = new PdfDocument(PaperType.Letter, false, UnitOfMeasure.Inch, "HelloPdfDocument.pdf"))
{
PdfPage Page = new PdfPage(Document);
PdfContents Contents = new PdfContents(Page);
PdfFont ArialNormal = PdfFont.CreatePdfFont(Document, "Arial", FontStyle.Regular, true);
PdfDrawTextCtrl TextCtrl = new PdfDrawTextCtrl(ArialNormal, 18.0);
TextCtrl.Justify = TextJustify.Center;
Contents.DrawText(TextCtrl, 4.5, 7, "Hello PDF Document");
PdfImage Image = new PdfImage(Document);
Image.LoadImage("..\\..\\..\\HappyFace.jpg");
PdfDrawCtrl DrawCtrl = new PdfDrawCtrl();
DrawCtrl.Paint = DrawPaint.Fill;
DrawCtrl.BackgroundTexture = Image;
Contents.DrawGraphics(DrawCtrl, new PdfRectangle(3.5, 4.8, 5.5, 6.8));
Document.CreateFile();
}
Process Proc = new Process();
Proc.StartInfo = new ProcessStartInfo("HelloPdfDocument.pdf") { UseShellExecute = true };
Proc.Start();
}
PDF File Writer Library Features
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 a point. 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. There are two exceptions: font size and resolution. Font size is always in points. Resolution is always in pixels per inch. 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:
if(Math.Abs(Value) < 0.0001) Value = 0.0;
String Result = ((Single) Value).ToString();
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.
The PDF File Writer library supports most of the fonts installed on your computer. The only exception is device fonts. The supported fonts follow the OpenType font specifications. More information is available at Microsoft Typography - OpenType Specification. The text to be drawn is stored in a string
made of Unicode characters. The library will accept any character (0 to 65536) except control codes 0 to 31 and 128 to 159. Every character is translated into a glyph. The glyphs are drawn on the page left to right in the same order as they are stored in the string. Most font files support only a subset of all possible Unicode characters. In other words, you must select a font that supports the language of your project or the symbols you are trying to display. If the input String contains unsupported glyphs, the PDF reader will display the "undefined glyph". Normally it is a small rectangle. The test program attached to this article has a "Font Families" button. If you click it, you can see all available fonts on your computer and within each font all available characters. If the language of your project is a left to right language and each character is translated into one glyph and the glyph is defined in the font, the result should be what you expect. If the result is not what you expect, here are some additional notes:
Unicode control characters. Unicode control characters are used to control the interpretation or display of text, but these characters themselves have no visual or spatial representation. The PDF File writer does not identify these characters. The library assumes that every character is a display character. They will be displayed as undefined character.
Right to left language. Normally the order of characters in a text string is the order a person would read them. Since the library draws left to right the text will be written backwards. The PdfContents.ReverseString
method reverses the character order. This will solve the problem if the text is made only of right to left characters. If the text is a mix of right to left, left to right, numbers and some characters such as brackets ()[]<>{} it will not produce the desired results. Another limitation is TextBox
class cannot break long right to left text into lines.
Ligature. In some languages a sequence of two or more characters are grouped together to display one glyph. Your software can identify these sequences and replaced them with the proper glyph.
Dotted circle. If you look at the Glyph column of Glyph Metrics screen you can see that some glyphs have a small-dotted circle (i.e., character codes 2364 and 2367). These characters are part of a sequence of characters. The dotted circle is not displayed. If the advance width is zero and the bounding box is on the left side of the Y axis, this glyph will be drawn ok. It will be displayed on top of the previous character. If the advance width is not zero, this glyph should be displayed before the previous character. Your software can achieve it by reversing the two characters.
The graphics operators used in PDF content streams describe the appearance of pages that are to be reproduced on a raster output device. PdfContent
class defines all the basic graphics methods. The OtherExample.cs
and the associated OtherExample.pdf
file has many examples of drawing graphics. Please look at the PDF example files attached to this project, find the example closely matching your requirement and go the source code to see how to do it.
Drawing rectangles, rounded rectangles, inverted rounded rectangles, and oval is best done with the PdfContents.DrawGraphics
method. This method is using the PdfDrawCtrl
class to set all parameters.
Example of rectangle with border and background color.
PdfRectangle Rect = new PdfRectangle(Left, Bottom, Left + Width, Bottom + Height);
PdfDrawCtrl RectCtrl = new PdfDrawCtrl();
RectCtrl.Paint = DrawPaint.BorderAndFill;
RectCtrl.BorderWidth = 0.02;
RectCtrl.BorderColor = Color.DarkBlue;
RectCtrl.BackgroundTexture = Color.Turquoise;
Contents.DrawGraphics(RectCtrl, Rect);
Example of drawing an image within oval area.
PdfImage Image = new PdfImage(Document);
Image.LoadImage("TestImage.jpg");
PdfRectangle ImageArea = new PdfRectangle(Left, Bottom, Right, Top);
PdfRectangle NewArea = PdfImageSizePos.ImageArea(Image, ImageArea, ContentAlignment.MiddleCenter);
PdfDrawCtrl DrawCtrl = new PdfDrawCtrl();
DrawCtrl.Shape = DrawShape.Oval;
DrawCtrl.Paint = DrawPaint.Border;
DrawCtrl.BorderWidth = 0.04;
DrawCtrl.BorderColor = Color.DarkBlue;
DrawCtrl.BackgroundTexture = Image;
Contents.DrawGraphics(DrawCtrl, NewArea);
To draw single line of text , such as a heading, you need a font resource, you need to create a draw control object and you need to call the PdfContents.DrawText
method. A simple example is given below. OtherExample.cs
source code has many examples. See page 5. The draw control class gives you many options to control the text's display.
PdfFont ArialNormal = PdfFont.CreatePdfFont(Document, "Arial", FontStyle.Regular);
PdfDrawTextCtrl TextCtrl = new PdfDrawTextCtrl(ArialNormal, FontSize);
Contents.DrawText(TextCtrl, PosX, PosY, "Arial normal ABCD abcd 1234");
Drawing a long string of text is done with PdfTextBox
class.
- Create a text box object and define the width of the box.
- Add text segments. It can be done one or more times. For each segment of text you can use the same
PdfDrawTextCtrl
or a diffrent one. You can have text with diffrent colors, fonts, and sizes. - Draw the text box on one or more pages.
Below you will find an example of a text box to be printed on multiple pages.
PdfDocument Document = new PdfDocument(PaperType.Letter, false, UnitOfMeasure.Inch, FileName);
PdfPage Page = new PdfPage(Document);
PdfContents Contents = new PdfContents(Page);
PdfTextBox Box = new TextBox(6.5);
PdfFont ArialNormal = new PdfFont(Document, "Arial", FontStyle.Regular);
PdfDrawTextCtrl TextCtrl = new PdfDrawTextCtrl(ArialNormal, FontSize);
Box.AddText(TextCtrl, TextBlock);
double PosX = 1.0;
double PosY;
int LineNo = 0;
for(;;)
{
PosY = 10;
LineNo = Contents.DrawText(PosX, ref PosY, 1.0, LineNo, Box);
if(LineNo >= Box.LineCount) break;
Page = new PdfPage(Document);
Contents = new PdfContents(Page);
}
Document.CreateFile();
Displaying images in the PDF document is handled by the PdfImage class. Controlling image size and aspect ratio is done with PdfImageSizePos
. Actual drawing is done with PdfContents.DrawGraphics
method. This method takes two arguments PdfDrawCtrl
and PdfRectangle
. The PdfImage
class is a PDF resource. Image sources can be:
- Image file
- .NET Image derived class such as Bitmap
- A Boolean array of black and white pixels
- QRCode barcode represented by QREncoder class
- PDF 417 barcode represented by Pdf417Encoder class
- PdfPrintDocument is using internally PdfImage to capture print pages
Images are saved to the PDF file in one of the following formats:
- Jpeg format (lossy compression)
- Indexed bitmap (Lossless compression)
- Gray bitmap (Lossless compression)
- Black and white bitmap (Lossless compression)
Color pictures should be saved in Jpeg format. To control the size of your image, you can reduce the resolution or change the image quality. Color pictures can be saved in shades of gray. Data size is cut by three, but you lose the color. If the image was created programmatically, and the number of colors are less than 256 the image can be saved as an indexed bitmap. Each color is represented by one byte (or less) compare to 3 bytes. This can result in a very significant file size reduction. If the image is black and white as in PdfPrintDocument
images of text, the image can be saved as BWImage. In the case of PrintExample.pdf
the Jpeg file is 1795KB and the black and white version is 66KB.
Adding an image to your PDF File
Create an empty PdfImage class.
PdfImage MyImage = new PdfImage(Document);
Set optional parameters if required. All the parameters have a default value. Optional parameters must be set before loading the image.
Set internal image format. Jpeg, IndexedImage, GrayImage, BWImage. Default is Jpeg.
MyImage.SaveAs = SaveImageAs.Jpeg;
Crop rectangle is the image area to be cropped. The default is no crop, entire image is drawn. The origin is at top left and Y axis is pointing down. The dimensions are in pixels. The crop rectangle must be contained within the image.
MyImage.CropRec = new Rectangle(x, y, width, height);
Crop percent rectangle is the image area to be cropped. The default is no crop (empty rectangle). The origin is at top left and Y axis is pointing down. The dimensions are in percent of image. The crop rectangle must be contained within the image.
MyImage.CropPercent = new RectangleF(x, y, width, height);
Image Quality is an integer in the range of 0 to 100. Representing poor to best quality image. The default (-1) is saving image with Bitmap default quality. For your information Bitmap class default image quality is 75. Lower image quality means smaller PDF file.
MyImage.ImageQuality = PdfImage.DefaultQuality;
Image resolution sets the image resolution provided that it is smaller than the resolution of source image. Default of 0, is keeping the original image resolution. Resolution is specified in pixels per inch. Reduced resolution means smaller PDF file.
MyImage.Resolution = 0;
Cutoff value for gray conversion to black and white. The range is 1 to 99. The default is 50. If shade of gray is below cutoff, the result is black. If shade of gray is above cutoff, the result is white.
MyImage.GrayToBWCutoff = 50;
Reverse black and white. Default is false. In Gray or BW images the color is reversed.
MyImage.ReverseBW = false;
Attach to layer control. Image visibility will be controlled by viewer application.
MyImage.LayerControl = PdfLayer;
Load image into PdfImage object. NOTE: the loading method saves the image in the PDF output file. Once this step is done the image cannot be changed.
Use one of five methods to load the image. image source can be a file, Bitmap, BW bool array, QRCode or Pdf417 barcode.
MyImage.LoadImage(image_source);
Draw the image into the PDF Document. Image will be stretched to fill the rectangle area.
PdfRectangle ImageRect = PdfRectangle(PosX, PosY, Width, Height);
Contents.DrawImage(MyImage, ImageRect);
Second choice is to draw the image by specifying the width and not the height. The height will be calculated to maintain the correct aspect ratio.
Contents.DrawImage(MyImage, PosX, PosY, Width);
If you want the image to maintain correct aspect ratio use PdfImageSizePos.ImageSize
to calculate the width and height. If the ratio of width and height is not the same as the image, the image will look stretched in one of the directions. See OtherExample 2e.
SizeD PdfImageSizePos.ImageSize(MyImage, DrawingArea);
SizeD PdfImageSizePos.ImageSize(MyImage, DrawingArea, ContentAlignment.MiddleCenter);
The code below illustrates how to include EAN13 barcode in a PDF document.
PdfBarcodeEAN13 Barcode1 = new PdfBarcodeEAN13("1234567890128");
PdfDrawBarcodeCtrl BarcodeCtrl = new PdfDrawBarcodeCtrl();
BarcodeCtrl.NarrowBarWidth = 0.012;
BarcodeCtrl.Height = 0.75;
BarcodeCtrl.TextCtrl = new PdfDrawTextCtrl(ArialNormal, 8.0);
Contents.DrawBarcode(BarcodeCtrl, PosX, PosY, Barcode1);
The PDF File Writer library includes a base class Barcode
. For each supported barcode one needs a derived class. The class library includes four derived classes: Barcode128
, Barcode39
, BarcodeInterleaved2of5
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 several 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 Draw Barcodes, 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.
The PDF File Writer library provides support for QR Code. It is based on article QR Code Encoder and Decoder Class Library Written in C# . The program supports three characters sets: numeric, alphanumeric and eight-bit byte. The program does not support Kanji characters. The program will scan the data string input and selects the most effective character set. If your data can be divided into segments with just digits or just alphanumeric characters you can create a QR Code object with array of data strings.
Adding QRCode to your PDF document must follow the steps below.
- Create
QREncoder
object. - Set encoding options. All encoding options have default values.
- Encode a data string or a data bytes array.
- Create
PdfImage
. - Draw the barcode image with
PdfContent.DrawImage
QR Code example
PdfQREncoder QREncoder = new PdfQREncoder();
QREncoder.ErrorCorrection = ErrorCorrection.M;
QREncoder.ModuleSize = 1;
QREncoder.QuietZone = 4;
QREncoder.Encode(YourText);
PdfImage BarcodeImage = new PdfImage(Document);
BarcodeImage.LoadImage(QREncoder);
Contents.DrawImage(BarcodeImage, OrigX, OrigY, Width);
PDF417 barcode support software is based on article PDF417 Barcode Encoder Class Library and Demo App. The PDF417 barcode documentation and specification can be found in the following websites. Wikipedia provides a good introduction to PDF417. Click here to access the page. The PDF417 standard can be purchased from the ISO organization at this website. An early version of the specifications can be downloaded from this website for free. I strongly recommend that you download this document if you want to fully understand the encoding options.
The PDF417 barcode encodes array of bytes into an image of black and white bars. Encoding Unicode text requires converting Unicode characters into bytes. The decoder must do the reverse process to recover the text. The bytes are converted to codewords. This conversion process compresses the bytes into codewords. The encoder adds error correction codewords for error detection and recovery. Once the total number of data codewords and error correction codewords is known, the encoder divides the codewords into data rows and data columns. The final step is the creation of a black and white image.
Adding PDF417 barcode to your PDF document must follow the steps below.
- Create
Pdf417Encoder
object. - Set encoding options. All encoding options have default values.
- Encode a data string or a data bytes array.
- Check the image width and height or the number of data columns and data rows to make sure image size is appropriate for your application. If it is not, adjust the layout.
- Create
PdfImage
. - Draw the barcode image with
PdfContent.DrawImage
Example of PDF417 Barcode Drawing
public void DrawPdf417Barcode()
{
string ArticleLink =
"http://www.codeproject.com/Articles/570682/PDF-File-Writer-Csharp-Class-Library-Version";
Pdf417Encoder Pdf417 = new Pdf417Encoder();
Pdf417.DefaultDataColumns = 3;
Pdf417.Encode(ArticleLink);
Pdf417.WidthToHeightRatio(2.5);
PdfImage BarcodeImage = new PdfImage(Document);
BarcodeImage.LoadImage(Pdf417);
Contents.DrawImage(BarcodeImage, 1.1, 5.2, 2.5);
return;
}
PDF417 Barcode Object
Create PDF417 barcode object. This object can be reused serially to produce multiple barcodes.
Pdf417Encoder Pdf417 = new Pdf417Encoder();
Set optional parameters to control the encoding process.
Encoding control
The PDF417 encoder encodes Input bytes into codewords. There are three types of codewords: byte, text and numeric. The program has an algorithm to divide the data input into these three types to compress the data. The default is Auto. However, you can restrict the encoding to only bytes or only text and bytes.
Pdf417.EncodingControl = Pdf417EncodingControl.Auto;
Pdf417.EncodingControl = Pdf417EncodingControl.ByteOnly;
Pdf417.EncodingControl = Pdf417EncodingControl.TextAndByte;
Error Correction Level
The PDF417 adds error correction codewords to detect errors and correct them. More error correction codewords improves the reliability of the barcode. However, it makes the barcode bigger. Error correction level allows you to control the quality of the barcode. The ErrorCorrectionLevel
enumeration has two types of values. Fixed levels from 0 to 8. And levels that are recommended values based on the number of data codewords. The default value in ErrorCorrectionLevel.AutoNormal
. For more details look at Table 6 and Table 7 in the PDF417 Specification.
Pdf417.ErrorCorrection = ErrorCorrectionLevel.Level_0;
Pdf417.ErrorCorrection = ErrorCorrectionLevel.AutoNormal;
Pdf417.ErrorCorrection = ErrorCorrectionLevel.AutoLow;
Pdf417.ErrorCorrection = ErrorCorrectionLevel.AutoMedium;
Pdf417.ErrorCorrection = ErrorCorrectionLevel.AutoHigh;
Narrow Bar Width
The width in pixels of a narrow barcode bar. The default is 2. If this value is changed, the program makes sure that RowHeight
is at least three times that value. And that QuiteZone
is at least twice that value.
Pdf417.NarrowBarWidth = value;
Row Height
The height in pixels of one row. This value must be greater than or equal to 3 times the NarrowBarWidth
value. The default is 6.
Pdf417.RowHeight = value;
Quiet Zone
The width of the quiet zone all around the barcode. The quiet zone is white. This value must be greater than or equal to 2 times the NarrowBarWidth
value. The default is 4.
Pdf417.QuietZone = value;
Default Data Columns
The default data columns value. The value must be in the range of 1 to 30. The default is 3. After the input data is encoded, the software sets the number of data columns to the default data columns and calculates the number of data rows. If the number of data rows exceeds the maximum allowed (90), the software sets the number of rows to the maximum allowed and recalculate the number of data columns. If the result is greater than the maximum columns allowed, an exception is thrown.
Pdf417.DefaultDataColumns = value;
Global Label ID Character Set
Set Global Label ID Character Set to ISO 8859 standard. The n can be 1 to 9 or 13 or 15. If the string is null, the default of ISO-8859-1 is used. Language support is defined here.
Pdf417.GlobalLabelIDCharacterSet = "ISO-8859-n";
Global Label ID User Defined
Set Global Label ID User Defined value. The default is not used. I did not find any reference explaining the usage of this value. User defined value must be between 810900 and 811799.
Pdf417.GlobalLabelIDUserDefined = UserDefinedValue;
Global Label ID General Purpose
Set Global Label ID General Purpose value. The default is not used. I did not find any reference explaining the usage of this value. User defined value must be between 900 and 810899.
Pdf417.GlobalLabelIDGeneralPurpose = UserDefinedValue;
Encoding data
There are two encoding methods. One accepts text string as an input and the other one accepts byte array as an input.
Pdf417.Encode(string StringData);
Pdf417.Encode(byte[] BinaryData);
The barcode was designed for binary data. Therefore, the first method above must encode the string from 16 bit characters to byte array. The encode method with string input has the following conversion logic. The Global Label ID Character Set property control the conversion. It is done in two steps. Step one string to UTF8 and step two UTF8 to ISO-8859-n. If you want to encode Hebrew, you should set the character set to ISO-8859-8.
public void Encode(string StringData)
{
byte[] UtfBytes = Encoding.UTF8.GetBytes(StringData);
Encoding ISO = Encoding.GetEncoding(_GlobalLabelIDCharacterSet ?? "ISO-8859-1");
byte[] IsoBytes = Encoding.Convert(Encoding.UTF8, ISO, UtfBytes);
Encode(IsoBytes);
Return;
}
Final Barcode Layout
After the data was encoded, you can check the layout of the barcode by examining these values: ImageWidth
, ImageHeight
, DataColumns
or DataRows
. If you want to readjust the width and the height of the barcode you can used one of the methods below. In addition, you can readjust the optional parameters: NarrowBarWidth
, RowHeight
or QuietZone
values.
Width to Height Ratio
This method will calculate the number of data rows and data columns to achieve a desired width to height ratio. The ratio includes the quiet zone. Check the return value for success.
Bool Pdf417.WidthToHeightRatio(double Ratio);
Set Data Columns
This method will calculate the number of data rows based on the desired number of data columns. Check the return value for success.
Bool Pdf417.SetDataColumns(int Columns);
Set Data Rows
This method will calculate the number of data columns based on the desired number of data rows. Check the return value for success.
Bool Pdf417.SetDataRows(int Rows);
Create PDF Document Image Resource
In this step we create a PDF document image resource from the PDF417 barcode.
PdfImage BarcodeImage = new PdfImage(Document, Pdf417);
Draw the Barcode
The last step is adding the barcode to the content of a PDF document’s page.
Contents.DrawImage(BarcodeImage, PosX, PosY, Width);
The PDF File Writer library provides weblink support. This feature is one of the PDF interactive features described in the PDF reference manual in Section 8 Interactive Features. It is a combination of annotation and action. Annotation associates a weblink with an area on the page. When the user clicks on the area, the PDF reader will activate the default web browser navigating to the desired web page.
The annotation area is a rectangle area defined by absolute coordinates relative to the bottom left corner of the page. First you create an annotation weblink object that ties the link url To the page. Next you define the annotation rectangle on the page in absolute coordinates.
PdfAnnotWebLink WebLink = new PdfAnnotWebLink(Document, ArticleLink);
WebLink.AnnotRect = new PdfRectangle(Left, Bottom, Right, Top);
Annotations are not part of the page contents. For the user to know where to click on the page, you need to display appropriate text or graphics in the same area of the page. In other words, you need to create PdfAnnotWebLink
object attached to a specific page and supply the weblink. When you create the weblink, the software associates it with the current page. And at the same time display a graphic object such as an image or text on that page. Because AddWebLink
requires coordinates relative to the bottom left corner of the page, the coordinates of your graphic object must be the same. In other words, do not use translation, scaling or rotation. If you do, you need to make sure that the two areas will coincide.
Drawing weblink within TextBox
is a two-step process. First you add the text and the weblink string to the box using the AddText
method of TextBox
class. The weblink is included in the PdfDrawTextCtrl
argument. Second you draw the TextBox
to the page contents using the DrawText
methods of PdfContents
. The last argument must be the current page.
Add weblink to TextBox
. The text will be displayed underlined and blue.
PdfTextBox Box = new PdfTextBox(BoxWidth);
Add weblink to TextBox
. The text attributes are defined by DrawStyle
and FontColor
.
PdfDrawTextCtrl TextCtrl = new PdfDrawTextCtrl(ArialNormal, 11);
TextCtrl.Annotation = new PdfAnnotWebLink(Document, ArticleLink);
Box.AddText(TextCtrl, ArticleDescription);
Contents.DrawText(BoxPosX, ref BoxPosY, BoxBottomPosY, 0, 0, 0, TextBoxJustify.Left, Box);
For coding examples please review ArticleExample.cs and OtherExample.cs source code.
An interactive form sometimes referred to as an AcroForm is a collection of fields for gathering information interactively from the user. A PDF document may contain any number of fields appearing on any combination of pages, all of which make up a single, global interactive form spanning the entire document.
Each field in a document’s interactive form is defined a class derived from PdfWidgetField
. The library supports the following fields.
- Button field
PdfAcroButtonField
. - Check box field
PdfCheckBoxField
. - Combo box field
PdfComboBoxField
. - List box field
PdfListBoxField
. - Text box field
PdfTextBoxField
. - Radio button group and radio button field
PdfRadioButtonGroup
PdfRadioButton
.
All fields share one parent PdfAcroForm
.
Each field has a unique name. The name is madeof two parts, a page number and a unique name for this page. "Page#/name". The page number (#) is NOT the document page number, but a sequential page number of pages with fields. The name is the field name given when the class is created. The name must be unique on the page.
Fonts used for text fields and combo-box edit field must be define with Unicode range or ranges. The library saves each font and each glyph definition. The library has no way of knowing which characters the user will enter into a text field. To solve this problem a range or a group of ranges must be define. For English it is simple the ASCII range is enough. For other languages, you must define the appropriate range.
PdfFont FieldTextFont = PdfFont.CreatePdfFont(Document, "Arial", FontStyle.Regular);
PdfDrawTextCtrl FieldTextCtrl = new PdfDrawTextCtrl(FieldTextFont, 12);
FieldTextFont.SetCharRangeActive(' ', '~');
For more information, please review FormExample.cs
source code.
Below you will find a method to draw a text field. It is taken from the form example above.
private PdfAcroTextField AddTextField
(
double OrigX,
double OrigY,
out double Width,
out double Height,
string FieldDescription,
string FieldName,
string FieldValue,
int TextMaxLength
)
{
const double VertGap = 0.12;
const double FrameToField = 0.04;
double PosY = OrigY;
PosY -= FixedTextCtrl.LineSpacing;
double DescriptionWidth = Contents.DrawText(FixedTextCtrl, OrigX + FieldMargin, PosY + FixedTextCtrl.TextDescent, FieldDescription);
PosY -= FieldTextCtrl.LineSpacing + VertGap;
double FieldWidth = TextMaxLength * FieldTextCtrl.CharWidth('0');
double FieldHeight = FieldTextCtrl.LineSpacing;
double FrameMargin = DrawFrame.BorderWidth + FrameToField;
PdfRectangle FrameRect = new PdfRectangle(OrigX, PosY, OrigX + FieldWidth + 2 * FrameMargin, PosY + FieldHeight + 2 * FrameMargin);
Contents.DrawGraphics(DrawFrame, FrameRect);
PdfRectangle FieldRect = FrameRect.AddMargin(-FrameMargin);
PdfAcroTextField TextField = new PdfAcroTextField(AcroForm, FieldName);
TextField.AnnotRect = FieldRect;
TextField.TextCtrl = FieldTextCtrl;
TextField.TextMaxLength = TextMaxLength;
TextField.BackgroundColor = Color.FromArgb(240, 240, 255);
if(!string.IsNullOrWhiteSpace(FieldValue)) TextField.FieldValue = FieldValue;
TextField.DrawTextField();
Width = Math.Max(FrameRect.Width, DescriptionWidth);
Height = OrigY - FrameRect.Bottom;
return TextField;
}
Radio buttons come in group. Only one button at a time can be active. Each group has a unique name. All the radio buttons with the same group name are members of that group. The PdfAcroRadioButtonGroup
class is created automatically by the library. You have to define the PdfAcroRadioButton
classes. Please look at method AddRadioButtonGroup
in FormExample.
Bookmarks are described in the PDF specification (section 8.2.2 Document Outline) as follows: "A PDF Document may optionally display a document outline on the screen, allowing the user to navigate interactively from one part of the document to another. The outline consists of a tree-structured hierarchy of outline items (sometimes called bookmarks), which serve as a visual table of contents to display the document's structure to the user. The user can interactively open and close individual item by clicking them with the mouse."
The OtherExample.cs source code has an example of bookmarks. At one location there is a hierarchy of three levels. You can see the result in OtherExample.pdf file.
The first step in adding bookmarks to your application is:
PdfBookmark BookmarkRoot = Document.GetBookmarksRoot();
This step activates bookmarks in your document and returns the root node.
Adding bookmarks is like adding controls to a windows form. The first level bookmarks are added to the root. Subsequent levels are added to existing bookmarks. At minimum you must define a title, page, vertical position on the page and an open entries flag. Page is the PdfPage object of the page to go to. YPos is the vertical position relative to the bottom left corner of the page. Open entries flag is true if the lower-level bookmarks are visible and false if the lower levels are hidden. The first level is always visible by default.
PdfBookmark FirstLevel_1 = BookmarkRoot.AddBookmark("Chapter 1", Page, YPos, false);
PdfBookmark SecondLevel_11 = FirstLevel_1.AddBookmark("Section 1.1", Page, YPos, false);
PdfBookmark SecondLevel_12 = FirstLevel_1.AddBookmark("Section 1.2", Page, YPos, false);
PdfBookmark ThirdLevel_121 = SecondLevel_12.AddBookmark("Section 1.2.1", Page, YPos, false);
PdfBookmark ThirdLevel_122 = SecondLevel_12.AddBookmark("Section 1.2.2", Page, YPos, false);
PdfBookmark SecondLevel_13 = FirstLevel_1.AddBookmark("Section 1.3", Page, YPos, false);
PdfBookmark FirstLevel_2 = BookmarkRoot.AddBookmark("Chapter 2", Page, YPos, false);
PdfBookmark SecondLevel_21 = FirstLevel_2.AddBookmark("Section 2.1", Page, YPos, false);
PdfBookmark SecondLevel_22 = FirstLevel_2.AddBookmark("Section 2.2", Page, YPos, false);
AddBookmark() method has four overloading variations:
PdfBookmarkCtrl BookmarkCtrl = new PdfBookmarkCtrl();
BookmarkCtrl.Color = Color.Red;
BookmarkCtrl.TextStyle = BookmarkTextStyle.Bold;
PdfBookmark Bookmark = BookmarkRoot.AddBookmark(BookmarkCtrl, BookmarkText, Page, PosX, PosY);
PdfBookmark
class exposes one more method GetChild
. You can get any bookmark by calling GetChild
with one or more integer arguments. Each argument is a zero-base argument of the child position in the level. For example, GetChild(2)
is the third item of the first level. GetChild(2, 3)
is the fourth second level item of the third first level item.
Print document support allows you to print a report in the same way as printing to a printer and producing a PDF document. The difference between this method of producing a PDF file and using PdfContents
to produce a PDF file is the difference between raster graphics to vector graphics. Print document support creates one jpeg image per page. PrintExample.cs
has an example of creating a three-page document.
Normally each page is a full image of the page. If your page is letter size and the resolution is 300 pixels per inch, each pixel is 3 bytes, the bit map of the page will be 25.245MB long. PrintPdfDocument
has a method CropRect
that can reduce the size of the bit map significantly. Assuming one inch margin is used, the active size of the bit map will be reduced to 15.795 MB. That is 37.4% reduction.
Document = new PdfDocument(PaperType.Letter, false, UnitOfMeasure.Inch);
PdfImageControl ImageControl = new PdfImageControl();
ImageControl.Resolution = 300.0;
PrintPdfDocument Print = new PrintPdfDocument(Document, ImageControl);
Print.PrintPage += PrintPage;
Print.SetMargins(1.0, 1.0, 1.0, 1.0);
Print.CropRect = new RectangleF(0.95F, 0.95F, 6.6F, 9.1F);
Print.AddPagesToPdfDocument();
Print.Dispose();
Document.CreateFile(FileName);
Example of PrintPage method
public void PrintPage(object sender, PrintPageEventArgs e)
{
Graphics G = e.Graphics;
G.SmoothingMode = SmoothingMode.HighQuality;
G.InterpolationMode = InterpolationMode.HighQualityBicubic;
G.PixelOffsetMode = PixelOffsetMode.HighQuality;
G.CompositingQuality = CompositingQuality.HighQuality;
Rectangle PrintArea = e.MarginBounds;
G.DrawRectangle(Pens.DarkBlue, PrintArea);
int LineHeight = DefaultFont.Height + 8;
Rectangle TextRect = new Rectangle(PrintArea.X + 4, PrintArea.Y + 4, PrintArea.Width - 8, LineHeight);
String text = String.Format("Page Bounds: Left {0}, Top {1}, Right {2}, Bottom {3}",
e.PageBounds.Left, e.PageBounds.Top, e.PageBounds.Right, e.PageBounds.Bottom);
G.DrawString(text, DefaultFont, Brushes.Black, TextRect);
TextRect.Y += LineHeight;
text = String.Format("Page Margins: Left {0}, Top {1}, Right {2}, Bottom {3}",
PrintArea.Left, PrintArea.Top, PrintArea.Right, PrintArea.Bottom);
G.DrawString(text, DefaultFont, Brushes.Black, TextRect);
TextRect.Y += LineHeight;
for(int LineNo = 1;;LineNo++)
{
text = String.Format("Page {0}, Line {1}", PageNo, LineNo);
G.DrawString(text, DefaultFont, Brushes.Black, TextRect);
TextRect.Y += LineHeight;
if(TextRect.Bottom > PrintArea.Bottom) break;
}
PageNo++;
e.HasMorePages = PageNo <= 3;
return;
}
The data table classes allow you to display data tables in your PDF document. PdfTable
is the main class controlling the display of one table. A table is made of a header row and data rows. Each row is divided into cells. PdfTableCell
controls the display of one header cell or one data cell. If header is used it will be displayed at the top of the table. Optionally it will be displayed at the top of each additional page. To display data in a cell, you load the data into the Value
property of PdfTableCell
. Data can be text string, basic numeric value, bool, Char, TextBox
, image, QR code or barcode. Independently of data, you can load the cell with document link, web link, video, audio, or embedded file. Clicking anywhere within the cell's area will cause the PDF reader to activate the document link, web link, video, audio or embedded file. The display of the data is controlled by PdfTableStyle
class. PdfTable
class contains a default cell style and a default header style. You can override the default styles with private styles within PdfTableCell
. To display a table, you create a PdfTable
object. Next you initialize the table, header cells, data cells and styles objects. Finally, you set a loop and load the cell values of one row and then draw this row. This loop continues until all data was displayed. Below you will find the necessary sequence of steps to produce a table.
When DrawRow
method is called, the software calculates the required row height. Row height is the height of the tallest cell. The row will be drawn if there is sufficient space within the table. When the available space at the bottom is too small, a new page is called, and optional heading and the current row are displayed at the top of the table. If the required row height is so large that it will not fit in full empty table, an exception is raised. To accommodate long multi-line Strings or TextBoxes
, the software can handle these cases in a flexible way. Multi-line String is converted by PdfTabl
e into a TextBox
. The PdfTableStyle
class has a TextBoxPageBreakLines
property. If this property is set to zero (default), the TextBox
is treated as other data values. TextBox
height must fit the page. If TextBoxPageBreakLines
is set to a positive integer, the system will calculate cell's height as TextBox
height or the height the first few lines as specified by TextBoxPageBreakLines
. The system will draw the row with as many lines that fit the page. New page will be created, and the rest of the lines will be drawn. In other words, the first block of lines of a long TextBox
will be at least TextBoxPageBreakLines
long. TableExample.cs source contains an example of long TextBox
cells.
Create a PdfTable
object.
PdfTable Table = new PdfTable(Page, Contents, DrawTextCtrl);
Page is the current PdfPage. Contents is the current PdfContents. DrawTextCtrl contains the default font and font size to be used.
Define table's area on the page.
Table.TableArea = new PdfRectangle(Left, Bottom, Right, Top);
Table.RowTopPosition = StartingTopPosition;
The four arguments are the four sides of the table relative to bottom left corner and in user units. If on the first page the table-top position is not at the top of the page set RowTopPosition
to the starting top position. On subsequent pages the table will always start at the top. If TableArea
is not specified, the library will set it to default page size less one inch margin.
Divide the table width into columns.
StockTable.SetColumnWidth(Width1, Width2, Width3, ...);
The number of arguments is the number of columns. The table width less total border lines will be divided in proportion to these arguments.
Once the number of columns is set with SetColumnWidth
method the library creates two PdfTableCell
arrays. One array for header cells and one array for data cells.
Rows and columns of the data table can be separated by border lines. Border lines properties are defined by PdfTableBorder
and PdfTableBorderStyle
. There are four horizontal border lines: TopBorder
, BottomBorder
, HeaderHorBorder
between the header row and first data row and CellHorBorder
between data rows. There are two sets of vertical border lines: HeaderVertBorder
array for vertical border lines within the header row, and CellVertBorder
array for vertical border lines between columns within the data part of the table. Arrays size is the number of columns plus one. Array element zero is the table's left border. Array element Columns is the table's right border. All other elements are lines separating columns. Each of these lines can be defined individually. There are methods to define all border lines at once or define each individual border line.
Methods to define all border lines:
Table.Borders.ClearAllBorders();
Table.Borders.SetDefaultBorders();
Table.Borders.SetAllBorders(double Width);
Table.Borders.SetAllBorders(double Width, Color LineColor);
Table.Borders.SetAllBorders(double FrameWidth, double GridWidth);
Table.Borders.SetAllBorders(double FrameWidth, Color FrameColor, double GridWidth, Color GridColor);
Table.Borders.SetFrame(double Width);
Table.Borders.SetFrame(double Width, Color LineColor);
Each horizontal border line can be cleared or set. The example is for top border line:
Table.Borders.ClearTopBorder();
Table.Borders.SetTopBorder(double LineWidth);
Table.Borders.SetTopBorder(double LineWidth, Color LineColor);
Each vertical border line can be cleared or set. The example is for cell's vertical border lines:
Table.Borders.ClearCellVertBorder(int Index);
Table.Borders.SetCellVertBorder(int Index, double LineWidth);
Table.Borders.SetCellVertBorder(int Index, double LineWidth, Color LineColor);
Set other optional table properties. The values given in the example below are the defaults.
HeaderOnEachPage = true;
MinRowHeight = 0.0;
Table information is processed one row at a time. Each row is made of cells. One cell per column. The display of cell's information is controlled by PdfTableStyle
class. There are about 20 style properties. Some of these styles are specific to the type of information to be displayed. Here is an example.
Table.DefaultHeaderStyle.Alignment = ContentAlignment.BottomRight;
Table.Header[0].Style = Table.HeaderStyle;
Table.Header[0].Style.Alignment = ContentAlignment.MiddleLeft;
Table.Header[0].Value = "Date";
Table.DefaultCellStyle.Alignment = ContentAlignment.MiddleRight;
Table.DefaultCellStyle.Format = "#,##0.00";
Table.Cell[0].Style = StockTable.CellStyle;
Table.Cell[0].Style.Alignment = ContentAlignment.MiddleLeft;
Table.Cell[0].Style.Format = null;
After initialization is done it is time to display the data. The example below is from TableExample.cs
. It is a table of stock prices. There are 6 columns.
StreamReader Reader = new StreamReader("SP500.csv");
Reader.ReadLine();
for(;;)
{
String TextLine = Reader.ReadLine();
if(TextLine == null) break;
String[] Fld = TextLine.Split(new Char[] {','});
Table.Cell[ColDate].Value = Fld[ColDate];
Table.Cell[ColOpen].Value = double.Parse(Fld[ColOpen], NFI.PeriodDecSep);
Table.Cell[ColHigh].Value = double.Parse(Fld[ColHigh], NFI.PeriodDecSep);
Table.Cell[ColLow].Value = double.Parse(Fld[ColLow], NFI.PeriodDecSep);
Table.Cell[ColClose].Value = double.Parse(Fld[ColClose], NFI.PeriodDecSep);
Table.Cell[ColVolume].Value = int.Parse(Fld[ColVolume]);
StockTable.DrawRow();
}
StockTable.Close();
The DrawRow(NewPage)
method has an optional argument bool NewPage = false
. The default value is false
. If you want the next row to be printed at the top of the next page, set the argument to true
.
Interactive features example.
BookList.Cell[6].WebLink = WebLinkString;
BookList.Cell[6].Annotation = new PdfAnnotWebLink(Document, WebLinkString);
For more examples of data table source code look into ArticleExample.cs
and TableExample.cs
.
The PdfFileWriter
supports embedding video files in the PDF document. Full examples of playing video files are given in the page 7 of OtherExample.cs
. Adding a video file requires the use of three classes. First you need to embed the video file in the PDF document.
Second you need to define how the video is to be played. The PdfDisplayMedia
class has several methods to control the video display. Please refer to the class' source code. For example: RepeatCount
or ScaleMedia
. If you want to play the video in a floating window you must use SetMediaWindow
method.
Third you need to define the area on the PDF page that the user must click in order to activate the video. If you want to activate the video when the annotation area is visible, use ActivateActionWhenPageIsVisible
.
PdfEmbeddedFile Video = PdfEmbeddedFile.CreateEmbeddedFile(Document, "Omega.mp4");
DisplayMedia = new PdfAnnotDisplayMedia(Document, Video);
DisplayMedia.DisplayControls = true;
DisplayMedia.MediaWindowType = MediaWindow.Floating;
DisplayMedia.FloatingWindowTitleText = "Floating Window Example";
PdfDrawTextCtrl TextCtrl = new PdfDrawTextCtrl(ArialNormal, 12);
TextCtrl.Justify = TextJustify.Center;
double LineSpacing = TextCtrl.LineSpacing;
double TextPosX = PosX + 0.5 * AreaWidth;
double TextPosY = PosY + 0.5 * AreaHeight + LineSpacing;
double TextWidth = Contents.DrawText(TextCtrl, TextPosX, TextPosY, "Click this text to play the video");
TextPosY -= LineSpacing;
Contents.DrawText(TextCtrl, TextPosX, TextPosY, "in a floating window");
DisplayMedia.AnnotRect = new PdfRectangle(TextPosX - 0.5 * TextWidth, TextPosY - TextCtrl.TextDescent,
TextPosX + 0.5 * TextWidth, TextPosY + TextCtrl.TextAscent + LineSpacing);
The PdfFileWriter
supports embedding sound files in the PDF document. Full example of playing sound file is given in the page 7 of OtherExample.cs
. Embedding sound files is essentially the same as video files. The only obvious difference is that there is nothing to display.
PdfDrawTextCtrl RedTextCtrl = new PdfDrawTextCtrl(ArialNormal, 12);
RedTextCtrl.Justify = TextJustify.Center;
RedTextCtrl.TextColor = Color.Red;
double TextPosX = PosX + 0.5 * AreaWidth;
double TextPosY = PosY + 0.7 * AreaHeight + RedTextCtrl.LineSpacing;
double TextWidth = Contents.DrawText(RedTextCtrl, TextPosX, TextPosY, "Click this text to play");
TextPosY -= RedTextCtrl.LineSpacing;
Contents.DrawText(RedTextCtrl, TextPosX, TextPosY, "Ringing sound");
PdfRectangle TextRect = new PdfRectangle(TextPosX - 0.5 * TextWidth, TextPosY - RedTextCtrl.TextDescent,
TextPosX + 0.5 * TextWidth, TextPosY + RedTextCtrl.LineSpacing + RedTextCtrl.TextAscent);
PdfEmbeddedFile RingSoundFile = PdfEmbeddedFile.CreateEmbeddedFile(Document, "Ring01.wav");
PdfAnnotDisplayMedia RingSound = new PdfAnnotDisplayMedia(Document, RingSoundFile);
RingSound.MediaWindowType = MediaWindow.Hidden;
RingSound.AnnotRect = TextRect;
RingSound.ActivateWhenPageIsVisible();
The PdfFileWriter
supports embedding data files in the PDF document. Full example of embedding file is given in the page 7 of OtherExample.cs
. The user can save the files or display the files.
PdfDrawTextCtrl TextCtrl = new PdfDrawTextCtrl(ArialNormal, 12);
TextCtrl.Justify = TextJustify.Center;
PdfEmbeddedFile EmbeddedFile = PdfEmbeddedFile.CreateEmbeddedFile(Document, "BookList.txt");
TextCtrl.Annotation = new PdfAnnotFileAttachment(Document, EmbeddedFile);
TextCtrl.TextColor = Color.DarkViolet;
Contents.DrawText(TextCtrl, PosX + 0.5 * AreaWidth, PosY + 0.4 * AreaHeight, "Right click to open or save the attached file,");
The PdfFileWriter
appends new pages to the end of the page list. If you want to move a page from its current position to a new position, use the following method.
Document.MovePage(int SourceIndex, int DestinationIndex);
The PdfFileWriter creates PDF documents. The main class PdfDocument constructor gives you two choices to save the document. The first choice is to save the PDF file to a disk file. In this case you provide the constuctor with a file name. At the end of file creation, you call PdfDocument.CreateFile. This method writes the PDF to the file and closes the file.
PdfDocument Document = new PdfDocument(PaperType.Letter, false, UnitOfMeasure.Inch, FileName);
Document.CreateFile();
The second choice is a stream. You create a stream, either memory stream or a file stream, and you pass the stream as an argument to the PdfDocument constructor. After CreateFile method is executed, your stream contains the PDF document. Extract the document from the stream as appropriate to your application. You must close the stream in your application.
MemoryStream PdfStream = new MemoryStream();
PdfDocument Document = new PdfDocument(PaperType.Letter, false, UnitOfMeasure.Inch, PdfStream);
Document.CreateFile();
FileStream FS = new FileStream(FileName, FileMode.Create);
PdfStream.WriteTo(FS);
PdfStream.Close();
FS.Close();
The PDF document information dictionary is displayed by the PDF reader in the Description tab of the document properties. The information includes Title, Author, Subject, Keywords, Created-Date and Created-Time, Modified date and time, the Application that produced the file, the PDF Producer. Including document information in your application is done as follows:
PdfInfo Info = new PdfInfo(Document);
Info.Title("Article Example");
Info.Author("Uzi Granot");
Info.Keywords("PDF, .NET, C#, Library, Document Creator");
Info.Subject("PDF File Writer II C# Class Library");
When PdfInfo
object is created, four additional fields are added to the dictionary. You can override all of them in your code.
DateTime LocalTime = DateTime.Now;
Info.CreationDate(LocalTime);
Info.ModDate(LocalTime);
Info.Creator("PdfFileWriter C# Class Library Version " + PdfDocument.RevisionNumber);
Info.Producer("PdfFileWriter C# Class Library Version " + PdfDocument.RevisionNumber);
As a document is being built, the PDF File Writer accumulates all the information required to create the PDF file. The information is kept in memory except for images and embedded files. Images and embedded files are automatically written to the output file when they are declared. For very large documents the memory used keeps growing. The library offers methods (CommitToPdfFile
) to write contents information to the output file and invoke the garbage collector to free the unused memory. The GC.Collect
method takes time to execute. If execution time is an issue, set the GCCollect
argument once every few pages. In other words, the CommitToPdfFile
must run for every page but the cleanup is done once every few pages. Once a commit was executed, no additional information can be added. PdfTable
automatically starts a new page when the next row cannot fit at the bottom of the current page. The PdfTable
class has two members CommitToPdfFile
and CommitGCCollectFreq
to control memory usage while a table is being build. The PdfChart
class generates an image from the .NET Chart class. The DrawChart
method of PdfContents
will perform the commit. Alternatively, you can call CommitToPdfFile
method of PdfChart
.
Contents.CommitToPdfFile(true);
By default the PDF imaging model paints objects (shapes, lines, text and images) opaquely onto the page. Each new object completely obscures the image under it. PDF has two mechanisms to change this behavior opacity and blending. The graphic state dictionary has opacity value for stroking (pen) and non-stroking (brush) operations. The opacity value of fully opaque is 1.0 and fully transparent is 0.0. The opacity value corresponds to the alpha component of a color structure such that 1.0 is 255 alpha and 0.0 is 0 alpha. If the opacity value is 0.5 a new object painted on the page will be 50% transparent. To set opacity call the SetAlphaStroking
method for lines or SetAlphaNonStroking
method for shapes. Blending is a process of combining the color on the page with the color of the new item being painted. To set a bland mode call the SetBlendMode
method of PdfContents
. The argument is BlendMod
e enumeration. For full description please refer to section 7.2.4 Blend Mode of the PDF specifications document. For example please refer to OtherExample.cs
page 8.
Document links allow PDF document users to click on the link and jump to another part of the document. Adding document links is done in two parts. The destination is defined as a location marker. Location marker must have a unique name, a scope (LocalDest
or NamedDest
), and document location (page and position). NamedDest
Scope can be used for either document link or for named destination or both. The second part is the link location. The two parts can be defined in any order. They are tied together by the name. The name is case sensitive. Many links can point to the same location marker.
Named destinations are targets within the PDF document. They are defined with location marker in the same way as document links. The scope must be set to NamedDest
. When a PDF reader such as Adobe Acrobat opens a PDF document it can open the document while displaying the target in the viewing window.
To embed a location marker call the AddLocationMarker
method of PdfPage
. Note: Name is case sensitive.
public void AddLocationMarker
(
string LocMarkerName,
LocMarkerScope Scope,
DestFit FitArg,
params double[] SideArg
)
To add link location call AddLinkLocation method of PdfPage.
public PdfAnnotation AddLinkAction
(
string LocMarkerName,
PdfRectangle AnnotRect
)
For more information about named destinations please refer to Adobe PDF file specification “PDF Reference, Sixth Edition, Adobe Portable Document Format Version 1.7 November 2006”. Table 8.2 on page 582.
DestFit.Fit
(no arg): Display the page, with its contents magnified just enough to fit the entire page within the window both horizontally and vertically. DestFit.FitH
(1 arg Top): Display the page, with the vertical coordinate top positioned at the top edge of the window and the contents of the page magnified just enough to fit the entire width of the page within the window. DestFit.FitV
(1 arg Left): Display the page, with the horizontal coordinate left positioned at the left edge of the window and the contents of the page magnified just enough to fit the entire height of the page within the window. DestFit.FitR
(4 args Left Bottom Right Top): Display the page, with its contents magnified just enough to fit the rectangle specified by the coordinates left, bottom, right, and topentirely within the window both horizontally and vertically. DestFit.FitB
(No arg): Display the page, with its contents magnified just enough to fit its bounding box entirely within the window both horizontally and vertically. DestFit.FitBH
(1 arg Top): Display the page, with the vertical coordinate top positioned at the top edge of the window and the contents of the page magnified just enough to fit the entire width of its bounding box within the window. DestFit.FitBV
(1 arg Left): Display the page, with the horizontal coordinate left positioned at the left edge of the window and the contents of the page magnified just enough to fit the entire height of its bounding box within the window.
The PDF reader's calling parameters are defined in Parameters for Opening PDF Files by Adobe. If the PDF is opened on a desktop computer the calling line must be:
"path\AcroRd32.exe" /A "nameddest=ChapterXX" "path\Document.pdf"
If the PDF document is pointed by a link in a web page, the destination is appended to the link:
<a href="http://example.org/Document.pdf#ChapterXX">Target description</a>
Or: <a href="http://example.org/Document.pdf#namedsest=ChapterXX">Target description</a>
The PDF File Writer library provides support to AES 128 and Standard 128 (RC4) encryption. For more information, please refer to PDF Reference sixth edition (Version 1.7) section 3.5 Encryption. The PDF File writer supports two types of encryption filters, the AES-128 and Standard 128. The Standard 128 is RC4 encryption. It is considered unsafe. For new project do not use it. It does not support public key security to encode recipient list.
To encrypt your PDF document call one of four SetEncryption
methods defined in PdfDocument
class:
Set Encryption with no arguments.
The PDF File Writer library will encrypt the PDF document using AES-128 encryption. The PDF reader will open the document without requesting a password. Permissions flags are set to allow all.
Document.SetEncryption();
Set Encryption with one argument.
The PDF File Writer library will encrypt the PDF document using AES-128 encryption. The argument is permissions. Permission flags are defined below. You can or together more than one permission. The PDF reference manual has full description of permissions. The PDF reader will open the document without requesting a password.
Document.SetEncryption(Permission Permissions);
Set Encryption with two arguments.
The PDF File Writer library will encrypt the PDF document using AES-128 encryption. The two arguments are user password and permissions. The PDF reader will open the document with user password. Permissions will be set as per argument.
Document.SetEncryption(String UserPassword, Permission Permissions);
Set Encryption with four arguments.
The PDF File Writer library will encrypt the PDF document using either EncryptionType.Aes128 encryption or EncryptionType.Standard128 encryption. The four arguments are user password, owner password, permissions, and encryption type. If user password is null, the default password will be taken. If owner password in null, the software will generate random number password. The Standard128 encryption is considered unsafe. It should not be used for new projects.
A PDF reader such as Acrobat will accept either user or owner password. If owner password is used to open document, the PDF reader will open it with all permissions set to allow operation.
Document.SetEncryption(String UserPassword, String OwnerPassword,
Permission Permissions, EncryptionType Type);
Permission flags are as follows:
public enum Permission
{
None = 0,
LowQalityPrint = 4,
ModifyContents = 8,
ExtractContents = 0x10,
Annotation = 0x20,
Interactive = 0x100,
Accessibility = 0x200,
AssembleDoc = 0x400,
Print = 0x804,
All = 0xf3c,
}
The PDF reference document defines Sticky Notes or Text Annotation in Section 8.4 page 621. “A text annotation represents a “sticky note” attached to a point in the PDF document. When closed, the annotation appears as an icon; when open, it displays a pop-up window containing the text of the note in a font and size chosen by the viewer application. Text annotations do not scale and rotate with the page; they behave as if the NoZoom and NoRotate annotation flags (see Table 8.16 on page 608) were always set. Table 8.23 shows the annotation dictionary entries specific to this type of annotation.”
Adding a sticky note to your document is very simple. You add one single line of code. The sticky note is added to a PdfPage
object. It is not part of the page contents. The position of the sticky note is an absolute page location measured from the bottom left corner of the page to the top left corner of the sticky note icon. The text string is the content of the pop-up window. The stick note argument is one of enumeration items below.
Page.AddStickyNote(PageAbsPosX, PageAbsPosY,
"My first sticky note", StickyNoteIcon.Note);
public enum StickyNoteIcon
{
Comment,
Key,
Note,
Help,
NewParagraph,
Paragraph,
Insert,
}
The PDF specification document (section 4.10) defines optional contents as follows. “Optional content (PDF 1.5) refers to sections of content in a PDF document that can be selectively viewed or hidden by document authors or consumers. This capability is useful in items such as CAD drawings, layered artwork, maps, and multi-language documents.”
Adobe Acrobat viewer has navigation panels on the left side of the screen. One of them is the layers panel. If a PDF document uses layers, the layers control switches will be displayed in this panel. The user can display or hide items that were attached to these layer controls.
Adding layers to your PDF document. The full example is given in LayersExample.cs
. In addition, OtherExample.cs
has examples of using layers to control images and annotations.
Create the main layers control object. One per document.
PdfLayers Layers = new PdfLayers(Document, "PDF layers group");
Set the list mode option. The default is all pages
Layers.ListMode = ListMode.AllPages;
Layers.ListMode = ListMode.VisiblePages;
Create one or more layers objects. Each one will correspond to one check box on the layer panel. Each one can control one or many displayed items.
PdfLayer LayerName = new PdfLayer(Layers, "Layer name");
Several layers can be combined into radio buttons group. One group of radio buttons can be all off or just one layer on.
LayerName1.RadioButton = "Group1";
LayerName2.RadioButton = "Group1";
Set the order of layers in the layer pane. If DisplayOrder method is not used, the program will list all layers specified above on the same main level. If DisplayOrder method is used, all layers must be included
The list of layers can have sub-groups with optional name
Layers.DisplayOrder(LayerName1);
Layers.DisplayOrder(LayerName2);
Layers.DisplayOrder(LayerName3);
Layers.DisplayOrderStartGroup("Sub Group");
Layers.DisplayOrder(LayerName4);
Layers.DisplayOrder(LayerName5);
Layers.DisplayOrder(LayerName6);
Layers.DisplayOrderEndGroup();
Define an area within contents stream to be controlled by layer
Contents.LayerStart(LayerName1);
Contents.LayerEnd();
Control an image or annotation directly. The image can be anywhere within the document.
QREncoder QREncoder = new QREncoder();
QREncoder.ErrorCorrection = ErrorCorrection.M;
QREncoder.Encode("Some data");
PdfImage QRImage = new PdfImage(Document);
QRImage.LayerControl = LayerName1;
QRImage.LoadImage(QREncoder);
The initial document display controls the appearance of your document when it is displayed by the PDF viewer (Acrobat). It controls the left pane of the screen.
For example, open the bookmarks pane.
Document.InitialDocDisplay = InitialDocDisplay.UseBookmarks;
public enum InitialDocDisplay
{
UseNone,
UseBookmarks,
UseThumbs,
FullScreen,
UseLayers,
UseAttachments,
}
The XMP file or byte array are embedded in a metadata stream contained in a PDF object. The XMP must be encoded as UTF-8. The PdfFileWriter includes the input file or input byte array as given by the user. The user must ensure the XMP input is a valid metafile. The XMP stream is not compressed or encrypted. This allows readers to get the metadata information with little programming. You should include the XMP metadata shortly after the PdfDocument is created and before any image is loaded. By doing so the metadata will be at the start of the file and it will be readable by simple text editors.
new PdfMetadata(Document, FileName);
new PdfMetadata(Document, ByteArray);
The test/demo/debug 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 at the start of the article 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 buttons produce a variety of PDF documents. In total, practically every feature of this library is demonstrated by these 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 or viewer. 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.
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;
PdfFileWriter 1.28.0 projects and before are not compatible with PdfFileWriter 2.0.0, however, they are close enough to allow for conversion with some effort. The following list shows most of the main changes.
- All class names start with Pdf.
- All methods related to drawing text strings are controled by
PdfDrawTextCtrl
. - All methods related to drawing barcodes are controled by
PdfDrawBarcodeCtrl
. - All methods related to drawing rectangles, rounded rectangles, inverted rounded rectangles, and ovals controled by
PdfDrawCtrl
. - Creating image resources was changed from multiple constructors to one constructor and setting fields and methods.
- All annotation derived classes were rewriten.
- 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.
- 2014/08/25: Version 1.7 Support for document encryption, web-links and QR Code.
- 2014/09/12: Version 1.8 Support for bookmarks.
- 2014/10/06: Version 1.9 Support for charting, PrintDocument and image Metafiles.
- 2014/10/12: Version 1.9.1 Fix to ChartExample. Parse numeric fields in regions with decimal separator other than period.
- 2014/12/02: Version 1.10.0 Support for data tables. Add source code documentation. Increase maximum number of images per document.
- 2015/01/12: Version 1.11.0 Support for video, sound, and attachment files. Add support for Interleave 2 of 5 barcode.
- 2015/04/13: Version 1.12.0 Support for reordering pages and enhance data table border lines support.
- 2015/05/05: Version 1.13.0 PDF document output to a stream. PDF table insert page break. Image quality enhancement. Support for Standard-128 (RC4) encryption.
- 2015/06/08: Version 1.14.0 Support for long text blocks or TextBox within PDF Table.
- 2015/06/09: Version 1.14.1 one-line change to Copy method of PdfTableStyle class.
- 2015/06/17: Version 1.15.0 Document information dictionary. PdfImage rewrite. Additional image saving options.
- 2015/06/18: Version 1.15.1 Remove unused source from solution explorer.
- 2015/07/27: Version 1.16.0 Unicode support. Commit page method.
- 2015/08/07: Version 1.16.1 Fix for small (<0.0001) real numbers conversion to string.
- 2015/09/01: Version 1.16.2 Fix for undefined characters. The selected font does not support characters used.
- 2015/09/22: Version 1.16.3 PdfTable constructor uses current page size to calculate the default table area rectangle. When PdfTable starts a new page the page type and orientation is taken from the previous page.
- 2015/09/30: Version 1.16.4 Consistent use of IDisposable interface to release unmanaged resources.
- 2016/01/26: Version 1.17.0 WPF graphics, transparency, color blending, elliptical arcs and quadratic Bezier curves.
- 2016/02/29: Version 1.17.1 PdfTable will display headers properly when the first column header is a TextBox.
- 2016/03/22: Version 1.17.2 PdfInfo PDF documents properties will be displayed properly.
- 2016/04/14: Version 1.17.3 Fix problem with non-integer font size in regions that define decimal separator to be non-period (comma).
- 2016/05/24: Version 1.18.0 Named destinations and creation of PdfFont resource.
- 2016/06/02: Version 1.18.1 Re-apply 1.17.3 fix.
- 2016/06/13: Version 1.19.0 Document links. Changes to named destination. Interactive features support to TextBox and PdfTable.
- 2016/07/27: Version 1.19.1 Fix: AddLocationMarker fix for regions with decimal separator not period.
- 2017/08/31: Version 1.19.2 Fix: Debug working directory is not saved as part of the project
- 2018/06/26: Version 1.19.3 Fix PdfFontFile.BuildLocaTable method. Long format buffer pointer initialization. Fix PdfTableCell add value type of DBNull.
- 2018/07/15: Version 1.20.0 Modify QR Code support by adding number of pixels per module.
- 2019/02/06: Version 1.21.0 Support for PDF417 barcode.
- 2019/02/13: Version 1.21.1 Fix for PDF417 barcode quiet zone.
- 2019/02/18: Version 1.22.0 Support for sticky notes.
- 2019/05/26: Version 1.23.0 Support for layers and changes to QRCode and Pdf417 barcode.
- 2019/06/06: Version 1.24.0 Support for layers control of images and annotations.
- 2019/06/20: Version 1.24.1 Support for meter as unit of measure.
- 2019/07/15: Version 1.25.0 Support for font collections (mainly CJK fonts) and for non-ASCII font names.
- 2019/07/28: Version 1.26.0 Support for XMP Metadata and QR Code ECI Assignment Number.
- 2020/09/09: Version 1.27.0 Fix out of memory problem related to PDF417 barcode. The problem only occurred under unusual circumstances.
- 2021/03/31: Version 1.28.0 Upgrade of the internal file structure to include object streams and cross reverence streams.
-
- 2022/02/01: Version 2.0.0 PDF File Writer II Version.