I am trying to create a pdf document in c# using iTextSharp 5.0.6. I want to add header and footer to every page in OnStartPage and OnEndPage events respectively.
In case of footer there is a problem that the footer is created right where the page ends whereas I would like to be at the bottom of page.
Is there a way in iTextSharp to specify page height so that footer is always created at the bottom.
Thanks!
The page's height is always defined:
document.PageSize.Height // document.getPageSize().getHeight() in Java
Keep in mind that in PDF 0,0 is the lower left corner, and coordinates increase as you go right and UP.
Within a PdfPageEvent you need to use absolute coordinates. It sounds like you're either getting the current Y from the document, or Just Drawing Stuff at the current location. Don't do that.
Also, if you want to use the same exact footer on every page, you can draw everything into a PdfTemplate, then draw that template into the various pages on which you want it.
PdfTemplate footerTmpl = writer.getDirectContent().createTemplate( 0, 0, pageWidth, footerHeight );
footerTmpl.setFontAndSize( someFont, someSize );
footerTmpl.setTextMatrix( x, y );
footer.showText("blah");
// etc
Then in your PdfPageEvent, you can just add footerTempl at the bottom of your page:
writer.getDirectContent().addTemplateSimple( footerTmpl, 0, 0 );
Even if most of your footer is the same, you can use this technique to save memory, execution time, and file size.
Furthermore, if you don't want to mess with PdfContentByte drawing commands directly, you can avoid them to some extent via ColumnText. There are several SO questions tagged with iText or iTextSharp dealing with that class. Poke around, you'll find them.
Related
I am using MigraDoc to generate a PDF. I want to align some content to the bottom of the last page. This is boilerplate disclaimer information that my company always includes in these types of documents. The goal is to keep the content altogether and always have it appear just above the footer on the last page. If there isn't room on the last page of actual content to keep it together, there should be a page break and the boilerplate content will be on a page by itself.
I would like to do this without measuring the height of the content.
I get the impression that I can use TextFrame to assist with this in some way, but I can't find any documentation on it. The questions and examples I've found online refer to being able to "absolutely position" the TextFrame, but none of the examples seem to do that, exactly.
As a starting point, I am trying to position a paragraph of text in the way I described on an otherwise blank page. Here's my latest experiment:
static void AddBoilerPlate(Section section) {
var sectionWidth = PdfSharp.PageSizeConverter.ToSize(PageSize.Letter).Width - section.Document.DefaultPageSetup.LeftMargin.Point -
section.Document.DefaultPageSetup.RightMargin.Point;
section.AddPageBreak();
var frame = section.AddTextFrame();
frame.RelativeVertical = RelativeVertical.Page;
frame.Width = sectionWidth;
frame.Top = ShapePosition.Bottom;
frame.AddParagraph(DisclaimerText);
}
The text starts just above the footer (the blue line in this screenshot) and then runs over the footer:
Once I get a paragraph of text aligned, then I think I will be able to use a table with one column and one row instead, and then put all of my content in there.
Update: here is a screenshot showing my goal (faked using a page break and SpaceBefore):
Update: here are some related articles that don't quite get me where I'm trying to go:
Centering a table on a page using a TextFrame: http://forum.pdfsharp.net/viewtopic.php?p=753#p753
Seems to answer the same question, but doesn't provide information about how to absolutely position the TextFrame: http://forum.pdfsharp.com/viewtopic.php?f=2&t=587
Keeping table together on a page ("in one piece"). This will be useful once I figure out the issue with aligning relative to the bottom of the page: Keep table in one piece MigraDoc / PDFsharp
Update: Note that adding a height to the TextFrame does make the text align the way I need it to. It's not ideal, because I would rather not hard-code the height. But it does produce the desired effect:
static void AddBoilerPlate(Section section) {
var sectionWidth = PdfSharp.PageSizeConverter.ToSize(PageSize.Letter).Width - section.Document.DefaultPageSetup.LeftMargin.Point -
section.Document.DefaultPageSetup.RightMargin.Point;
section.AddPageBreak();
var frame = section.AddTextFrame();
frame.RelativeVertical = RelativeVertical.Page;
**frame.Height = new Unit(75, UnitType.Millimeter);**
frame.Width = sectionWidth;
frame.Top = ShapePosition.Bottom;
frame.AddParagraph(DisclaimerText);
}
Update: Note, though, that setting the TextFrame height doesn't resolve the ultimate issue. Content added before the boilerplate should push the boilerplate to the next page if there isn't enough space for it, and that's not happening.
Update: After trying it out myself (I've had the same Problem), add an invisible element with the Height you want to have just before the bottom element. In case the invisible Element doesn't fit it will seem that the page break occurred because of the bottom element.
Works like a charm.
(tip I added a border to both elements for testing so I was able to make sure the layout was proper)
Is there a way to set fixed height of an element? Could be a table, row or section. This element is dynamically generated from database and it can have a variable number of rows. I need to do that, because the section below needs to be in a fixed position for print out. I am using WPF v1.31. I know it is not the latest, but it's an addition to a quite old application.
You can set the height of a Paragraph or a table Row.
I think you cannot set the height of a Table - but that will be the sum of the heights of all rows. Automatic page breaks will make things complicated if a table does not fit a single page.
A Section always starts on a new page.
TextFrame can be used to place text at a fixed position. Depending on the requirements, this could be simple or complicated.
You can prepare a document to let MigraDoc determine sizes and positions. Then you code can decide whether the items with the fixed position will be on the same page or on a new page.
Here is sample code that shows how to show the progress while creating a PDF:
http://forum.pdfsharp.net/viewtopic.php?f=8&t=3172
The same technique can be used to stitch several MigraDoc documents together to create a single PDF. If I understand your requirements correctly, this could be the way to go - without setting the height of any elements.
I use a Header in my Migradoc documents. Right now I just add a Paragraph to the Header but it doesnt really fit my needs as I want to have lets say two texts that have a different Alignment. For example:
Middle-ALigned.Text Right-Aligned-Text
second line second line
Before I used two textframes and added them to the section (not as Header). That worked somehow but cant be the right choice as I want to print the text on every page and thats what headers are for.
So the question is how do I align the two texts differently in one paragraph or how do I get two paragraphs to appear on the same height in the header.
I hope someone can help with that.
Cheers
Keep it Simple: Use a Tab Stop
The best way to do this is the same as you would do in most word processing tools: with a right-aligned tab-stop, placed on the right margin of the page, with the "left" text, being center-aligned. This is pretty straight forward, but I couldn't find the "full" solution anywhere, so here's what you need:
// Grab the current section, and other settings
var section = documentWrapper.CurrentSection;
var footer = section.Footers.Primary;
var reportMeta = documentWrapper.AdminReport.ReportMeta;
// Format, then add the report date to the footer
var footerDate = string.Format("{0:MM/dd/yyyy}", reportMeta.ReportDate);
var footerP = footer.AddParagraph(footerDate);
// Add "Page X of Y" on the next tab stop.
footerP.AddTab();
footerP.AddText("Page ");
footerP.AddPageField();
footerP.AddText(" of ");
footerP.AddNumPagesField();
// The tab stop will need to be on the right edge of the page, just inside the margin
// We need to figure out where that is
var tabStopPosition =
documentWrapper.CurrentPageWidth
- section.PageSetup.LeftMargin
- section.PageSetup.RightMargin;
// Clear all existing tab stops, and add our calculated tab stop, on the right
footerP.Format.TabStops.ClearAll();
footerP.Format.TabStops.AddTabStop(tabStopPosition, TabAlignment.Right);
The hardest part of this, is figuring out what your tab stop position should be. Because I'm boring and really like encapsulation, I dynamically calculate the tab stop position, based on the page width, less the horizontal page margins. However, getting the current page width wasn't as easy as I'd thought it'd be, because I'm using PageFormat to set the page dimensions.
Next Challenge: Getting Your Page Width, Dynamically
I really hate having tightly coupled code (think: fan-in and fan-out), so even though I know at this point in time what my page width is, even to the point of hard-coding it, I still want to hard code it in only a single place, then refer to that one place everywhere else.
I keep a custom "has-a"/wrapper class to keep this stuff encapsulated into; That's documentWrapper in my code here. Additionally, I don't expose any of the PDFSharp/MigraDoc types to the rest of my application, so I'm using ReportMeta as a way to communicate settings.
Now for some code. When I setup the section, I'm using the MigraDoc PageFormat to define the size of my page for the current section:
// The tab stop will need to be on the right edge of the page, just inside the margin
// We need to figure out where that is
var tabStopPosition =
documentWrapper.CurrentPageWidth
- section.PageSetup.LeftMargin
- section.PageSetup.RightMargin;
// Clear all existing tab stops, and add our calculated tab stop, on the right
footerP.Format.TabStops.ClearAll();
footerP.Format.TabStops.AddTabStop(tabStopPosition / 2, TabAlignment.Center);
footerP.Format.TabStops.AddTabStop(tabStopPosition, TabAlignment.Right);
footerP.Format.Alignment = ParagraphAlignment.Center;
What's really important here, is that I'm storing the CurrentPageWidth, this becomes really important when setting up our tab stops. The CurrentPageWidth property, is simply a MigraDoc Unit type. I am able to determine what this is by using MigraDoc's PageSetup.GetPageSize with my chosen PageFormat.
Results
You can add TextFrames to the header - then they will appear on every page.
Or use one paragraph as header. Use TabStops to position the text (as in Word there are left-aligned, center-aligned, and right-aligned TabStops. With TabStops you have to deal with the linebreaks like this:
(TabStop)Middle Text(TabStop)RightText(LineBreak)(TabStop)MT Second Line(TabStop)RT Second Line.
See also:
https://stackoverflow.com/a/29250830/1015447
So, I am writing some text into a PDF file using iTextSharp.
After having added a few paragraphs and phrases to the PDF document, I want to:
Draw the next piece of text on top of a rectangle that has a fill color, say, red.
I can compute the required width and height that the rectangle must have based on the text metrics of the text I am going to write on top of it. But how do I tell the Rectangle API what is top and left coordinates are, as in where it must be drawn?
Seems that you are looking for the Chunk.setBackground() method. This draws a colored background underneath some text. There's also a variation of the method that takes extra parameters if you need a larger or smaller rectangle.
Suppose that you don't want a colored rectangle, but a custom type of shape, then you'd use the page event onGenericTag(). See Chunk > Generic tag for more info.
The onGenericTag() method is triggered every time a Chunk that is marked as generic (using the setGenericTag() method) is rendered to a page. Your implementation of the page event can then use the Rectangle value that is passed to the event method. It is important to understand that a single Chunk marked as a generic tag can result in multiple invocations of this method: if the contents of a single Chunk needs to be distributed over different lines, the event will be triggered as many times as there are lines (giving you a separate Rectangle value for every separate line).
Hi I am using Debenu Quick PDF Lib.
I couldn't see any sample or info about creating custom size PDF document.
For example I want to create a new document in size of 80mm x 100mm in 300 dpi. Is that possible with QP ?
Thank you .
user3253797,
QP.SetMeasurementUnits(1); // Set the measurement units to mm
QP.SetPageDimensions(80.0, 100.0); // Set the page size to 80mm x 100mm
In a PDF file there is no DPI value as nearly all the values in a PDF are based on floating point numbers.
When SetMeasurementUnits is set to 1 then all values you use for drawing are assumed to be in millimetres. ie. QP.DrawLine(0, 0, 25.4, 25.4); will draw a diagonal line from the bottom left corner (0,0) to a point 1 inch up and 1 inch to the right of the bottom corner of the page. If you need the Origin to be based a the top right then you need to call QP.SetOrigin(1); first.
Also, the "Debenu Quick PDF Library 10 Developer Guide.pdf" is the perfect place to start to learn about Debenu Quick PDF Library. It explains the basics of creating PDF files using the library and some of the fundamentals of PDF files.
Andrew.
Disclaimer: I work for Debenu.