I'm working on program that insert some kind of watermark on existing pdf document. The watermark isn't image but text generated during program's work. I need to rotate the text, send it to center of page, and those things are done, but the text has many lines. So I put new line character "\n" in Phrase but PDF prints only characters before first use of "\n". How could I overlay some text on pdf document (mainly scanned docs) and rotate it?
My source code (simplified):
PdfContentByte canvas = stamper.GetOverContent(1);
String message = "some\n multiline \n expression";
Phrase text = new Phrase(text);
ColumnText.ShowTextAligned(canvas, Element.ALIGN_MIDDLE, text, size.Width / 2, size.Height / 2, 30);
That is documented: the ShowTextAligned() method is for single lines only. If you want multiple lines, you need to use a ColumnText object, define a Rectangle using the SetSimpleColumn() method and draw the content using the Go() method.
If you want to rotate such a Rectangle, you need to create a PdfTemplate first. Render the ColumnText to this PdfTemplate and add the template to the document.
Adding the template to the document can be done with the AddTemplate() method. In this case, you need some algebra to rotate the template. This is the algebra you'll need for the parameters:
a = cosine(angle);
b = sine(angle);
c = -sine(angle);
d = cosine(angle);
e = x;
f = y;
If you can't get the algebra working, you can wrap the template inside an Image object:
Image img = Image.getInstance(template);
Now you have different methods to introduce a rotation, including a simple one that merely requires an angle in degrees.
P.S.: wrapping a template inside an image doesn't "rasterize" the text. It creates a Form XObject (as opposed to an Image XObject).
I solved the problem in another way:
using (PdfStamper stamper = new PdfStamper(reader, ms))
{
PdfContentByte canvas = stamper.GetOverContent(1);
String message = String.Format("mutli\nline\text");
}
PdfGState gState = new PdfGState();
gState.FillOpacity = 0.3f;
canvas.SetGState(gState);
using (StringReader stringReader = new StringReader(message))
{
string line;
float y = size.Height / 2 + 200;
while ((line = stringReader.ReadLine()) != null)
{
Phrase p = new Phrase(line,FontFactory.GetFont(FontFactory.HELVETICA, 35));
ColumnText.ShowTextAligned(canvas, Element.ALIGN_CENTER, p, 300, y, 30);
y = y - 70;
}
}
}
Related
I am trying to make a orders page and there i have added a button which fetches some data and i am trying to display that data in pdf file and generate a pdf file. the data is being displayed correctly but i cant get the watermark on pdf.
here's the code
using (MemoryStream stream = new MemoryStream())
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
PdfDocument document = new PdfDocument();
PdfPage page = document.AddPage();
XFont font = new XFont("Verdana", 20, XFontStyle.Bold);
DrawWatermark(page, font);
XGraphics gfx = XGraphics.FromPdfPage(page);
string total = "Total price: " + ord.Totalprice;
string remark = "Remark: " + ord.Remark;
string status = "Payment status: " + ord.PaymentStatus;
gfx.DrawString(total, font, XBrushes.Black, 10, 100);
gfx.DrawString(remark, font, XBrushes.Black, 10, 135);
gfx.DrawString(status, font, XBrushes.Black, 10, 170);
document.Save(stream, false);
return File(stream.ToArray(), "application/pdf", "Invoice.pdf");
}
another method
void DrawWatermark(PdfPage page, XFont font)
{
string watermark = "CartMart";
// Variation 2: Draw a watermark as an outlined graphical path.
// NYI: Does not work in Core build.
// Get an XGraphics object for drawing beneath the existing content.
var gfx1 = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Append);
// Get the size (in points) of the text.
var size = gfx1.MeasureString(watermark, font);
// Define a rotation transformation at the center of the page.
gfx1.TranslateTransform(page.Width / 2, page.Height / 2);
gfx1.RotateTransform(-Math.Atan(page.Height / page.Width) * 180 / Math.PI);
gfx1.TranslateTransform(-page.Width / 2, -page.Height / 2);
// Create a graphical path.
var path = new XGraphicsPath();
// Create a string format.
var format = new XStringFormat();
format.Alignment = XStringAlignment.Near;
format.LineAlignment = XLineAlignment.Near;
// Add the text to the path.
// AddString is not implemented in PDFsharp Core.
path.AddString(watermark, font.FontFamily, XFontStyle.BoldItalic, 150,
new XPoint((page.Width - size.Width) / 2, (page.Height - size.Height) / 2),
format);
// Create a dimmed red pen.
var pen = new XPen(XColor.FromArgb(128, 255, 0, 0), 2);
// Stroke the outline of the path.
gfx1.DrawPath(pen, path);
gfx1.Dispose();
}
there is no watermark in pdf file. can somebody help me with the code. i want to display data as well and i dont know whats going on. There is no error as well.
Seems you mixed up a bit variations 2 and 3 from here. In variation 2, you should use XGraphicsPdfPageOptions.Prepend to draw beneath instead of above.
Also, if you're using .NET Core, it seems only variation 1 works. Looks like there is a port for Core here but no idea what is the status of this development.
I'm generating a clothing label as pdfs using iText. I'm trying to add a dashed line as a folding line in every page. But when I added a dashed line existing strokes replace to dashed lines? Any idea how to stop this?
I tried adding dashed lines when creating the pdf and after creating the pdf. But none of those works.
This is my code.
string inputPDF = "C:\\Users\\User\\Documents\\visual studio 2017\\Projects\\iTextSharpExample\\iTextSharpExample\\pdf\\Label_dynamicLive_SampleTemplate.pdf";
string outputPDF = "C:\\Users\\User\\Documents\\visual studio 2017\\Projects\\iTextSharpExample\\iTextSharpExample\\pdf\\Label_dynamicLive_SampleTemplate_foldline.pdf";
PdfReader reader = new PdfReader(inputPDF);
using (var fileStream = new FileStream(outputPDF, FileMode.Create, FileAccess.Write))
{
var document = new Document(reader.GetPageSizeWithRotation(1));
var writer = PdfWriter.GetInstance(document, fileStream);
document.Open();
for (var i = 1; i <= reader.NumberOfPages; i++)
{
document.NewPage();
var baseFont = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
var importedPage = writer.GetImportedPage(reader, i);
var contentByte = writer.DirectContent;
//line start
float moveto_x = 0 + 1;
float lineto_x = 20 - 1;
float moveto_y = (110 / 2) + 5;
float lineto_y = (110 / 2) + 5;
float moveto_x2 = 0 + 1;
float lineto_x2 = 20 - 1;
float moveto_y2 = (110 / 2) - 5;
float lineto_y2 = (110 / 2) - 5;
float lineWidth = 0.5f;
float unitsOn = 5;
float unitsOff = 1;
float phase = 2;
moveto_x = iTextSharp.text.Utilities.MillimetersToPoints(moveto_x);
moveto_y = iTextSharp.text.Utilities.MillimetersToPoints(moveto_y);
contentByte.MoveTo(moveto_x, moveto_y);
lineto_x = iTextSharp.text.Utilities.MillimetersToPoints(lineto_x);
lineto_y = iTextSharp.text.Utilities.MillimetersToPoints(lineto_y);
contentByte.LineTo(lineto_x, lineto_y);
contentByte.SetLineWidth(lineWidth);
contentByte.SetLineDash(unitsOn, unitsOff, phase);
contentByte.Stroke();
//line end
contentByte.AddTemplate(importedPage, 0, 0);
}
document.Close();
writer.Close();
}
I expected to write dashed lines in every page in given ordinates. But it turned to replace straight lines to dashed lines. Any idea how to add a lines without replacing existing?
The line dash (just like the line width, fill and stroke colors, and many other properties) is part of the "pdf graphics state".
To get back an earlier graphics state, pdfs support a stack of graphics states. When the current state is what you want to get back to later, you push the current state on that stack. And when you want to get back to that state, you pop it off of that stack.
The instruction for pushing is called save-state, the instruction for popping restore-state. The matching PdfContentByte methods are SaveState() and RestoreState().
Thus, start with contentByte.SaveState(), then do your stuff, then end with contentByte.RestoreState().
Add an aside, your code generates instructions in an invalid order:
contentByte.MoveTo(moveto_x, moveto_y);
contentByte.LineTo(lineto_x, lineto_y);
contentByte.SetLineWidth(lineWidth);
contentByte.SetLineDash(unitsOn, unitsOff, phase);
contentByte.Stroke();
Here you first create a path, then set line width and line dash, and then stroke the path. Strictly speaking, though, between the creation of a path and the instruction drawing it there may at most be an instruction to combine the path with the clip path but nothing else.
Most pdf viewers don't insist on that, though, so you'll probably not have concrete problems because of that.
But if your pdfs are validated, this invalid order may be reported as error.
Thus, first set the parameters, then create the path and draw it.
contentByte.SaveState();
contentByte.SetLineWidth(lineWidth);
contentByte.SetLineDash(unitsOn, unitsOff, phase);
contentByte.MoveTo(moveto_x, moveto_y);
contentByte.LineTo(lineto_x, lineto_y);
contentByte.Stroke();
contentByte.RestoreState();
I am making an application that creates a watermark on a PDF that the user selects and I can't seem to get the watermark to appear on the selected PDF but I also get no errors. Any help would be appreciated.
I am using PDFsharp version 1.50.4000
public void WaterMarkPDF(string sourceFileName)
{
try
{
string watermark = "watermark";
int emSize = 100;
string file ="test.pdf";
File.Copy(sourceFileName, file, true);
File.SetAttributes(file, File.GetAttributes(file) & ~FileAttributes.ReadOnly);
// Take in pdf from the form
PdfDocument document = PdfReader.Open(file);
// change the version cause sometimes newer versions break it
if (document.Version < 14)
document.Version = 14;
XFont font = new XFont("Times New Roman", emSize, XFontStyle.BoldItalic);
for (int idx = 0; idx < document.Pages.Count; idx++)
{
var page = document.Pages[idx];
// Get an XGraphics object for drawing beneath the existing content.
var gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Prepend);
// Get the size (in points) of the text.
var size = gfx.MeasureString(watermark, font);
// Define a rotation transformation at the center of the page.
gfx.TranslateTransform(page.Width / 2, page.Height / 2);
gfx.RotateTransform(-Math.Atan(page.Height / page.Width) * 180 / Math.PI);
gfx.TranslateTransform(-page.Width / 2, -page.Height / 2);
// Create a string format.
var format = new XStringFormat();
format.Alignment = XStringAlignment.Near;
format.LineAlignment = XLineAlignment.Near;
// Create a dimmed red brush.
XBrush brush = new XSolidBrush(XColor.FromArgb(128, 255, 0, 0));
// Draw the string.
gfx.DrawString(watermark, font, brush,
new XPoint((page.Width - size.Width) / 2, (page.Height - size.Height) / 2),
format);
// Save the document...
document.Save(file);
// ...and start a viewer.
Process.Start(file);
}
}
catch (Exception e)
{
throw e;
}
}
Maybe try XGraphicsPdfPageOptions.Appendinstead of XGraphicsPdfPageOptions.Prepend.
Call document.Save and Process.Startoutside the for loop.
Update: Explanation: With XGraphicsPdfPageOptions.Prepend the watermark is drawn below the original PDF page. Most PDF files consist of black text on transparent background and the watermark will be visible there (you can check this by activating the Transparency Grid in Adobe Reader). For PDF pages with a solid background (e.g. images, tables with a background colour, ...) the watermark will not be visible.
The PDFsharp source code includes a Watermark sample:
http://pdfsharp.net/wiki/Watermark-sample.ashx
There are two variants that add a semi-transparent text on top of the existing PDF page. These variants also work for PDF pages without transparency.
I am using the below code to add watermark to my pdf.
private void Merge(List<string> src, string dest)
{
iTextKernel.PdfWriter writer = new iTextKernel.PdfWriter(dest);
iTextKernel.PdfDocument pdfDocument1 = new iTextKernel.PdfDocument(new iTextKernel.PdfReader(src[0]), writer);
pdfDocument1.AddEventHandler(PdfDocumentEvent.END_PAGE, new WatermarkingEventHandler());
for (int i = 1, max = src.Count; i < max; i++)
{
iTextKernel.PdfDocument pdfDocument2 = new iTextKernel.PdfDocument(new iTextKernel.PdfReader(src[i]));
var pagesCount = pdfDocument2.GetNumberOfPages();
pdfDocument2.CopyPagesTo(1, pagesCount, pdfDocument1);
pdfDocument2.Close();
}
pdfDocument1.Close();
protected class WatermarkingEventHandler : IEventHandler {
public void HandleEvent(Event e) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) e;
iTextKernel.PdfDocument pdfDoc = docEvent.GetDocument();
iTextKernel.PdfPage page = docEvent.GetPage();
iText.Kernel.Font.PdfFont font = null;
try {
font = PdfFontFactory.CreateFont(FontConstants.HELVETICA_BOLD);
} catch (IOException ex) {
//_log.Error(ex);
}
PdfCanvas canvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), pdfDoc);
new Canvas(canvas, pdfDoc, page.GetPageSize())
.SetFontColor(iText.Kernel.Colors.DeviceGray.LIGHT_GRAY)
.SetFontSize(60)
.SetFont(font)
.ShowTextAligned(new Paragraph("FOR YOUR RECORDS ONLY: DO NOT SUBMIT"), 298, 421, pdfDoc.GetPageNumber(page),
TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
}
But am getting the watermark only in the last page that too hidden under the contents. Could you please modify this code so that i could get the watermark on all the pages and shown over the contents.
Please take a look at the iText 7 for C# jump-start tutorial, more specifically Chapter 5: Manipulating an existing PDF document. Scroll to the part where it says: "Adding a header, footer, and watermark" and look at the example:
PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
Document document = new Document(pdfDoc);
Rectangle pageSize;
PdfCanvas canvas;
int n = pdfDoc.GetNumberOfPages();
for (int i = 1; i <= n; i++) {
PdfPage page = pdfDoc.GetPage(i);
pageSize = page.GetPageSize();
canvas = new PdfCanvas(page);
//Draw header text
}
pdfDoc.close();
As you can see, we only need one PdfDocument instance, but instead of passing only a PdfWriter, we also pass a PdfReader instance. We will read the file with path src and we will write to a file with path dest.
You want to add content to each page. This means that you have to loop over each page (from 1 to n). Get the PdfPage object for each page i and replace the line //Draw header text with whatever it is you want to do.
In your case, you add an image underneath the existing content. That is the normal thing to do, but you say that the watermark is covered by the existing content. That happens for instance when the actual content consists of images (e.g. scanned pages). If you add a watermark under the pages of a PDF that consists of scanned pages, you will never see the watermark.
In that case, you have to add the content on top of the existing content, but it is best to make the watermark transparent:
Paragraph p = new Paragraph("FOR YOUR RECORDS ONLY: DO NOT SUBMIT").SetFontSize(60);
canvas.SaveState();
PdfExtGState gs1 = new PdfExtGState().SetFillOpacity(0.2f);
canvas.SetExtGState(gs1);
document.ShowTextAligned(p, pageSize.GetWidth() / 2, pageSize.GetHeight() / 2, pdfDoc.GetPageNumber(page), TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
canvas.RestoreState();
Note that in the tutorial, we are using pageSize.GetWidth() / 2 and pageSize.GetHeight() / 2 as coordinates, which means that we assume that the lower-left corner of the page has the coordinate (0, 0). That may not be the case. You may have to add the x-offset and the y-offset to that value.
I'm trying the create a multiple-page pdf using iTextSharp, but I'm having some issue creating a loop to have more than a single page.
My code below is working well for one page; however, my content will not fit into a single page. Thanks.
How can I write a loop to write contents on the first pdf page and the remaining to the second, third, etc...So far, I'm only seeing one page. Thank you.
int height = 600;
int totalPage = 1;
int oldPage = 1;
bool cons = false;
bool st = false;
foreach (string al in combo)
foreach (string al in combo) //my loop to write on the pdf but "combo" has 100 lines, which would fit into a single page.
{
string[] word = al.Split(',');
int strIndex = combo.IndexOf(al);
if (al.Length != 0)
{
if (word[0].ToString().ToUpper().Contains("(REV")==true && cons == false)
{
cb.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 11);
cb.BeginText();
// put the alignment and coordinates here
cb.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "CONSTRUCTION PRINTS", 80, height, 0);
cb.EndText();
height = height - 20;
cons = true;
}
if (word[0].ToString().ToUpper().Contains("(REV")==false && st == false)
{
cb.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 11);
cb.BeginText();
// put the alignment and coordinates here
cb.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "SAG & TENSION CHARTS", 80, height, 0);
cb.EndText();
height = height - 20;
st = true;
}
cb.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 11);
totalPage = totalPage + oldPage;
// write the text in the pdf content
cb.BeginText();
// put the alignment and coordinates here
cb.ShowTextAligned(PdfContentByte.ALIGN_LEFT, word[0].ToString().ToUpper(), 80, height, 0);
cb.EndText();
// write the text in the pdf content
cb.BeginText();
// put the alignment and coordinates here
cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "......................................................................................", 335, height, 0);
cb.EndText();
// write the text in the pdf content
cb.BeginText();
// put the alignment and coordinates here
cb.ShowTextAligned(PdfContentByte.ALIGN_RIGHT, totalPage.ToString(), 500, height, 0);
cb.EndText();
oldPage = Convert.ToInt32(word[1]);
}
height = height - 20;
}
//// create the new page and add it to the pdf
// reader = new PdfReader(oldFile);//old file
PdfImportedPage page = writer.GetImportedPage(reader, 1);
cb.AddTemplate(page, 0, 0);
//// close the streams and voilá the file should be changed :)
document.Close();
reader.Close();
fs.Close();
writer.Close();
Please go to the official documentation and click Q&A to go to the most frequently asked questions. Pick the Getting started category. The first thing you'll see, is the most popular iText example (which I am porting to C# for your convenience):
// step 1
Document document = new Document();
// step 2
FileStream fs = new FileStream("hello.pdf", FileMode.Create);
PdfWriter.GetInstance(document, fs);
// step 3
document.Open();
// step 4
document.Add(new Paragraph("Hello World!"));
// step 5
document.Close();
In your code, you are adding text at absolute positions by introducing PDF syntax, such as BeginText() (BT) / EndText() (ET) / SetFontAndSize() (Tf). This is creating PDF the hard way. If is very easy to make mistakes, as shown in this question: What is causing syntax errors in a page created with iText?
If you don't know the PDF reference (ISO 32000-1) by heart, you should avoid code like this. Instead you can use objects such as Paragraph, List, PdfPTable... The beauty of adding these objects to a Document using the Add() method, is that a new page gets triggered automagically as soon as a page is full. You can also trigger a new page yourself using:
document.NewPage();
If you want to add text at absolute positions, iText offers convenience methods and objects such as ColumnText. See my answer to Adding footer to existing PDF
You can define a Rectangle and add objects such as Paragraph, List, PdfPTable... Take a look at the answer to the question How to continue an ordered list on a second page? for inspiration:
ColumnText ct = new ColumnText(cb);
ct.AddElement(list);
Rectangle rect = new Rectangle(36, 36, 559, 806);
ct.SetSimpleColumn(rect);
int status = ct.Go();
while (ColumnText.HasMoreText(status)) {
document.NewPage();
ct.SetSimpleColumn(rect);
ct.Go();
}
The while loop is the loop you are looking for.