Using iTextSharp to construct header on multiple pdf pages - c#

I'm generating a PDF file based on a record selected in my datagridview. It will consist of 3-5 pages. I created a table with 2 columns to represent my header. the first cell is left aligned and the 2nd cell is right aligned. I want this same inforamtion displayed on all pages.
After doing some googling, I saw a header.WriteSelectedRows() property which is supposed to help with that? One example was :
header.WriteSelectedRows(0, -1, doc.PageSize.GetLeft(5), doc.PageSize.GetTop(5), wri.DirectContent);
2nd was:
header.WriteSelectedRows(0, -1, doc.LeftMargin, doc.PageSize.Height - 36, wri.DirectContent);
However both resulted in just the first page having the table/header. Any ideas on what I need to fix? Thanks!
Code:
PdfPTable header = new PdfPTable(2);
header.HorizontalAlignment = Element.ALIGN_LEFT;
header.TotalWidth = doc.PageSize.Width - 20f;
header.LockedWidth = true;
Phrase cell1 = new Phrase(signal.ProformaType);
Phrase cell2 = new Phrase("text" + Environment.NewLine + "text"
+ Environment.NewLine + signal.Signal);
PdfPCell c1 = new PdfPCell(cell1);
c1.Border = iTextSharp.text.Rectangle.NO_BORDER;
c1.VerticalAlignment = iTextSharp.text.Element.ALIGN_TOP;
c1.HorizontalAlignment = iTextSharp.text.Element.ALIGN_LEFT;
header.AddCell(c1);
PdfPCell c2 = new PdfPCell(cell2);
c2.Border = iTextSharp.text.Rectangle.NO_BORDER;
c2.VerticalAlignment = iTextSharp.text.Element.ALIGN_TOP;
c2.HorizontalAlignment = iTextSharp.text.Element.ALIGN_RIGHT;
header.AddCell(c2);
header.WriteSelectedRows(0, -1, doc.LeftMargin, doc.PageSize.Height - 36, wri.DirectContent);

The PdfPTable is added to the first page only because you are adding it to the first page only. If you want to add it to every page that is created by iText, you shouldn't add the PdfPTable where you are adding it now.
Instead you should add it in the OnEndPage() method of a page event. This is explained in answers to questions such as:
How can I add Header and footer in pdf using iText in java?
how to add an image to my header in iText generated PDF?
How to handle the case in wich an iText\iTextSharp table is splitted in two pages?
...
In other words, you need to create your own implementation of the PdfPageEvent interface. The best way is to extend the PdfPageEventHelper class:
public class MyPageHeader : PdfPageEventHelper
{
PdfPTable header = ... // define header table here
public override void OnEndPage(PdfWriter writer, Document document)
{
header.WriteSelectedRows(0, -1, document.Left, document.Top, writer.DirectContent);
}
}
To make this work, you need to declare this page event before opening the Document:
PdfWriter pdfWriter = PdfWriter.GetInstance(document, pdfFileStream);
pdfWriter.PageEvent = new MyPageHeader();
document.Open();
Now, every time a new page is created, the header will be added automatically.
You may want to adapt document.Left and document.Top in the code above, because right now, it will add the table in the upper-right corner of each page, you may want to use document.Left + 36 and document.Top - 5 or something like that.
Also: make sure that there is sufficient room for the header, otherwise your header will overlap with the content you are adding straight to the Document using document.Add(). You can change the margins in the constructor of the Document class.

Related

How to rotate PDF content in iText 7 Core?

I am trying to create a PDF with a mixture of Portrait and Landscape/Seascape pages.
I have rotated the pages to be Seascape where required but the content is still being output as portrait. I am reading the data in from an HTML file using iText's pdfHTML solution.
Below is some sample code I've used to do this.
var elements = HtmlConverter.ConvertToElements(htmlSource, props);
var pdf = new PdfDocument(new PdfWriter(pdfDest));
var pageOrientationHandler = new PageOrientationsEventHandler();
pdf.AddEventHandler(PdfDocumentEvent.INSERT_PAGE, pageOrientationHandler);
var document = new Document(pdf, PageSize.A4);
document.SetFontProvider(new DefaultFontProvider());
document.Add(new Paragraph(LOREM_IPSUM));
pageOrientationHandler.SetSeascape();
document.Add(new AreaBreak());
foreach (IElement element in elements)
{
document.Add((Div)element);
}
pageOrientationHandler.SetSeascape();
document.Add(new AreaBreak());
foreach (IElement element in elements)
{
document.Add((Div)element);
}
pageOrientationHandler.SetPortrait();
document.Add(new AreaBreak());
document.Add(new Paragraph(LOREM_IPSUM));
document.Close();
The PageOrientationsEventHandler class looks like this:
public class PageOrientationsEventHandler : IEventHandler
{
private PdfNumber _orientation = new(0);
public void SetPortrait()
{
_orientation = new PdfNumber(0);
}
public void SetLandscape()
{
_orientation = new PdfNumber(90);
}
public void SetSeascape()
{
_orientation = new PdfNumber(270);
}
public void HandleEvent(Event currentEvent)
{
PdfDocumentEvent pdfDocumentEvent = (PdfDocumentEvent)currentEvent;
var page = pdfDocumentEvent.GetPage();
page.Put(PdfName.Rotate, _orientation);
}
}
What I would like is for pages 1 and 4 to be portrait orientation with portrait content (i.e. a "normal" looking page with text) and pages 2 and 3 to be Seascape with Seascape content.
What I am seeing in the generated PDF is:
This current incorrect layout
But what I want to see is:
Something like this
Can somebody tell me what I am doing wrong?
NB: These images are just showing pages 1 and 2.
EDIT:
I think I've managed to work something out, but it doesn't feel like the correct way to go about it.
I've changed the code that adds the table from the HTML to this:
foreach (IElement element in elements)
{
document.Add((Div)element);
Div div = (Div)element;
div.SetRotationAngle(_radiansConverter.ToRadians(270));
div.SetWidth(PAGE_HEIGHT);
div.SetHorizontalAlignment(iText.Layout.Properties.HorizontalAlignment.RIGHT);
}
I am still using the page orientation handler to rotate the actual page, but also setting the table to rotate by 270 degrees, and then setting the width of the table to be slightly less than the height of the page.
Which is better than what I was after from the second image I posted (I messed up what I thought the orientation of the table should be).
Also the print preview for 2 x 2 looks like what I am after with the top of the table being aligned along the left side rather than the right:

How to remove footer template from first page?

Using cete Dynamic PDFtool I want to remove the footer template from the first page of the document. How to achieve this?
Page.Elements.Add(tblcontent);
Document.Pages.Add(Page);
The page class has an ApplyDocumentTemplate property that you can set to false, if you do not want a the template to be applied to a particular page.
Document document = new Document();
Template template = new Template();
// Add elements to template
document.Template = template;
Page page1 = new Page(PageSize.Letter);
// Add elements to page
page1.ApplyDocumentTemplate = false;
// Add additional pages leaving ApplyDocumentTemplate as true
// Save the PDF
document.Draw("output.pdf");
You can also accomplish this by using document sectioning. When a document is broken up into sections, each section can have its own template, or not have a template at all. In this following example, the first section doesn't have a template so the page numbers are not shown for the first two pages, and the second section does so page numbers are shown for the last 3 pages.
Document document = new Document();
// Create a template object and add a page numbering label
Template template = new Template();
template.Elements.Add(new PageNumberingLabel("%%SP%% of %%ST%%", 0, 680, 512, 12, Font.Helvetica, 12, TextAlign.Center));
// Begin the first section
document.Sections.Begin(NumberingStyle.RomanLowerCase);
// Add two pages
document.Pages.Add(new Page()); //Page 1
document.Pages.Add(new Page()); //Page 2
// Begin the second section
document.Sections.Begin(NumberingStyle.Numeric, template);
// Add three pages
document.Pages.Add(new Page()); //Page 3
document.Pages.Add(new Page()); //page 4
document.Pages.Add(new Page()); //page 5
// Save the PDF
document.Draw("output.pdf");
Here is a link to a topic on document sectioning:
http://docs.dynamicpdf.com/NET_Help_Library_19_08/Document%20Sectioning.html

Define the size of iTextSharp Textfield based on how much content a user inputs in C#

I was not able to find any overflow posts about resizing or readjusting iTextSharp's Text Field based on the user's input content they have in C#. I was hoping if anybody can help me here as this has been proving rather difficult for me.
Here is what I want to accomplish. Based on the user's amount of text input, I want to be able to have iTextSharp's Text Field size to be readjustable without have the text content be wrapped or resize font size at the end of the textbox.
Here is the block of code that I have for a textbox so far:
using iTextSharp.text.pdf;
string bodyText = "This is the text that the user inputs. I want the textfield to resize ";
bodyText += "based on how much text content there is here. I do not want the ";
bodyText += "text to wrap around or shrink text size at the end of the textfield.";
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(strPDFpath, FileMode.Create));
PdfContentByte cb = writer.DirectContent;
TextField _subject = new TextField(writer, new Rectangle(103f, 485f, 503, 499f), "tfSubject");
//I want this Rectangle size to be readjustable based on the text content but
//I'm not sure how to do that.
_subject.FontSize = 10f;
_subject.Alignment = Element.ALIGN_LEFT;
_subject.Text = bodyText;
writer.AddAnnotation(_subject.GetTextField());
cb = writer.DirectContent;
Not only that, after the textfield has been resized, I want to be able to add static text right under the resized textfield. This proves to be quite tricky since the textfield is set at absolute positioning.
Any help would greatly be appreciated.
Did you take a look at the answer to this question: Add PdfPCell to Paragraph
In this answer, we create a form that looks like this:
As you can see, the size of the form fields differs depending on the length of the content we're expecting.
How is this done? That's easy: we use Chunk objects with generic tag events to add the fields. See the GenericFields example:
public class FieldChunk extends PdfPageEventHelper {
#Override
public void onGenericTag(PdfWriter writer, Document document, Rectangle rect, String text) {
TextField field = new TextField(writer, rect, text);
try {
writer.addAnnotation(field.getTextField());
} catch (IOException ex) {
throw new ExceptionConverter(ex);
} catch (DocumentException ex) {
throw new ExceptionConverter(ex);
}
}
}
This snippet is written in Java, but it should be fairly easy to port it to C# (just pretend that I wrote pseudo-code if you don't know Java).
We can use the page event like this:
public void createPdf(String dest) throws IOException, DocumentException {
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
writer.setPageEvent(new FieldChunk());
document.open();
Paragraph p = new Paragraph();
p.add("The Effective Date is ");
Chunk day = new Chunk(" ");
day.setGenericTag("day");
p.add(day);
p.add(" day of ");
Chunk month = new Chunk(" ");
month.setGenericTag("month");
p.add(month);
p.add(", ");
Chunk year = new Chunk(" ");
year.setGenericTag("year");
p.add(year);
p.add(" that this will begin.");
document.add(p);
document.close();
}
As you can see, the length of the field is determined by the number of spaces we introduce in the Chunk:
Chunk day = new Chunk(" ");
Chunk month = new Chunk(" ");
Chunk year = new Chunk(" ");
The more spaces, the wider the field.
Using Chunks will make it much easier for you to introduce extra static content under each field.
For multi-line text fields, I would suggest to use a PdfPTable and a cell event. Adding a field in a table cell is demonstrated in the examples Create fields in a table on the official web site.

set the footer in place

setting the footer..
in the above screen the footer is displayed after new member report and reporting period but i dont want like this
I'm working on windows application using C#.
I have generated the "Report" using Ms chart control. While printing and exporting into XPS format, Header and Footer are appearing its fine .
But i want the Footer will be displayed at the bottom of the report at present it was appearing just after the header, I want to add this Footer at the bottom using C#. So user can print page with Header and Footer. How to do this.
can any one have idea about this ..
Many thanks....
this is my code
Title maintitle = kpiChartControl.Titles.Add("New Members Report" + Environment.NewLine);
maintitle.Alignment = ContentAlignment.TopLeft;
maintitle.Font = new Font(FontFamily.GenericSansSerif, 11, FontStyle.Bold);
Title rangetitle = kpiChartControl.Titles.Add(string.Format("Report period from : {0} to {1}{2}", dStartDate.Value.ToString(xxx.dateFormat),
denddate.Value.ToString(xxxx.dateFormat), Environment.NewLine));
rangetitle.Alignment = ContentAlignment.TopLeft;
rangetitle.Font = new Font(FontFamily.GenericSansSerif, 11, FontStyle.Bold);
Title footertitle = kpiChartControl.Titles.Add("--------------------------------------------------------" + Environment.NewLine);
footertitle.Alignment = ContentAlignment.BottomCenter;
Title gompanytitle = kpiChartControl.Titles.Add("xxxx");
gompanytitle.Alignment = ContentAlignment.BottomLeft;
gompanytitle.Font = new Font(FontFamily.GenericSansSerif, 9, FontStyle.Regular);
Title printedby = kpiChartControl.Titles.Add(string.Format("Printed By ("+text+") On :{0}", dt,Environment.NewLine));
printedby.Alignment = ContentAlignment.BottomRight;
printedby.Font = new Font(FontFamily.GenericSansSerif, 9, FontStyle.Regular);
kpiChartControl.Printing.Print(true);
kpiChartControl.Titles.Remove(maintitle);
kpiChartControl.Titles.Remove(rangetitle);
kpiChartControl.Titles.Remove(footertitle);
kpiChartControl.Titles.Remove(gompanytitle);
kpiChartControl.Titles.Remove(printedby);
The trick is to use the Docking property. So for all items that you wish to place below the graph, do the following
printedby.Docking = Docking.Bottom;
gompanytitle.Docking = Docking.Bottom;
footertitle.Docking = Docking.Bottom;
I'm kinda guessing here to be honest - but it seems to me that you need to be adding the footer in the XPS document, rather than as part of the chart. My guess is that the chart will always by displaying titles at the top.
This SO - about adding header/footer to an XPS - should help: add footer to FlowDocumentsdocuments, both Sauron's and Vikram's answers there should provide the information you need.

How to identify end of page is reached in pdf file using itextsharp

Hi
I am using itextsharp to generate a pdf file.I am placing a backgound image on it and want that image on all the pages .But when the first page is completed the text move to next page automatically so the image is not appearing on the new page.
Is there a way to identify the end of page so that we can add a new page and then set the image first so will appear in background and then can add the remaining text.
All is i want a image in background on all the pages of pdf file.
I suggest you use a page event:
myWriter.setPageEvent(new BackgroundPageEvent(backgroundImage));
class BackgroundPageEvent extends PdfPageEventHelper {
Image backgroundImage = null;
public BackgroundPageEvent( Image img ) {
backgroundImage = img;
}
public void onStartPage(PdfWriter writer, Document doc) {
PdfContentByte underContent = writer.getDirectContentUnder();
underContent.addImage(backgroundImage);
}
}
With the above code, backgroundImage will be added to the "under content" as each page is created. No need to worry about when to add it yourself... iText will figure that out for you, and the first thing in the underContent of each page will be your image. You might need to play around with the various overrides of addImage to get the size you want.
I believe you can also query doc for the current page size if it varies in your program. If not, you should be able to create the image you pass in with an absolute position/scale (which may be what you're doing already).
PdfPageEvent has a number of other events you can override. PdfPageEventHelper covers all the bases with "no ops" so you can just override the event[s] you want:
OnStartPage
OnEndPage
OnCloseDocument
OnParagraph
OnParagraphEnd
OnChapter
OnChapterEnd
OnSection
OnSectionEnd
OnGenericTag
Generic tag is actually Really Handy. You can give a generic tag (a string) to just about anything within your document, and your OnGenericTag override will be called with the rect that was used to draw whatever it was you tagged. All kinds of spiffy possibilities.
Just check PdfWriter.PageNumber property like this:
using (FileStream fs = File.Create("test.pdf"))
{
Document document = new Document(PageSize.A4, 72, 72, 72, 72);
PdfWriter writer = PdfWriter.GetInstance(document, fs);
document.Open();
int pageNumber = -1;
for (int i = 0; i < 20; i++)
{
if (pageNumber != writer.PageNumber)
{
// Add image
pageNumber = writer.PageNumber;
}
// Add something else
}
document.Close();
}

Categories

Resources