Watermark specific page in PDF iTextSharp - itext

I create the PDF dynamically based on the custom object data and water mark all pages in the PDF using iTextSharp 5.5.10.0 as shown in the code below.
Question: How can I watermark one or more page based on the criteria in the for loop? Custom object data has a boolean flag which indicates whether the pdf page could be watermarked?
Any help is greatly appreciated.
using (MemoryStream workStream = new MemoryStream())
{
using (Document document = new Document())
{
using (PdfWriter writer = PdfWriter.GetInstance(document, workStream))
{
HeaderFooter headerfooter = new HeaderFooter();
headerfooter.watermarkpage = WaterMarkPage;
headerfooter.includefooter = IncludeFooter;
writer.PageEvent = headerfooter;
writer.CloseStream = false;
document.Open();
PdfContentByte cb = writer.DirectContent;
foreach (TestResult testresultdata in testresults)
{
document.Add(PopulateData(testresultdata, reporttitle, includesponsordata));
// Move to next page
document.NewPage();
} // end foreach Order
document.Close();
} // end writer
} // end document
}

Related

can we add multiline textual watermark in a document using latest iText jar?

I am looking for multi-line textual watermark feature. Does iText latest version support this feature?
I am attaching a picture of the requirement.
Let me know your findings.
Here is an example of how to add repeating watermark as the background to an existing document:
pdfDocument = new PdfDocument(new PdfReader(inFileName), new PdfWriter(outFileName));
PdfPattern.Tiling tiling = new Tiling(new Rectangle(100, 50));
new Canvas(new PdfPatternCanvas(tiling, pdfDocument), pdfDocument, tiling.getBBox()).add(new Paragraph("TESTING")
.setFontColor(ColorConstants.RED)
.setRotationAngle(Math.PI / 10));
for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
PdfPage page = pdfDocument.getPage(i);
new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDocument)
.saveState()
.setFillColor(new PatternColor(tiling))
.rectangle(page.getCropBox())
.fill()
.restoreState();
}
pdfDocument.close();
This is how the result look visually:

LayoutResult more one page in Itext7

i ask this: Remove the first and last lines properties in the paper Itext7
and if i do it:
PdfWriter pdfWriter = new PdfWriter(dest);
PdfDocument pdfDoc = new PdfDocument(pdfWriter);
Div div = new Div();
Document doc = new Document(pdfDoc, PageSize.A5);
doc.setMargins(0,0,0,36);
for (int i = 0; i <50 ; i++) {
ListItem listItem = new ListItem();
String s= "hello "+i;
Paragraph p = new Paragraph();
for (int j = 0; j <s.length() ; j++) {
p.add("HELLO " +I);
}
LayoutResult result = div.createRendererSubTree().setParent(doc.getRenderer()).layout(new LayoutContext(new LayoutArea(0,PageSize.A5)));
List<IRenderer> childRendererParagraph = result.getSplitRenderer().getChildRenderers();
childRendererParagraph contain Paragraphs only from first page.And i don't know how many pages well be in pdf
As I mentioned in the answer to your previous question,
split renderer represent the part of the content which iText can place on the area, overflow - the content which overflows.
So if you want to layout the rest of the content, you can perform the same operation (layout) on your overflowRenderer.
The code is as follows:
LayoutResult firstPageResult = div.createRendererSubTree().setParent(doc.getRenderer()).layout(new LayoutContext(new LayoutArea(0, PageSize.A5)));
LayoutResult secondPageResult = firstPageResult.getOverflowRenderer().layout(new LayoutContext(new LayoutArea(1, PageSize.A5)));
Once the content has been fully placed, the overflowRenderer will be null.
pdf.setDefaultPageSize(new PageSize(595, 14400));
Resize the page to display all content on one page

iText Text Expansion Not Working in Certain Conditions

The following code will generate a pdf that will not use the specified text expansions when read out loud. It seems that adding the image in a container is causing the problem.
void Main()
{
using(var ms = new MemoryStream())
{
var doc = new Document(PageSize.LETTER, 72, 72, 72, 72);
var writer = PdfWriter.GetInstance(doc, ms);
writer.SetTagged();
doc.Open();
var c1 = new Chunk("ABC");
c1.SetTextExpansion("the alphabet");
var p1 = new Paragraph();
p1.Add(c1);
doc.Add(p1);
// Adding this image to the document as img > chunk > doc causes the text expansion not to work.
// Adding this image to the document as img > doc works
var t = writer.DirectContent.CreateTemplate(6, 6);
t.SetLineWidth(1f);
t.Circle(3f, 3f, 1.5f);
t.SetGrayFill(0);
t.FillStroke();
var i = iTextSharp.text.Image.GetInstance(t);
var c2 = new Chunk(i, 0, 0);
doc.Add(c2);
var c3 = new Chunk("foobar");
c3.SetTextExpansion("foo bar");
var p3 = new Paragraph();
p3.Add(c3);
doc.Add(p3);
doc.Close();
ms.Flush();
File.WriteAllBytes("d:\\expansion.pdf", ms.ToArray());
}
}
Is this just me doing something wrong or a bug?
While this doesn't read out loud correctly in Adobe Reader, it does in JAWS. So it sounds like this is a reader issue and not necessarily an iText issue.

How do you underline text with dashedline in ITEXT PDF

I have underlined "Some text" by
var par = new Paragraph();
par.Add(new Chunk("Some text", CreateFont(12, Font.UNDERLINE)));
document.Add(par);
It is possible underline just "Some text" with dashed line (not the paragraph)?
Thanks
This answer tells you how to do it but unfortunately doesn't provide any code so I've provided it below.
To the best on my knowledge there isn't a direct way to achieve this in iTextSharp by just setting a simple property. Instead, you need to use a PageEvent and manually draw the line yourself.
First you need to subclass PdfPageEventHelper:
private class UnderlineMaker : PdfPageEventHelper {
}
You then want to override the OnGenericTag() method:
public override void OnGenericTag(PdfWriter writer, Document document, iTextSharp.text.Rectangle rect, string text) {
}
The text variable will hold an arbitrary value that you set later on. Here's a full working example with comments:
private class UnderlineMaker : PdfPageEventHelper {
public override void OnGenericTag(PdfWriter writer, Document document, iTextSharp.text.Rectangle rect, string text) {
switch (text) {
case "dashed":
//Grab the canvas underneath the content
var cb = writer.DirectContentUnder;
//Save the current state so that we don't affect future canvas drawings
cb.SaveState();
//Set a line color
cb.SetColorStroke(BaseColor.BLUE);
//Set a dashes
//See this for more details: http://api.itextpdf.com/itext/com/itextpdf/text/pdf/PdfContentByte.html#setLineDash(float)
cb.SetLineDash(3, 2);
//Move the cursor to the left edge with the "pen up"
cb.MoveTo(rect.Left, rect.Bottom);
//Move to cursor to the right edge with the "pen down"
cb.LineTo(rect.Right, rect.Bottom);
//Actually draw the lines (the "pen downs")
cb.Stroke();
//Reset the drawing states to what it was before we started messing with it
cb.RestoreState();
break;
}
//There isn't actually anything here but I always just make it a habit to call my base
base.OnGenericTag(writer, document, rect, text);
}
}
And below is an implementation of it:
//Create a test file on the desktop
var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.pdf");
//Normal iTextSharp boilerplate, nothing special here
using (var fs = new FileStream(testFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (var doc = new Document()) {
using (var writer = PdfWriter.GetInstance(doc, fs)) {
doc.Open();
//Bind our helper class
writer.PageEvent = new UnderlineMaker();
//Create a new paragraph
var p = new Paragraph();
//Add a normal chunk
p.Add(new Chunk("This is a "));
//Create another chunk with an arbitrary tag associated with it and add to the paragraph
var c = new Chunk("dashed underline test");
c.SetGenericTag("dashed");
p.Add(c);
//Add the paragraph to the document
doc.Add(p);
doc.Close();
}
}
}
If you wanted to get fancy you could pass a delimited string to SetGenericTag() like dashed-black-2x4 or something and parse that out in the OnGenericTag event.

iTextSharp does not render header/footer when using element generated by XmlWorkerHelper

I am trying to add header/footer to a PDF whose content is otherwise generated by XMLWorkerHelper. Not sure if it's a placement issue but I can't see the header/footer.
This is in an ASP.NET MVC app using iTextSharp and XmlWorker packages ver 5.4.4 from Nuget.
Code to generate PDF is as follows:
private byte[] ParseXmlToPdf(string html)
{
XhtmlToListHelper xhtmlHelper = new XhtmlToListHelper();
Document document = new Document(PageSize.A4, 30, 30, 90, 90);
MemoryStream msOutput = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(document, msOutput);
writer.PageEvent = new TextSharpPageEventHelper();
document.Open();
var htmlContext = new HtmlPipelineContext(null);
htmlContext.SetTagFactory(Tags.GetHtmlTagProcessorFactory());
var cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(false);
cssResolver.AddCssFile(HttpContext.Server.MapPath("~/Content/themes/mytheme.css"), true);
var pipeline = new CssResolverPipeline(cssResolver, new HtmlPipeline(htmlContext, new PdfWriterPipeline(document, writer)));
var worker = new XMLWorker(pipeline, true);
var parser = new XMLParser();
parser.AddListener(worker);
using (TextReader sr = new StringReader(html))
{
parser.Parse(sr);
}
//string text = "Some Random Text";
//for (int k = 0; k < 8; ++k)
//{
// text += " " + text;
// Paragraph p = new Paragraph(text);
// p.SpacingBefore = 8f;
// document.Add(p);
//}
worker.Close();
document.Close();
return msOutput.ToArray();
}
Now instead of using these three lines
using (TextReader sr = new StringReader(html))
{
parser.Parse(sr);
}
if I comment them out and uncomment the code to add a random Paragraph of text (commented in above sample), I see the header/footer along with the random text.
What am I doing wrong?
The EventHandler is as follows:
public class TextSharpPageEventHelper : PdfPageEventHelper
{
public Image ImageHeader { get; set; }
public override void OnEndPage(PdfWriter writer, Document document)
{
float cellHeight = document.TopMargin;
Rectangle page = document.PageSize;
PdfPTable head = new PdfPTable(2);
head.TotalWidth = page.Width;
PdfPCell c = new PdfPCell(ImageHeader, true);
c.HorizontalAlignment = Element.ALIGN_RIGHT;
c.FixedHeight = cellHeight;
c.Border = PdfPCell.NO_BORDER;
head.AddCell(c);
c = new PdfPCell(new Phrase(
DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") + " GMT",
new Font(Font.FontFamily.COURIER, 8)
));
c.Border = PdfPCell.TOP_BORDER | PdfPCell.RIGHT_BORDER | PdfPCell.BOTTOM_BORDER | PdfPCell.LEFT_BORDER;
c.VerticalAlignment = Element.ALIGN_BOTTOM;
c.FixedHeight = cellHeight;
head.AddCell(c);
head.WriteSelectedRows(
0, -1, // first/last row; -1 flags all write all rows
0, // left offset
// ** bottom** yPos of the table
page.Height - cellHeight + head.TotalHeight,
writer.DirectContent
);
}
}
Feeling angry and stupid for having lost more than two hours of my life to Windows 8.1! Apparently the built in PDF Reader app isn't competent enough to show 'Headers'/'Footers'. Installed Foxit Reader and opened the output and it shows the Headers allright!
I guess I should try with Adobe Reader too!!!
UPDATES:
I tried opening the generated PDF in Adobe Acrobat reader and finally saw some errors. This made me look at the HTML that I was sending to the XMLWorkerHelper more closely. The structure of the HTML had <div>s inside <table>s and that was tripping up the generated PDF. I cleaned up the HTML to ensure <table> inside <table> and thereafter the PDF came out clean in all readers.
Long story short, the code above is fine, but if you are testing for PDF's correctness, have Adobe Acrobat Reader handy at a minimum. Other readers behave unpredictably as in either not reporting errors or incorrectly rendering the PDF.