You are on page 1of 40

Create PDFs in ASP.

NET / C#

Michéle Johl

Getting started with iTextSharp

The .NET framework does not contain any native way to work with PDF files. So, if you want to generate or work with PDF files as part of your ASP.NET web application, you will have to rely on one of the many third party components that are available. Google will help you to find one that fits your budget, as well as a range of open-source free components. One of the free components is iTextSharp, which is a port of a well known Java utility, iText. The main problem with iTextSharp is that it lacks documentation. There are some basic tutorials available, but most programmers have to resort to trying to wrestle with the documentation provided for the Java version - iText - to get going with the component, or you may want to purchase the book iText In Action. However, this only provides guidance in Java. Many of the code samples are transferable to C# without a lot of modification, but if you are relatively new to C#, you may frequently become frustrated with undocumented or inexplicable differences in classes and method names between the two versions. As a final resort, you can always use Reflector to pick the dll apart and examine its innards. So, as part of a series of How To articles, here's how to get started using iTextSharp with code samples in C#. First thing to do is to download the component from here. You will be presented with a .zip file containing itextsharp.dll. Unzip this, and save it somewhere on your machine. Now create a new Web Site from within Visual Studio or Visual Web Developer. Make sure that you have added the Bin folder from the options in the Add ASP.NET Folder option. Right-click on the Bin folder and select Add Reference. The dialogue box should appear. Choose the Browse tab, and locate the dll you saved earlier.

Then select it and click "OK". That's it. The dll will be copied to your Bin directory, and is now available to the web site or project.

I have also added a folder called PDFs in which I plan to store my generated files. To avoid typing full references to the dll, it is best to add a couple of using statements to the default ones in your code-behind: using iTextSharp.text; using iTextSharp.text.pdf; You will also want to reference System.IO, as you will be creating, opening and closing files, and classes in this namespace are required. The principal object within iTextSharp is the Document object. You need to create an instance of this to be able to work with your PDF in memory. So, the first thing to do is to instantiate one: var doc1 = new Document(); This creates a PDF document object in memory with the default settings. The size of the document by default is A4 (which measures 210mm x 297mm, or 8.26 inches x 11.69 inches). Margins are set at half an inch all round. The next thing to do is to commit the document to disk. The iTextSharp.text.pdf.PdfWriter class is required for this: //use a variable to let my code fit across the page... string path = Server.MapPath("PDFs"); PdfWriter.GetInstance(doc1, new FileStream(path + "/Doc1.pdf", FileMode.Create)); Now to begin actually working with the document, open it, and add a new paragraph, then close it: doc1.Open(); doc1.Add(new Paragraph("My first PDF")); doc1.Close(); That's it! If you refresh the PDFs folder in your web site, you will see that a new item - Doc1.pdf has been added, and opening it will reveal your success. It may be, however, that you don't want to always create a PDF with the default size and margins, so iTextSharp provides ways for you to customise these settings. There are 2 further constructors to the Document object: public Document(iTextSharp.text.Rectangle pageSize); public Document(iTextSharp.text.Rectangle pageSize, float, float, float, float); The first one can be used like this: var doc = new Document(PageSize.A5); The PageSize class contains a number of Rectangle objects representing the most common paper sizes from A0 to A10, B0 to B10, LEGAL, LEDGER, LETTER, POSTCARD, TABLOID and so on. If you want to apply a custom size that isn't available within the PageSize class, you define your own Rectangle object, set its properties and pass that into the constructor as an argument: var doc = new Document(new Rectangle(100f, 300f)); PdfWriter.GetInstance(doc, new FileStream(path + "/Doc2.pdf", FileMode.Create)); doc.Open(); doc.Add(new Paragraph("This is a custom size")); doc.Close(); In this case, a PDF document was created with the width being 100 points, and the height set at 300 points. There are 72 points to an inch, so this particular document isn't very large. It's in fact 1.39 inches x 4.17 inches. (You will probably find that as well as iTextSharp.dll, a calculator will be very handy....). The second constructor which takes a Rectangle object and a series of 4 float values allows you to set your custom margins through the floats. Again, these values are measured in points. The default half inch margins are 36 points. If you use the PageSize class constructor, or a Rectangle directly, you can also set the background colour of the document. This can be done using RGB colour values, or CMYK (Cyan - a kind of blue, Magenta - a pinkish red, Yellow and "Key", or black). It used to be that if you wanted to prepare a PDF for printing by a professional lithographic printer, you had to ensure that all colours were CMYK, but with greater adoption of digital printing by printing companies, RGB is becoming more acceptable. Certainly, for display on the web, RGB is preferred. To set the background colour, we use the BackgroundColorproperty of the Rectangle object:

124).BackgroundColor = new Color(191. 25. r.r. Both of the above result in a rather fetching pinkish colour for the document. .BackgroundColor = new CMYKColor(25. 90. 0). 64.

Working with Fonts .

PdfWriter.RegisteredFonts collection holds them. Times Roman Bold and Italic. doc. BaseFont bfTimes = BaseFont.pdf". this decreases the overall size of the document. that's usually C:/WINDOWS/Fonts. 12pt. and further setting the font size in points.GetFont() method. Times Roman Italic.RegisterDirectory("C:\\WINDOWS\\Fonts"). and only sets up the definition of a font. Font times = new Font(bfTimes. and the third is to instantiate a new Font object.CP1252. using iTextSharp's constants for these values. Document doc = new Document(). The above lines create a BaseFont object and uses the built-in constant values to set the font family and encoding. Times Roman. It also offers 14 overloaded constructors which gives you a lot more options to work with. Helvetica translates more or less to Windows Arial font. Courier Bold and Italic. doc. while Times Roman has an equivalent in Times New Roman. int totalfonts = FontFactory. colour.CreateFont() method.CreateFont() out of the way first. doc. a new Font object is created. Symbol. Times Roman Bold. the free PDF utility that lets you work with PDF files within ASP.GetInstance(doc. new Font() allows for propogation of font styles from one font to the next.Add(new Paragraph("This is a Red Font Test using Times Roman".Create)).GetFont(). I recommend that you do so now. FontFactory.ITALIC. this article looks at working with fonts in PDF documents that you create. The default font is Helvetica. the second is to use the FontFactory. Helvetica. On Win XP Pro.RED). iTextSharp has built-in support for the 14 Type 1 fonts: Courier. embedding. StringBuilder sb = new StringBuilder(). It also specifies false for embedding the font within the PDF document. Font.NET. Each time that you call FontFactory. new FileStream(path + "/Font. But we will get BaseFont. BaseFont. And the result (if all goes well) is as follows: Now to the FontFactory. A new Font object is created using the BaseFont object. If you want a list of all the registered fonts. style. size. false). black in the style typically known as Normal. Courier Italic. Now the font is put to use in a paragraph: string path = Server. or if you plan to get the PDF printed professionally. ZapfDingBats®. which includes all fonts found in the Windows default font directory. encoding and caching in pretty much any combination you like. but should be set to true if you are using fonts that are unlikely to be on the user's system.GetFont() method.GetFont() method .RegisteredFonts) { . Color. Helvetica Bold and Italic. the style and the colour .CreateFont(BaseFont. FileMode. Helvetica Bold.GetFont() returns a valid and new Font object that you can work with directly. This method will work directly with all fonts registered by iTextSharp.again. This method has 14 (count 'em!) overloads that allow you to specify anything from font family. For that reason. you are most likely going to use the FontFactory.Open().Close().Following on from my introduction to iTextSharp.CreateFont() is a lot more limited. Helvetica Italic. There are three principal ways to set the font to work with: one is to use the BaseFont. This can be useful if you want to find the exact name of each font. times)). the FontFactory.TIMES_ROMAN.MapPath("PDFs"). 12. foreach (string fontname in FontFactory. Courier Bold. BaseFont. If you haven't read the first article in this series.

CP1252.ITALIC.Add(new Paragraph(s.CreateFont(fontpath + "myspecial.GetFont("nina fett"). x. as your expensive font is unlikely to exist on users' operating systems.EMBEDDED. You may notice that the above example is embedded in the PDF file (BaseFont.Add(new Paragraph("All Fonts:\n" + sb.". BaseFont. font)). they use a constant value for the font style. while others use the SetColor() method and pass in RGB values or create a new Color object passing in RGB values. new Color(125. Here's a variety of ways to use the GetFont() method: Font arial = FontFactory. 16. Code Complete and the Object Browser will reveal the full panoply of options.Append(fontname + "\n"). x.MapPath(". Font.Size = 10. but you can pass in an int representing one of the values. There are also varying numbers of parameters passed. 12).GRAY). BaseFont. Registering Fonts You may have a situation where you cannot install a font you want to use in the default font directory on the web server. doc.GetFont("Arial". Intellisense.SetColor(100. BaseFont. . string fontpath = Server.SetStyle("Italic"). BaseFont. Font palatino = FontFactory. x."). Font font = new Font(customfont. Font. or use the SetStyle() method passing in a string. 50. 28.GetFont("Arial". string s = "My expensive custom font.sb.BOLDITALIC. 7). Color. Font verdana = FontFactory.EMBEDDED). BaseFont customfont = BaseFont. some of them use the iTextSharp Color object to set the colour using a constant. As you can see. 15)).GetFont( "palatino linotype italique". Font smallfont = FontFactory.GetFont("Verdana". } doc. which ilustrates some of the different overloads available. 88. Color.EMBEDDED). 200). so you have to register it explicitly with iTextSharp. Generally.ttf".CP1252.ToString())).GREEN ). 10. Font x = FontFactory.

Phrases and Paragraphs .Adding Text with Chunks.

all they should be used for is to change or set the style of a word or phrase inline.Open(). if you would like to read earlier articles.getting started with iTextSharp iTextSharp . It's ASP. setBackGround().GetFont("dax-black")). for (int i = 1. then write it to the PDF document 3 times: string path = Server. i++) { doc. Chunk c1 = new Chunk("A chunk represents an isolated string.Add(c1).MapPath("PDFs"). iTextSharp offers the Chunk.NewLine. or even Chunk. Before going on. Rectangle r = new Rectangle(400.5f). 300). doc.pdf".NEWLINE as part of the string you give a chunk. "). The following snippet shows how to set the text of a Chunk. PdfWriter.5f. you need to be careful how you use Chunks. Document doc = new Document(r). -1. } [Keep an eye on the following paragraph . as well as a number of constructors that permit you to set the font and its styles. As with the Label. You can of course force a newline using "\n" or Environment.This is the third in a series of articles that looks at using the open source component.SetUnderline(0.NET provide containers for varying ampounts of textual content. Phrase and Paragraph classes. which shows the text having been written to the document but it looks a mess. Chunks have no concept of how to force a new line when the length exceeds the available width in the document. i < 4. Just as HTML and ASP.Create)). they are: Create PDFs in ASP. new FileStream(path + "/Blocks.GetInstance(doc. chunk. and setTextRise().NET to generate PDFs. iTextSharp from within ASP. such as setUnderLine(). FileMode. FontFactory. Chunk chunk = new Chunk("Setting the Font". The chunk has a number of methods to allow you to do this.we will come back to it] The result can be seen below.NET . Really.NET equivalent is the <asp:Label>.Working with Fonts Chunks A Chunk is the smallest significant piece of text that you can work with. .

Paragraphs derive from Phrase.Phrases The Phrase is the next container in the hierarchy. Phrase phrase = new Phrase(). Since the default font-size was applied by iTextSharp (12pt). The following snippet shows how the earlier chunk is added to a phrase 3 times. Document doc = new Document(r). try { . and the result. i < 4. and will force a newline when the length of its contents exceed the vertical margins of the document. } Paragraphs What we have seen so far is the very basic building blocks for text in PDFs. The object that you will use most often is a Paragraph.5 times the font size. You can set the leading or font as part of initiating a new phrase. for (int i = 1.Add(c1). as well as pass it a string or chunk to set its content through the phrase's various overloaded constructors. i++) { phrase. The paragraph earlier in the Chunk section of this article is as good as any to experiment with. Rectangle r = new Rectangle(400. which is a sequence of Phrases and Chunks held together. or "leading") is 1. It has a number of sentences and some formatted inline text. The space between each line (actually the measurement taken between the baselines of each line.MapPath("PDFs"). the code below will result in a leading of 16pt. A phrase is an array of chunks. so they autommatically fit text within the horizontal boundaries of the document. but they also force a new line for each paragraph (just as in any word processing application). so we can use that to build a paragraph from chunks and phrases: string path = Server. 300).

Replace(Environment. Chunks have no concept of how to force a new line when the length exceeds the available width in the document. 9f). courier). lightblue). brown).Replace(" ".Add(c2). text = text. p2. p2.Add(c4). p2.Add(p). courier). georgia). Chunk c1 = new Chunk("You can of course force a newline using \"". new Color(43.Add(p2). Phrase p2 = new Phrase(). the result. georgia).Color = Color. Chunk beginning = new Chunk(text.Add(c6). 9f. 10f).NewLine. Font lightblue = new Font(Font. 145. all they should be used for is to change or set the style of a word or phrase inline. } catch (IOException ioex) { throw (ioex).PdfWriter. Really.Open(). georgia).GRAY. georgia). p2. } finally { doc. } catch (DocumentException dex) { throw (dex). Font.Add(c3). Font georgia = FontFactory. } First.Add(c5). p2. Chunk c6 = new Chunk(". lightblue). which shows the text having been written to the document but it looks a mess. Font courier = new Font(Font. p2.Add(p1). ". FileMode.NORMAL. 9f. Chunk c3 = new Chunk("\" or ".GetFont("georgia".GetInstance(doc. new Color(163. p2. doc. Chunk c2 = new Chunk(@"\n". p2. String. p. Font. doc.COURIER. 21)). Font brown = new Font(Font. Paragraph p = new Paragraph(). then some notes about the code: .Add(c7).COURIER.Empty).Create)). new FileStream(path + "/Blocks2. string text = @"The result can be seen below.Add(c1).NEWLINE". or even ". Chunk c8 = new Chunk(".Empty). Chunk c4 = new Chunk("Environment". 175)). Phrase p1 = new Phrase(beginning).".NORMAL.Close(). georgia). Chunk c5 = new Chunk(". String. Chunk c9 = new Chunk(" as part of the string you give a chunk. p.NewLine". georgia. p2.Add(c9).pdf".Add(c8). Chunk c7 = new Chunk("Chunk".COURIER. 21.

IndentationLeft //allows you to add space to the left hand side Paragraph. with "Left". in that I passed in the value Font. otherwise it will appear with them preserved in the resulting PDF. and prevents the sort of mistake I experienced happening again. which is the value that the constant is set to. "Justify". There is another source of exceptions that I found to be rather sneaky.NORMAL before the size. which is @-quoted.It didn't take long to start adding Exception handling to the code. and "Right" being valid values.setSpacingBefore //adds a specified amount of space above the paragraph Paragraph. The following shows the earlier example with p. It is also possible to set the alignment of the paragraph text. You will also notice that the font size values are now passed in with the f suffix following them. So. and with iTextSharp Document objects. The first block of text.FirstLineIndent //allows you to apply a float value to indent the first line Paragraph. Finally both phrases are added to the single Paragraph object. so that at least the document object is released. catch when performing IO operations. "Center". each individually styled string is applied to its own Chunk object. there is also a DocumentException object to manage. or a verbatim string literal.Close(). and then added to a Phrase to ensure that lines are wrapped in the PDF.setAlignment("Justify"). exception handling starts to make its appearance. Other than that. needs to have all the whitespace and newlines removed from it. Of course. and I have to shut down VS to release its hold on the document object..IndentationRight //allows you to add space to the right hand side Paragraph. you should always use try. This had the effect of setting the font size to 0. The Paragraph class has a number of other useful methods and properties for styling including: Paragraph. An exception is thrown when trying to call doc. When testing the code to generate the PDF file.setSpacingAfter //adds the specified amount of space after the paragraph . I inadvertently transposed two arguments in the constructor for the font I called lightblue.. That explicitly tells the compiler that the value is to be treated as a float. This accepts a string. using the Paragraph.setAlignment() method.

Lists with iTextSharp .

If you are coding your PDF generation within an ASP. which also includes a ListItem class.text.Web. } If you are not familiar with the concept.Add(list). "it. and to pass in a bool to indicate whether it is an ordered. The default is false. try { PdfWriter.WebControls. ListItem inherits from Paragraph (which inherits from Phrase. string text = "Lists".cs file is created.List list = new it. FileMode.pdf". doc. it.Document().getting started with iTextSharp iTextSharp . Actually. paragraph.text. A List is a collection of iTextSharp. Lists can be UNORDERED or ORDERED (numbered). All that extra typing can get very boring.the first thing is to create a new List object.text.Working with Fonts iTextSharp .Message). Phrases and Paragraphs Lists are generated from the iTextSharp. it is an ArrayList of ListItem objects. The code . which inherits from ArrayList).Add(text). doc.List.NET .Open(). list. list.ListItem("One")). } catch (it. list. You may want to review earlier articles in this series.Document doc = new it.DocumentException dex) { Response. you will probably be working with the default set of namespaces that Visual Stuido references when the aspx.Paragraph().Add(new it. so each item in the list is rendered on a new line. Back to what the code actually does . to your code will result in a warning of ambiguity. As you can see.UNORDERED)." is used as a prefix for some objects. this article turns its attention to lists. list. As with their html <ul> and <ol> counterparts. new FileStream(path + "/Lists.Add("Three").UI.Having already looked at how to create a PDF document with iTextSharp.Add("Five").Add("Two").Create)).List object.Write(ioex. Diving straight into code. Now you can use the alias instead. so you can shortcut the namespace by providing an alias to it: using it = iTextSharp. it.ListItem objects. or numbered list or not. One of those namespaces is System. doc.GetInstance(doc.Message).Write(dex.Add("Four"). the way that a List or ListItem is referenced in the above code needs explaining.Adding Text with Chunks. } catch (IOException ioex) { Response.List(it.ListItem li = new iTextSharp. That means that attempting to simply add ListItem li = new ListItem(). Create PDFs in ASP. The way to resolve this is to fully reference the ListItem class you are attempting to use by adding its namespace: iTextSharp.MapPath("PDFs").Close(). here's how to generate a List: string path = Server.text.NET code-behind file. } finally { doc. if you haven't already done so. Ordered and unordered lists will be covered.ListItem().text. it.Add(paragraph). list. set fonts and their styles and add text.Paragraph paragraph = new it.

A second argument (float) is passed in to the List constructor. followed by the List being added to the document. for example. The second and subsequent items are added directly to the List object as strings. a Paragraph is created and added to the document. which sets the symbolIndent value at 10 points. in that it occupies a new line. the actual symbol is changed to the more traditional bullet point using the setListSymbol() method. The first is added by creating a new ListItem object. iTextSharp provides ways to format the List so that it looks a lot better. Finally. it.UNORDERED.List list = new it. This results in the space between the symbol and the item itself being increased. Secondly. and none of the usual indentation that you would get if you were using Microsoft Word. You will also note that the default settings provide a boring list with hyphens as symbols for each ListItem.SetListSymbol("\u2022"). Finally. the List is indented 30 points from the left margin of the document.List(it.List.doesn't do much more except add 5 items to the list. you can use the RomanList class: . list. each item acts like a Paragraph as promised. list. and setting its string value.IndentationLeft = 30f. The result is this: As you can see. 10f). The result looks a little more pleasing: If you like your ordered lists with Roman numerals.

zlist.Add(zlist).ZapfDingbatsList(49.Add("Three"). zlist. Since the List. zlist.Add("Four"). romanlist. and two further classes: ZapfDingbatsList and ZapfDingbatsNumberList offer more symbol formatting opportunities as they make use of the ZapfDingBats font. romanlist.Add("Five"). doc. The first argument is a bool that tells iTextSharp whether you want lowercase symbols or not.Add("Two"). and iTextSharp indents the RomanList relative to the ordered list to which it belongs: .Add("Three"). romanlist. The Greek and Roman lists should never be used for lists that contain more than 24 and 26 items respectively.Add() method accepts an object.RomanList romanlist = new RomanList(true.Add(romanlist). doc. For some odd reason. 20).Add("One"). ZapfDingbatsList zlist = new it.Add("One"). The following code creates a RomanList first. Lists can also be nested. all you need to do is to pass in a valid List() object. instead of a float. A separate GreekList class supplies list symbols as Greek letters. The RomanList is added to the ordered list.IndentationLeft = 30f. and the ZapfDingBatsNumberList can only cope with a maximum of 10 items before the numbering runs out and becomes 0. zlist.Add("Four"). romanlist.Add("Two"). romanlist. the symbolIdent value passed into the constructor is an int this time. romanlist.Add("Five"). zlist. then an ordered list. 15).

romanlist.SetListSymbol("\u2022").Add(romanlist).Add("Two").Add("Three"). romanlist.Add("One").Add("Four"). 20). list. list.Add("Five").Add("Five").RomanList romanlist = new RomanList(true. romanlist. doc.Add("Three"). romanlist. doc. List list = new List(List. . list. list.Add("Four").ORDERED. list.IndentationLeft = 10f. list.Add(list). romanlist. romanlist.Add(paragraph). list.Add("Roman List").Add("Two"). list.IndentationLeft = 20f.Add("One"). 20f). list.

Links and Bookmarks .

Message).Write(ioex. Document doc = new Document(). anchor. Font. doc. } finally { doc.mikesdotnetting. I suggest applying underlining and a blue colour to the font. try { PdfWriter. Phrases and Paragraphs Lists with iTextSharp Links iTextSharp Anchor objects are very similar to their HTML counterparts. in that they permit you to create hyperlinks both externally from the document. You may want to review earlier articles in this series.Open(). which when clicked will open a browser at this site. FileMode.UNDERLINE.com".Close().Reference = "http://www.GetInstance(doc. doc. iTextSharp adopts the same model: . } catch (IOException ioex) { Response.com". if you haven't already done so.MapPath("PDFs"). link). 0. this particular contribution will introduce the basics of linking and bookmarking PDF documents created via iTextSharp.Create)). For that reason. 12. and internally within the document. Internal links within an HTML document are specified by adding a NAME attribute to an <a> tag. Font link = FontFactory. } catch (DocumentException dex) { Response.Message).Write(dex. Create PDFs in ASP.Add(anchor).mikesdotnetting.Working with Fonts iTextSharp .Adding Text with Chunks. new FileStream(path + "/Anchors. Where they diverge from the HTML <a> element is that by default. as this should help users identify an Anchor as providing some functionality: string path = Server. Following earlier articles in my iTextSharp series.Interactivity within PDF documents is enabled though Anchors (links) and Bookmarks. Anchor anchor = new Anchor("www.pdf". they do not adopt any special styling within a PDF.getting started with iTextSharp iTextSharp . new Color(0.GetFont("Arial". } The code sample above creates an external link.NET . 255)).

iTextSharp provides the functionality to generate this tree-view through its Chapter and Section classes. p3. just as with the HTML version.Add(target). with a Name attribute set to match the Reference value in the Anchor in the first paragraph. The first chunk is added using the font that's set up to convey to users that the text should act as a hyperlink.Add(new Chunk(" to find local goto")). p4. A number of empty lines are added followed by another chunk.Add(new Chunk("Click ")). When rendered to the PDF. and clicking on it brings "Local Goto Destination" to the top of the screen. and SetLocalDestination() methods of the Chunk class. Anchor target = new Anchor("This is the Target"). The first paragraph contains the text "Click to go to Target". An alternative to using Anchors to set internal bookmark targets is to use the SetLocalGoto(). Bookmarks Often when you open a PDF file. It's matches the one set in the SetLocalGoto() method earlier.Add(p1).Add(p3).Reference = "#target".Add(p2). the word "here" is underlined and in blue. p4. doc. Paragraph p5 = new Paragraph().Add(p4). your PDF Viewer application displays a tree-view of the structure of the document. Paragraph p3 = new Paragraph().Add(new Chunk("here". The Chunk.Add(p5). Paragraph p2 = new Paragraph(). p4. p1. p4.SetLocalGoto("GOTO")). and its reference is set to "#target". link). p5. doc.SetLocalDestination("GOTO")).SetLocalGoto() method accepts a string. The second paragraph adds some empty lines and the final paragraph contains a new Anchor. Paragraph p1 = new Paragraph(). click. doc.Anchor click = new Anchor("Click to go to Target").Add(new Chunk("Local Goto Destination"). The result is that if you click on the "Click to go to the Target" text. doc.Add(click). again with a string defining the location of the target. This one has its SetLocalDestination() method invoked. which acts a a label for the target. target. the PDF will immediately reposition itself so that "This is the Target" will be at the top of whatever PDF viewer you are using. p2. with each branch or leaf acting as a link to the corresponding chapter or section. doc.Add(new Chunk("\n\n\n\n\n\n\n\n\n")).Name = "target".Add(new Chunk("\n\n\n\n\n\n\n\n")). . Paragraph p4 = new Paragraph().

Chapters and Sections are pretty memory hungry. 1).The top-level object is a Chapter.BookmarkTitle = "Changed Title". Section section2 = chapter1. 3).2. Section subsection3 = section3. 2). "Sub Subsection 1.AddSection("Section 2.Add(chapter1). Section subsection1 = section2. Sections cannot be added alone. 4). this might be a taks best scheduled for quieter times on your web server. The rest of the code that adds Chapters and Sections should be straightforward. Section subsubsection = subsection2. 2). Section section1 = chapter1. chapter2.1". "Section 1.2. chapter1.AddSection(20f. The final lines of code show that the actual entry in the Bookmarks can be changed from the title on the page by setting the BookMarkTitle property to another string value. 2). "Section 1.1 is set to appear as a second-level entry on the tree.AddSection("Subsection 2. Initially. The image above helps to explain the preceding code.AddSection(20f.2. 3). Then the outline view for the tree is set as open for Chapter 1. chapter1.1". The second argument is the number of the Chapter .1".BookmarkOpen = false. In this case. a Chapter object is created with a Paragraph passed in as the first argument. both Chapters are added to the document.2.AddSection("Section 2. Section subsection2 = section2.AddSection(20f. Nest. Section section3 = chapter2. so they should be used judiciously. "Subsection 1. Subsection1 is added to Section 2 and has been told to appear as a third-level entry in the tree.1".in this case 1. a Section object is added to the Chapter. the title of the Section to appear on the page and in the Bookmars.2". If you need to create a document such as a manual on a regular basis.Add(chapter2). which will always begin on a new page.1).1.2". Finally. or parent Section objects: Chapter chapter1 = new Chapter(new Paragraph("This is Chapter 1"). doc. but closed for Chapter 2.AddSection(20f. 3). Section 1.2". with 3 arguments: a float specifying the left indentation in points. "Subsection 1. doc.1". and the indentation depth for the entry in the Bookmarks tree. 2).AddSection(20f. but must be added to Chapter objects. . Section section4 = chapter2. Chapter chapter2 = new Chapter(new Paragraph("This is Chapter 2").BookmarkOpen = true.

Introducing Tables .

the integer 3 being passed into the constructor. At its most simplest. here is how to create a table and add it to a document: PdfPTable table = new PdfPTable(3). . //fix the absolute width of the table table. just as in HTML. //relative col widths in proportions .AddCell("Col 1 Row 2"). Phrases and Paragraphs Lists with iTextSharp iTextSharp .AddCell("Col 3 Row 2"). This overview is not an exhaustive examination of tables.AddCell("Col 2 Row 2").SetWidths(widths). PdfPCell cell = new PdfPCell(new Phrase("Header spanning 3 columns")). especially as many of the property names are so similar or identical to their counterparts within CSS and HTML. cell. table. It also shows some other options that can be used for styling and presenting the table: PdfPTable table = new PdfPTable(2).AddCell("Col 2 Row 1"). Following that.Adding Text with Chunks. 2f }.Working with Fonts iTextSharp . cell.HorizontalAlignment = 1.NET .TotalWidth = 216f.AddCell("Col 1 Row 1"). The Colspan is set to 3. //actual width of table in points table.SpacingBefore = 20f.NET applications to provide the structure for documents such as orders and invoices. which means that the cell will occupy the full width of the table. //leave a gap before and after the table table.1/3 and 2/3 float[] widths = new float[] { 1f. table. two rows of cells are added using the AddCell() method and the table is finally committed to the currently open document.LockedWidth = true. so for the avoidance of doubt. table. doc. I will be using the PdfPTable class. table. The PdfPTable object is instantiated as a three column table .Tables will probably be one of the most used elements in PDFs generated from ASP. table. but provides an introduction to working with them through iTextSharp. table. which is designed specifically for use within PDF documents. All possible values are shown as a comment.Colspan = 3. table. and presents the resulting data in a table.AddCell("Col 3 Row 1").Add(table). There is more than one class in iTextSharp that can be used to create tables. 1=Centre. The first cell is set as a PdfPCell object.getting started with iTextSharp iTextSharp .Links and Bookmarks Working with tables using iTextSharp is not that difficult. 2=Right table. //0=Left. which can take a Phrase object in one of its 7 constructors. and builds on the previous articles in this iTextSharp series: Create PDFs in ASP.AddCell(cell). The following effort queries a database. Cells can be added in a number of ways.HorizontalAlignment = 0. table.SpacingAfter = 30f. The horizontal position of the text within the cell is set using one of three possible values. table.

table. using the same value as that used for aligning the table in the document. for example: float[] widths = new float[] { 100f.Open(). ProductName FROM Products". try { conn.ToString()). using (SqlConnection conn = new SqlConnection(connect)) { string query = "SELECT ProductID.Add(table). Then the width of the table is set in points. where a quick tap of the Enter key has the same spacing effect.ToString()). SqlCommand cmd = new SqlCommand(query. which is treated as a header by setting the colspan to equal the number of columns in the table.HorizontalAlignment = 1.Trusted_Connection=True.Read()) { table. conn). A gap is created before and after the table by setting the SpacingBefore and SpacingAfter properties. The width of the columns themselves are set relatively at one third and two thirds of the total table width.PdfPCell cell = new PdfPCell(new Phrase("Products")). using (SqlDataReader rdr = cmd.AddCell(rdr[1]. string connect = "Server=. cell. 116f }. and fixed. } } } catch(Exception ex) { Response.".Message).Write(ex. you would pass in 1f and 4f respectively. cell.ExecuteReader()) { while (rdr.\\SQLEXPRESS. and the text in the cell is centre-aligned. The border is removed from the first cell. as the default behaviour is to pin subsequent tables to the previous one. This is useful if you have more than one table following on from another. To set it a one fifth and 4 fifths. } doc. } The table is initally created with 2 columns.AddCell(rdr[0]. cell.Border = 0. the data is consigned to cells which are added to the table: . Then the database is queried and the data returned in a SqlDataReader.Database=Northwind. table.AddCell(cell). You can slo set the absolute widths by passing in values that together total the table width. as in MS Word. As it is read.Colspan = 2.

The following code creates a four column table. three row table is nested within the bottom left cell. table.AddCell("Cell 3").BorderColor = new Color(255. Well.0). and vertically by three rows. that's the final appearance.YELLOW)))..AddCell(cell). cell. As you will see. with the bottom right cell stretching horizontally across three columns.The following snippet illustrates some of the options for formatting cells. new Font(Font. Color.PaddingBottom = 10f. the creators of iTextSharp have followed the CSS names for properties as much as possible to make working with styling syntax as easy as possible (if you know your CSS. table.PaddingLeft = 20f. but what actually happens is that a single column. But what about vertically? In HTML you would use the Rowspan property.242. 150.BorderWidthBottom = 3f.Border = Rectangle. doc. cell. cell. but there is no equivalent in iTextSharp. Font.NORMAL.AddCell("Cell 1"). cell. PdfPCell cell = new PdfPCell(new Phrase("Cell 2". cell. 8f. The cell that the table is nested within has its padding removed so that the table occupies all of the available space within it. of course.BOTTOM_BORDER | Rectangle.Add(table)..TOP_BORDER.BackgroundColor = new Color(0.BorderWidthTop = 3f.HELVETICA. cell.PaddingTop = 4f. cell. We have seen on a number of occasions how a cell can stretch horizontally through the use of the Colspan property. So the answer is nested tables. 0).) PdfPTable table = new PdfPTable(3). table. cell. .

The Rotation property must be set to multiples of 90. nested. Intellisense or the Object Browser within Visual Studio reveals a lot of methods and properties that are worth experimenting with to see their results. In the meantime. The default direction that the content is rotated is anti-clockwise. PdfPCell bottom = new PdfPCell(new Phrase("bottom")). PdfPCell nesthousing = new PdfPCell(nested).LockedWidth = true. doc.AddCell(nesthousing). table.AddCell("Nested Row 2"). header.Add(table). in this look at tables.Colspan = 3. The middle cell is set to 90.TotalWidth = 144f.AddCell("Cell 3"). . or an error occurs. table. nested. PdfPCell middle = new PdfPCell(new Paragraph("Rotated")).AddCell("Not Rotated"). and I will cover additional functionality in future articles. PdfPTable nested = new PdfPTable(1).AddCell("Nested Row 1"). table. table.AddCell("Cell 1"). table. middle.PdfPTable table = new PdfPTable(4). table.AddCell(header).Rotation = 90. nesthousing.AddCell(middle). PdfPCell left = new PdfPCell(new Paragraph("Rotated")). we see how the text content of a cell can be rotated (which is rather natty).LockedWidth = true. doc. left. nested.AddCell(left).AddCell("Cell 2"). table. table. table.AddCell("Nested Row 3").Colspan = 4. table. PdfPCell header = new PdfPCell(new Phrase("Header")). PdfPTable table = new PdfPTable(3). The result is below: There is an awful lot more to working with tables in iTextSharp.AddCell(bottom).TotalWidth = 400f. but 270 would have had the same effect. table.Add(table). bottom. table.AddCell("Cell 4"). table. Finally. table.Rotation = -90.Padding = 0f. table.HorizontalAlignment = 0.

Drawing shapes and Graphics .

PageSize. cb.Height / 2). This also means that instead of just invoking the GetInstance method of the PdfWriter.MoveTo(0.The previous iTextSharp article looked at bringing images into a PDF file and working with them. cb. FileMode. iTextSharp includes a lot of functionality that covers simple drawing to quite complex shapes. which in this case is halfway across the document.PageSize. try { PdfWriter writer = PdfWriter.Height).. you may want to draw shapes and lines within the PDF and not rely on images. Now that we have a working PdfContentByte object.GetInstance(doc.. all content added to the PDF documents in previous articles have relied on Simple iText. The next line draws a line from this point to the position specified in the LineTo() method. which is still halfway across the document. but really only describes our intention. cb. Sometimes. cb. doc.Stroke().PageSize. y coordinates specified in the parameters passed in. Actually.PageSize. Document doc = new Document().PageSize. at a position halfway up the document to the righthand edge at the same height . Phrases and Paragraphs Lists with iTextSharp iTextSharp . Previous articles are listed below: Create PDFs in ASP.Open(). doc. . doc. PdfContentByte cb = writer.Width. in that we now need to use a PdfContentByte() object explicitly. string pdfpath = Server. new FileStream(pdfpath + "/Graphics.getting started with iTextSharp iTextSharp .pdf". cb.Create)).Stroke(). it doesn't "draw" it. The line is only actually committed to the document when Stroke() is called. . and halfway up (or the center point).Width / 2.DirectContent. Working with graphics needs a slightly different approach.Adding Text with Chunks. The second line is drawn from the lefthand edge.Height/2). but at the top of it.PageSize.LineTo(doc.Width / 2. This is obtained from the PdfWriter object's DirectContent.NET .Working with Fonts iTextSharp .Working with Images Up till now. which takes care of positioning content within the flow of a document. doc. doc.Height / 2). This article gets you started.so we end up with the top two quarters of the document outlined.PageSize. It also looks after creating new pages to accept overflow text etc. we can use it to start drawing: cb.MapPath("PDFs"). we actually need to instantiate a PdfWriter object.MoveTo(doc.Links and Bookmarks iTextSharp .Introducing Tables iTextSharp .LineTo(doc. however. The first line moves to the x.

100f). cb. there is a quicker way of delivering a square (or rectangle) using one of the convenience shapes provided by iTextSharp. cb. 200). 300).LineTo(100f. cb. 600f). but path not closed cb. cb. cb.Using the same methodology.Width-200f. 0f.SetColorFill(new CMYKColor(0f. cb. 0f)). 300). cb.MoveTo(310. cb. 100f. The next bit shows that is action.ClosePath(). 0f)). cb. placing a square in the top right quarter of the document: cb. cb. but not stroked or closed cb.LineTo(410. used to consign them to the document. cb. //Filled.Stroke(). 1f.MoveTo(190.SetColorStroke(new CMYKColor(1f.Fill().LineTo(310. each one illustrating the results of different methods other than Stroke().LineTo(200f.LineTo(290. cb. cb. 300). 0f.LineTo(290. 700f). stroked.MoveTo(100f. But first. 200). Four more squares are added to the page. //Filled.LineTo(200f. 200). 300). setting the Stroke colour to Cyan and the Fill colour to Yellow: cb. 700f). and Fill represents its internals bounded by the Stroke.LineTo(70. 300). such as PhotoShop or FireWorks.Rectangle(doc.PageSize. cb. We didn't need to explicitly specify the coordinates for the final side of the square.FillStroke(). cb. the Stroke colour and the Fill colour are set.LineTo(410.LineTo(170. However. 200). you will probably know that Stroke is the outline of an object. cb.LineTo(190. I have used CMYK as the colour space. ClosePath() automatically provides a line from the current position that we are at to the original coordinates. . we can add a square to the top left quarter: cb. cb.Stroke(). 600f). 600f. 300). If you have worked with any graphics packages. cb. //Path closed and stroked cb. 200).MoveTo(70. cb. 200). 0f.LineTo(170.ClosePathStroke().

and got my desired result. Rather irritatingly. followed by a value representing the radius. 255. so for 100% blue (Cyan) i could just have validly provided 3000f.LineTo(530. cb. First. 200). 100. here's an example of using another preset shape. the following code will do: cb. cb. that's the results I got when I tried it. All it did was reset to the default colour of black. but the x and y coordinates that are passed in represent the center point of the shape. Here's my red circle with a mauve border (2 points in width) in the first square: Moving on. height cb. 250f. 0). so 256 is the equivalent of 1. 0. To build on the oddity of this approach. Looking at the first of the 4 squares above. 200f. Providing values that represent the percentages works fine. Warm Red is referenced as C: 0%. 100f). The SetCMYKColorFill() method used just above accepts ints. cb. 0f. I applied the values you see above. K: 100%. rather than floats. and don't accidentally type in an extra zero. I thought maybe this method was working on percentages as I would expect with CMYK. Y: 100%. //Bottom left and top right coordinates . given that generally. a rectangle is drawn. I found you have to guess at the actual values required by the two methods concerning the use of CMYK colour I have used so far. The constructor for CMYKColor() requires four floats.or at least. so long as it is a valid float.Rectangle(100f. it is relatively easy to determine that the width and height is 100 points. then an ellipse is added to fit neatly within it to illustrate how the positioning works through the parameters supplied to the constructor: // x. When using a Rectangle object to represent a square or rectangle instead of drawing it.SetLineWidth(2f). I found out CMYKColor is built on the ExtendedColor class.SetCMYKColorStroke(255. Nope. 50f). the first two parameters represent the x and y coordinates of the bottom right hand corner. All I got was a washy pinky colour.ClosePathFillStroke(). If you do. //Path closed. 255.Fill().MoveTo(430. 200). 255. cb. and 510 is the equivalent of 255 . In fact. To add a circle to the square so that it fits nicely. the ellipse. 250 y. I also discovered that there is nothing to prevent you entering values above 255. 0f. and that something was being affected by the previous setting of the Fill colour. But I have provided values of 1f and 0f.SetCMYKColorFill(0. Eventually.LineTo(430. 100. it seems that iTextSharp subtracts 255 from whatever you supply. 300f. 0f. cb. and that the center point is at 120 x. and can accept ints up to 255 . 0 to represent Warm Red. The values are treated as being relative to eachother. so I originally supplied the value 0. cb. y of bottom left corner.which is reminiscent of the RGB colour values and really confusing unless you know. but workable if you stick to the usual CMYK percentages. width.Circle(120f. Strange. I thought perhaps there was a bug in there somewhere. stroked and filled cb. Anyway. I can provide any value I want. Other preset shapes include the Circle. 0). so I deployed the ResetCMYKColorFill() method in the hope that it did something. cb. Neither was intuitive. M: 100%. CMYK colours are represented as a series of percentages. The final two parameters are the width and height.cb. 300). For example.Stroke(). 300). enough of the digression.LineTo(530. cb.

and finally the radius of the rounded corners. 200f. . 200f.Stroke().LineTo(500f. 450f). 200f. cb.MoveTo(350f. 300f). 520f).Stroke(). The next example shows another preset shape. cb. 600f). cb. followed by the width and height.MoveTo(350f.MoveTo(118f. cb. Here's an example of a right-angled triangle with the right angle shown: cb. 520f. cb. When one of these are drawn. 518f). 20f). cb.MoveTo(120f. cb.RoundRectangle(100f.Stroke().LineTo(360f. cb. 520f). cb. I have also added a circle in the corner with the same radius as the corner itself to show how the radius of the corner works. 400f. cb. If the differences between the first and third parameter. Triangles are relatively simple to do. and the second and fourth parameter are the same. cb. you end up with a circle. cb.LineTo(122f.Circle(120f. just by drawing the three lines they require.Stroke(). 20f). 450f).ClosePathStroke(). cb. 522f). 460f).Stroke(). cb.Stroke(). height and radius of corners cb.LineTo(360f. cb. the rounded rectangle.LineTo(350f. I've placed a cross at the center of the circle: //Bottom left coordinates followed by width. 500f.LineTo(120f. 460f). the values passed in are the x and y coordinates for the bottom left hand corner. 450f).cb. cb.Ellipse(100f. cb.

then bends away towards the second control point at (450. 1f). cb. cb. and ends at (350. 150f). The curve will begin at the start point. 70f.LineTo(150f. control point 2 (x. cb.GREEN). The control points are used for directional purposes. and the distance between the start and end point themselves. and the second one is related to the end point. and head towards the end point in the direction of the 1st control point. you will have seen these control points. cb.Stroke(). Control Point 2. 350f. and are rarely hit by the path. It looks like this: I'm not really sure that shows a lot. The first control point is specified in reference to the start point. End Point cb. 30). cb. usually with little "handles" on the end of them which you can move to bend the curve. The curve heads towards the first control point at (150. How far it gets near the control point will depend on the distance between the start point and its control point. If you have ever used a Vector graphics package. 10f).LineTo(350f. 10f). so the curve only begins to move towards it. and two control points. //start point (x.MoveTo(200f. before arriving at the end point. cb. and the angle is altered: cb. like Photoshop or Fireworks.Stroke().Stroke(). cb. 30f.Stroke().y) cb. This effect is probably best illustrated by changing the second control point so that it is further away. 1f).SetColorStroke(Color.y). 70). 10f). cb. 150f). 70f.CurveTo(150f.y). 30f. Here's an example of a curve.MoveTo(200f. 150).Circle(150f. The second control point has a longer handle. //control point 1 (x.Curves and Arcs Bezier curves are important in Vector Graphics. cb.y) . and this starts to exert its influence on the curve along with the ultimate destination at a relatively early point in its journey.MoveTo(200f. so I will add in some "handles" that show the control points: cb. 450f. which is reflected in the way the line is "pulled" towards it.MoveTo(450f. 30f). 10). where they are based on mathematical equations rather than each individual point being specified along the path of the curve. and the end point and its control point. cb. They work by specifying a start point. end point (x. 70f).Stroke(). The first control point has a relatively short handle. that starts at (200.Circle(450f. //Start Point cb. //Control Point 1. an end point.

350f. while the new one is shown in green. 150f). cb. 30f. 550f.cb. cb. Top Right(x.Stroke(). cb.LIGHT_GRAY).MoveTo(550f.Stroke(). cb. 3f). 100f). The angle at which the arc is started is 270°. and only 90° of it are drawn. cb. An Arc is part of an ellipse. In this case.LineTo(552f.LineTo(350f. cb. The original curve is shown in black. 70f. cb.Stroke().LineTo(535f. the green line moves much further towards the second control point before finishing up at the end point. 150f). 90f). 130f. cb. 130). the ellipse will fit into a rectangle that has a bottom left corner at (350. 70) and a top right corner at (550.Stroke(). 95f). One is the Arc object. Since the new second control point is further away from the end point. cb. 270f. Extent cb.Stroke().MoveTo(550f. Start Angle. 100f.SetColorStroke(Color. The default direction that an ellipse is drawn is counter-clockwise. cb. cb.Stroke(). cb. 1f). 100f). 550f. and is at a slightly more obtuse angle. . which has been used in this instance to create the curved arrow illustrating the movement of the original and new second control points. Secondly. 100f). cb. the SetLineDash() method is shown for the first time in this series of articles.y). cb.CurveTo(150f.SetLineDash(3f. in that the green line starts just slightly beneath the original black one. which allows me to draw the arrow as a dashed line. //Bottom Left(x. 88f).y).SetLineDash(0f).Arc(350f. Now you can see that the increased length of the second "handle" has exerted its influence right from the start point. cb. There are a couple of other points to note about the code for the second curve. 100f.MoveTo(550f.Circle(550f. cb.

Working with images .

Note .Add(new Paragraph("GIF")).Image. gif.Message). png and wmf. } Alternative constructors that you may use include passing a URL or a System. new FileStream(pdfpath + "/Images. FileMode.Drawing. doc.Introducing Tables iTextSharp supports all the main image types: jpg.Open().MapPath("Images").Drawing.MapPath("PDFs").Create)). tif.Close().Image).Image object (as opposed to an iTextSharp. } catch (DocumentException dex) { Response. This article builds on the previous six which are listed below. Phrases and Paragraphs Lists with iTextSharp iTextSharp .GetInstance() method. Probably the most used option will be to pass a filesystem path and file name into the method: string pdfpath = Server.gif"). Document doc = new Document(). Image gif = Image.pdf".text. There are a number of ways to create images with iTextSharp using the Image.Adding Text with Chunks.Write(ioex. } catch (IOException ioex) { Response. } catch (Exception ex) { Response.GetInstance(doc.GetInstance(imagepath + "/mikesdotnetting. try { PdfWriter.Write(ex.Message).FromStream() method shows the use of namespace aliasing again . doc.Message).Write(dex. } finally { doc.The seventh article in my iTextSharp series looks at working with images.the following snippet that System. bmp.Links and Bookmarks iTextSharp .getting started with iTextSharp iTextSharp .NET . doc. string imagepath = Server.Working with Fonts iTextSharp .Add(gif). Create PDFs in ASP.

Add(new Paragraph("TIF Scaled to 300dpi")). and the depth to 2. tif.97 inches (72 points by 213. you can scale the image to 24%.Image. doc.6 points).17 inches wide by12.Add(tif). To achieve this.GetInstance(new Uri(url)). commercial printers require that colour images for printing have a resolution of 300 dpi. matches the number of points in an inch.Add(new Paragraph("JPG")). Generally.Open)) { Image png = Image. Increasing the resolution to 300 dpi will reduce the width to 1 inch. as was highlighted in the article Lists with iTextSharp to avoid clashes with the two different types of Image object: doc. FileMode. Image tif = Image.ImageFormat. So at the default 72 dpi. We can do that using the code above.36 inches deep.jpg".Image. string url = "http://localhost:1805/PDF/Images/mikesdotnetting. but the resolution of the resulting images in the PDF file is not that great. } It's difficult to tell from the images I have provided so far. using (FileStream fs = new FileStream(imagepath + "/mikesdotnetting. Now I want to place the .(sd. 72/300 * 100 = 24%. It measures 300 x 890 pixels.Add(new Paragraph("PNG")). doc. Image jpg = Image. That part is fine. Now. the final job would be a bit nasty. The image stays the same in terms of file size but occupies less space in the document. it will measure 4. I have a large tif file that I want to use as a logo on an A4 letterhead.FromStream(fs)).FromStream(fs).Png).Add(png). doc.GetInstance(imagepath + "/mikesdotnetting. If this file was being prepared for printing. doc.ScalePercent(24f).tif").Add(jpg). What you are actually trying to do is squeeze 300 pixels into the space that 72 normally occupies.GetInstance(sd. images are embedded at 72 dpi (Dots Per Inch) which coincidentally. By default. doc.png".

jpg").BorderColor = Color. I have in mind the top right hand corner. The following code takes an image of 800 x 600 and forces it to resize.BorderWidth = 5f.72f.ToString())). but I need to get a calculator out. which starts at the left hand edge of the document and finishes at the right hand edge of the document. jpg. The second represents the Y-axis co-ordinate which starts from the bottom of the document and goes to the top.PageSize. An A4 document is 595 points wide and 842 pixels high with a 36 point margin all around by default.tif"). The Y-axis co-ordinate is the height of the image + the margin away from the top of the document. jpg. doc. or 595 . and the margin and height of the image from the total height of the document for the Y-axis co-ordinate. into a rectangle measuring 250 points square. doc.Add(jpg). This image will butt right up to the right-hand margin.ToString())). Got my company logo in :-) Another scenario that might need to be catered for is to fit a user-supplied image into a fixed size box somewhere on a form. And fortunately.SetAbsolutePosition(doc. jpg. or 842 .Width .ToString())).36f . I don't really want to have to remember all the various sizes of different documents and do these calculations every time I want to set the absolute position of an element. 250f). doc.PageSize. SetAbsolutePosition() accepts 2 floats as parameters. doc.Add(new Paragraph("Original Height " + jpg.GetInstance(imagepath + "/Sunset.Border = Rectangle.(213. doc.ToString())).216.Add(new Paragraph("Original Width: " + jpg. The image is 72 points wide (1 inch) + the margin at 36 points (total 108 points) from the right hand edge of the document.ScaledWidth. The actual co-ordinate that needs to be passed in is the bottom left of the image position.PageSize object to do the work for me. Image tif = Image.6f).36f .BOX.GetInstance(imagepath + "/verticallogo. and I just remove the margin (36 points) and the width of the image (72 points) for the X-axis co-ordinate. doc. tif. doc. I don't have to.ScalePercent(24f). I've pinched the Sunset image that I found in the Sample Images folder in My Pictures that comes as part of the default install of WindowsXP to illustrate how to use the ScaleToFit() method to achieve this. Image jpg = Image.4 points from the bottom. jpg. doc.Add(tif).Width. tif.108 = 487 points along the X-axis. Cripes.6 + 36) = 592.300 dpi image in a particular position on the page. maintaining its aspect ratio.Width gives me the width in points of the document. .Add(new Paragraph("Scaled Width: " + jpg.Height .ScaleToFit(250f. I can use the Document.PageSize.YELLOW. The SetAbsolutePosition() method will do this.Height.Add(new Paragraph("Scaled Height " + jpg.ScaledHeight. The first represents the co-ordinate along the X-axis.

dignissim et.Add(new Paragraph("Resolution: " + Resolution)). Proin egestas leo a metus?"). And here's the result: If you use SetAbsolutePosition() you end up with the same effect as if you had set the Alignment property of the image to Image. ullamcorper vitae.UNDERLYING. . Phasellus id lectus! Vivamus laoreet enim et dolor. I have also taken the opportunity to add a yellow border to the embedded image. Fusce elit nisi. Nulla mauris elit.float Resolution = jpg. Suspendisse blandit blandit turpis. Integer arcu mauris. ultricies vel.WHITE. paragraph. in that text added to the document will run over the top of it.Add(paragraph). jpg. jpg.ALIGN_RIGHT.BorderWidthTop = 36f. Unless you want to achieve this kind of watermark effect. venenatis at. and the resulting resolution of the image. Vestibulum vestibulum dapibus erat. Paragraph paragraph = new Paragraph(@"Lorem ipsum dolor sit amet.ScaledWidth * 72f. libero.Alignment = Image. Integer ac turpis vel ligula rutrum auctor! Morbi egestas erat sit amet diam. viverra id. which is 5 points wide. commodo non. Nam in lectus ut dolor consectetuer bibendum. you need to use Image. laoreet id.GetInstance(imagepath + "/Sunset.TEXTWRAP | Image. accumsan eget.ScaleToFit(250f. luctus eget. facilisis quis. Vivamus suscipit. Nulla risus eros. porta quis. placerat at. Nunc dignissim consectetuer lectus.Width / jpg. doc. jpg. doc.ALIGN_JUSTIFIED. Donec nibh est. diam. 250f).BorderColorTop = Color. jpg.SpacingAfter = 9f. consectetuer sit amet.Alignment = Element. mauris.TEXTWRAP instead.Add(jpg). Morbi neque ipsum. Ut ut ipsum? Aliquam non sem. mollis quis. doc. jpg. adipiscing et. dolor? Suspendisse eleifend nisi ut magna. urna. hendrerit eu. and then shown the original dimensions. congue ac. libero. consectetuer adipiscing elit.jpg").IndentationLeft = 9f. blandit ut. followed by the scaled dimensions. jpg. Image jpg = Image.

You may ask why I didn't use SapcingBefore instead of adding a white border. and that's a good question.Rotation = (float)Math. you may be comfortable with this. Rotation by default is anticlockwise. I have no idea why this should be.In this instance. The float value represents an angle measured in Radians. If you did more Mathematics than I did at school. but if anyone does. which takes a float. The fact is that whatever I set the value to for SpacingBefore. or simply set the RotationDegrees property instead. Left and Right padding can be added using the IndentationLeft and IndentationRight properties. but if you are like me and ask "What??". .PI / 2. The following are equally valid and equivalent: jpg. you can either read this article on Radians and work out that a quarter turn (90°) is Pi / 2. it seemed to have no effect whatsover in this instance. I'll be pleased to hear from them.RotationDegrees = 90f. and a bit of padding to the left and bottom of the image to stop the text running right up to its edge. jpg. while SpacingBefore and SpacingAfter is used to pad the top and bottom.you can rotate them if you need to. I added a white border to the image to align it with the top of the text. One way to do this is to set the Rotation property. One final thing with images .