iText 7change document renderer and continue on the last position - c#

How do you change the DocumentRenderer in iText7 and continue on the corect position? I need some paragraphs to be rendered in 2 columns, and then normal text.
This is what I have, but it not works as expected:
using (MemoryStream oDocumentStream = new MemoryStream())
{
using (PdfWriter oDocumentWriter = new PdfWriter(oDocumentStream).SetSmartMode(true))
{
PdfDocument pdfDocument = new PdfDocument(oDocumentWriter);
Document document = new Document(pdfDocument);
float offSet = 60;
float columnWidth = (PageSize.A4.GetWidth() - offSet * 2 + 10) / 2;
float columnHeight = PageSize.A4.GetHeight() - offSet * 2;
//Define column areas
Rectangle[] columns = new Rectangle[]
{
new Rectangle(offSet - 5, offSet, columnWidth, columnHeight),
new Rectangle(offSet + columnWidth, offSet, columnWidth, columnHeight)
};
document.SetRenderer(new ColumnDocumentRenderer(document, columns)); //First renderer
document.Add(*myparagraph*);
document.SetRenderer(new iText.Layout.Renderer.DocumentRenderer(document)); //Second renderer
document.Add(*myparagraph*);
document.Close();
}
oPdfFile = oDocumentStream.ToArray();
}
The issue with this approach is that the second renderer don't continue where the first renderer ended, therefore they overlap, as you can see in this image:

Related

iText7 PDF renders correctly but prints incorrect in Adobe Reader

I have a task of adding watermarks to a lot of existing PDFs and I use iText7 for this in C#. The result can be seen in this picture (Blank pdf used)
It renders fine everywhere and prints perfectly from both Chrome and Edge. However, when printed from Adobe Acrobat Reader, this is what happens:
Anyone knowing more about PDF than I, who can help with this issue? I am using version 7.1.13 of iText.
The test pdf is available here:
https://potanteststorage.blob.core.windows.net/pdf/Test.pdf
C# Code:
public static void AddProductionWatermarks(string sourceFile, string destinationPath)
{
float watermarkTrimmingRectangleWidth = 75;
float watermarkTrimmingRectangleHeight = 250;
//Custom text
float formWidth = 75;
float formHeight = 250;
float formXOffset = 0;
float formYOffset = 0;
float xTranslation = 50;
float yTranslation = 0;
double rotationInRads = Math.PI / 2;
PdfFont font = PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN);
float fontSize = 12;
PdfDocument pdfDoc = new PdfDocument(new PdfReader(sourceFile), new PdfWriter(destinationPath));
var numberOfPages = pdfDoc.GetNumberOfPages();
PdfPage page = null;
for (var i = 1; i <= numberOfPages; i++)
{
page = pdfDoc.GetPage(i);
Rectangle ps = page.GetPageSize();
//PRODUCTION watermark -------------------------------------------------------
float prodBottomLeftX = -20;
float prodBottomLeftY = ps.GetHeight() / 2;
Rectangle prodWatermarkTrimmingRectangle = new Rectangle(prodBottomLeftX, prodBottomLeftY, watermarkTrimmingRectangleWidth, watermarkTrimmingRectangleHeight);
PdfWatermarkAnnotation prodWatermark = new PdfWatermarkAnnotation(prodWatermarkTrimmingRectangle);
AffineTransform transform2 = new AffineTransform();
transform2.Translate(xTranslation, yTranslation);
transform2.Rotate(rotationInRads);
PdfFixedPrint fixedPrint2 = new PdfFixedPrint();
prodWatermark.SetFixedPrint(fixedPrint2);
PdfFormXObject form2 = new PdfFormXObject(formRectangle);
PdfCanvas canvas2 = new PdfCanvas(form2, pdfDoc);
transform2.GetMatrix(transformValues);
canvas2.SaveState()
.BeginText().SetColor(new DeviceRgb(255, 36, 0), true)
.SetTextMatrix(transformValues[0], transformValues[1], transformValues[2], transformValues[3], transformValues[4], transformValues[5])
.SetFontAndSize(font, fontSize)
.ShowText("PRODUCTION")
.EndText()
.RestoreState();
canvas2.Release();
prodWatermark.SetAppearance(PdfName.N, new PdfAnnotationAppearance(form2.GetPdfObject()));
prodWatermark.SetFlags(PdfAnnotation.PRINT);
page.AddAnnotation(prodWatermark);
}
page?.Flush();
pdfDoc.Close();
}
You use FixedPrint dictionaries in your annotations:
PdfFixedPrint fixedPrint2 = new PdfFixedPrint();
prodWatermark.SetFixedPrint(fixedPrint2);
This additional entry for Watermark annotations specifies how this annotation shall be drawn relative to the dimensions of the target media during printing. Thus, you ask for special treatment of the watermark during printing.
So if you indeed want special treatment during printing (merely not the current treatment), simply set the PdfFixedPrint properties accordingly.
If you don't want any special treatment during printing, don't set a PdfFixedPrint object at all.

addind text with itext7

I want to add text into every page of my pdf which is rotaded from bottom to top.
Like this:
Here is my code:
PdfDocument srcDocument = new PdfDocument(new PdfReader(file));
PdfDocument destDocument = new PdfDocument(new PdfWriter(newfile));
int pagesCount = srcDocument.GetNumberOfPages();
for (int i = 1; i <= pagesCount; i++)
{
srcDocument.CopyPagesTo(i, i, destDocument);
PdfCanvas pdfCanvas = new PdfCanvas(srcDocument.GetPage(i));
}
srcDocument.Close();
destDocument.Close();
In this I got stuck. I don't know how to go further : write and rotate text.
So, as per the comments on the original question, you basically need to print on a Canvas object, and rotate the Paragraph. The Rectangle basically defines the coordinates where you will place the Canvas. Something like this should work:
PdfDocument srcDocument = new PdfDocument(new PdfReader(file));
PdfDocument destDocument = new PdfDocument(new PdfWriter(newfile));
FontProgram fontProgram =
FontProgramFactory.CreateFont(#"C:\temp\calibri.ttf");
PdfFont calibri = PdfFontFactory.CreateFont(fontProgram, PdfEncodings.WINANSI);
int pagesCount = srcDocument.GetNumberOfPages();
for (int i = 1; i <= pagesCount; i++)
{
srcDocument.CopyPagesTo(i, i, destDocument);
PdfCanvas pdfCanvas = new PdfCanvas(destDocument.GetPage(i));
Canvas canvas = new Canvas(pdfCanvas, new Rectangle(36, 750, 100, 50));
canvas.Add(new Paragraph("0001").SetRotationAngle(1.5708).SetFont(calibri).SetFontSize(4));
canvas.Close();
}
srcDocument.Close();
destDocument.Close();
Alternatively, you can set a Style, if you plan on reusing a lot, something like:
Style rotatedStuff = new Style()
.SetRotationAngle(1.5708)
.SetFont(calibri)
.SetFontSize(4);
and then just apply it to the Paragraph with the AddStyle() method.
Mind you that if you provide with a float number, it's in rads, so 90° is 1.5708 rad (1 Degree (°) = 0.01745 Radian (rad)).

iTextSharp - dynamic content with a footer, using padding

I am attempting to create documents that are highly-variable in length, and make them something that can be table-driven. I am trying to use iTextSharp tables exclusively to create the documents, including footer verbiage. In the code below I’m trying to pad the very last cell to the exact amount equal to the remaining space, so that my footer will be placed exactly at the bottom of the document, tight against the bottom margin. This works fine when I try to use document margins of 1, 2, or 3 inches, but when I use 5 for example, my footer begins to wrap. I think this may simply be a case of bad math. Does anyone have any suggestions to correct this (outside of using Page Events)?
(*Note: there are 2 helper methods used in creating tables and measuring the height of a paragraph, also included in addition to the main code from a button click)
(*Note: each table has SplitLate set to false, to make the content flow from page to page evenly); all tables have a specific width, and the width is locked
//declare path for the PDF file to be created
string strpath = #"C:\CROauto\Junk\MSE.pdf";
//instantiate a new PDF document
//(regular portrait format, with half-inch margins all around)
var doc = new Document(PageSize.LETTER,
iTextSharp.text.Utilities.InchesToPoints(1f),
iTextSharp.text.Utilities.InchesToPoints(1f),
iTextSharp.text.Utilities.InchesToPoints(5f),
iTextSharp.text.Utilities.InchesToPoints(.5f));
//create a PDF table
//(2 column, with no border)
PdfPTable mas_tbl = clsPDF.CreateTable(2, false, cell_padding_bottom: 0f, total_width: doc.PageSize.Width - doc.LeftMargin - doc.RightMargin);
//get base font types
BaseFont font_tb = FontFactory.GetFont(FontFactory.TIMES_BOLD).BaseFont;
BaseFont font_t = FontFactory.GetFont(FontFactory.TIMES).BaseFont;
//create regular Font objects, with varying sizes
iTextSharp.text.Font f10 = new iTextSharp.text.Font(font_t, 10);
iTextSharp.text.Font f8 = new iTextSharp.text.Font(font_t, 8);
//create regular Font objects, bold, with varying sizes
iTextSharp.text.Font fb10 = new iTextSharp.text.Font(font_tb, 10);
iTextSharp.text.Font fb8 = new iTextSharp.text.Font(font_tb, 8);
//get image
iTextSharp.text.Image da_img = iTextSharp.text.Image.GetInstance(#"C:\CROauto\Junk\img.gif");
//scale the image to a good size
da_img.ScaleAbsolute(iTextSharp.text.Utilities.InchesToPoints(.75f),
iTextSharp.text.Utilities.InchesToPoints(.75f));
//create new PDF cell to hold image
PdfPCell icell = new PdfPCell();
icell.PaddingBottom = 0f;
//make sure the "image" cell has no border
icell.Border = iTextSharp.text.Rectangle.NO_BORDER;
//add the image to the PDF cell
icell.AddElement(da_img);
//add the image cell to the table
mas_tbl.AddCell(icell);
//work with the return address
PdfPCell ra = new PdfPCell();
ra.Border = iTextSharp.text.Rectangle.NO_BORDER;
ra.PaddingBottom = 5f;
PdfPTable tblra = clsPDF.CreateTable(1, false);
tblra.HorizontalAlignment = Element.ALIGN_RIGHT;
Chunk c = new Chunk("Help Me Please", fb8);
string rtnadd = "\r\n123 iTextSharp Rd\r\nHelpMe, ST 12345\r\n\r\nstackoverflow.com";
Phrase pra = new Phrase(rtnadd, f8);
Paragraph p = new Paragraph();
p.SetLeading(1f, 1.1f);
p.Add(c);
p.Add(pra);
tblra.TotalWidth = clsPDF.GetLongestWidth(p) + ra.PaddingLeft + ra.PaddingRight + 2;
ra.AddElement(p);
tblra.AddCell(ra);
PdfPCell dummy = new PdfPCell();
dummy.PaddingBottom = 0f;
dummy.Border = iTextSharp.text.Rectangle.NO_BORDER;
dummy.AddElement(tblra);
mas_tbl.AddCell(dummy);
//create "content" table
PdfPTable t2 = clsPDF.CreateTable(1, false, Element.ALIGN_JUSTIFIED, cell_padding_bottom: 0f);
//create FileStream for the file
using (FileStream fs = new FileStream(strpath, FileMode.Create))
{
//get an instance of a PdfWriter, attached to the FileStream
PdfWriter.GetInstance(doc, fs);
//open the document
doc.Open();
string tmp = "";
for (int i = 0; i < 80; i++)
{
tmp += "The brown fox jumped over the lazy dog a whole bunch of times." + i.ToString();
}
Phrase p2 = new Phrase(tmp, f10);
t2.AddCell(p2);
p2 = new Phrase("Another paragraph", f10);
t2.AddCell(p2);
tmp = "";
PdfPTable t3 = clsPDF.CreateTable(1, false, cell_padding_bottom: 0f);
for (int i = 0; i < 150; i++)
{
tmp += "The lazy dog didn't like that very much." + i.ToString();
}
t3.AddCell(new Phrase(tmp, f10));
t2.AddCell(t3);
t2.AddCell(new Phrase("I SURE HOPE THIS WORKED", f10));
PdfPCell c2 = new PdfPCell();
c2.PaddingBottom = 0f;
c2.Border = iTextSharp.text.Rectangle.NO_BORDER;
c2.Colspan = mas_tbl.NumberOfColumns;
c2.AddElement(t2);
mas_tbl.AddCell(c2);
//work with adding a footer
//FOOTER MSE: ADD ENOUGH PADDING TO PUSH THE FOOTER TO THE BOTTOM OF THE PAGE
Paragraph fp = new Paragraph(new Phrase("Line 1 of footer\r\nLine 2 of footer\r\nhere's more of my footer text:\r\nthis project was SOOOO much fun\r\nand stuff", fb8));
//get the height of the footer
float footer_height = clsPDF.GetTotalHeightOfParagraph(fp);
Console.WriteLine("Footer height {0}", footer_height.ToString());
//get the total amount of "writeable" space per page
//(taking top and bottom margins into consideration)
float avail = doc.PageSize.Height - (doc.TopMargin + doc.BottomMargin);
//declare a variable to assist in calculating
//the total amount of "writeable" room remaining
//on the last page;
//start with with the current height of the master table
//(will do math below to calculate just what it's using
// on the last page)
float mas_tbl_last_page_height = mas_tbl.TotalHeight;
//the purpose of this loop is to start determining
//how much writeable space is left on the last page;
//this loop will subtract the "available" value from
//the total height of the master table until what's
//left is the amount of space the master table is
//using on the last page of the document only
while (mas_tbl_last_page_height > avail)
{
mas_tbl_last_page_height -= avail;
}
//to truly calculate the amount of writeable space
//remaining, subtract the amount of space that the
//master table is utilizing on the last page of
//the document, from the total amount of writeable
//space per page
float room_remaining = avail - mas_tbl_last_page_height;
//declare variable for the padding amount
//that will be used above the footer
float pad_amt = 0f;
if (room_remaining > (footer_height * 2))
{
//pad to push down
pad_amt = room_remaining - (footer_height * 2);
}
else
{
//don't use a pad
//(just let the table wrap normally)
pad_amt = 0f;
}
//declare the footer cell, and set all of it's values
PdfPCell ftcell = new PdfPCell();
ftcell.HorizontalAlignment = Element.ALIGN_JUSTIFIED;
//(use column span that is equal to the number of
// columns in the master table)
ftcell.Colspan = mas_tbl.NumberOfColumns;
ftcell.Border = iTextSharp.text.Rectangle.NO_BORDER;
ftcell.PaddingTop = pad_amt;
ftcell.PaddingBottom = 0f;
ftcell.AddElement(fp);
//add the footer cell to the master table
mas_tbl.AddCell(ftcell);
//add the master table to the document, which should contain everything
doc.Add(mas_tbl);
//close the document
doc.Close();
//HELPER METHODS
internal static PdfPTable CreateTable(int column_count,
bool include_border,
int h_align = Element.ALIGN_LEFT,
int v_align = Element.ALIGN_TOP,
float leading_multiplier = 1.1f,
float total_width = 468f,
float cell_padding_bottom = 5f,
float cell_padding_top = 0)
{
////////////////////////////////////////////////////////////////////////////////////
PdfPTable t = new PdfPTable(column_count);
//this line will keep the inner tables,
//from splitting off onto a 2nd page
//(making them only do it on wrapping)
//*NOTE: this needs to be tested thoroughly
// to make sure that rows aren't dropped!!!
t.SplitLate = false;
//used if you're adding paragraphs directly to table cells,
//instead of adding new PdfPCell objects
if (include_border == false)
{
t.DefaultCell.Border = Rectangle.NO_BORDER;
}
t.DefaultCell.PaddingLeft = 0f;
t.DefaultCell.PaddingRight = 0f;
t.DefaultCell.PaddingTop = cell_padding_top;
t.DefaultCell.PaddingBottom = cell_padding_bottom;
t.DefaultCell.HorizontalAlignment = h_align;
t.DefaultCell.VerticalAlignment = h_align;
t.TotalWidth = total_width;
t.LockedWidth = true;
t.DefaultCell.SetLeading(0, leading_multiplier);
return t;
}
internal static float GetLongestWidth(Paragraph p)
{
List<float> f = new List<float>();
foreach (Chunk c in p.Chunks)
{
string[] strarray = c.Content.Split(new string[] { "\r\n" }, System.StringSplitOptions.None);
for (int i = 0; i < strarray.Length; i++)
{
Chunk tc = new Chunk(strarray[i], c.Font);
Console.WriteLine(tc.Content + ", width: {0}", tc.GetWidthPoint().ToString());
f.Add(tc.GetWidthPoint());
}
}
return f.Max();
}
internal static float GetTotalHeightOfParagraph(Paragraph p)
{
PdfPTable t = clsPDF.CreateTable(1, false, cell_padding_bottom: 0f);
t.DefaultCell.PaddingBottom = 0f;
t.DefaultCell.PaddingTop = 0f;
t.AddCell(p);
return t.TotalHeight;
}
Solved it by using absolute positioning. I calculate the position that the footer should be in, by adding the footer height to the value of the bottom margin. To alleviate concerns about overwriting existing content, I calculate the amount of available space remaining on the last page; if it's not enough for my footer, I add a new page and post my content at the beginning of the next page.
byte[] content;
using (MemoryStream output = new MemoryStream())
{
PdfReader pdf_rdr = new PdfReader(strpath);
PdfStamper stamper = new PdfStamper(pdf_rdr, output);
PdfContentByte pcb = stamper.GetOverContent(pdf_rdr.NumberOfPages);
PdfPTable ftbl = clsPDF.CreateTable(1, false, cell_padding_bottom: 0f);
Paragraph fp = new Paragraph(new Phrase("Line 1 of footer\r\nLine 2 of footer\r\nhere's more of my footer text:\r\nthis project was SOOOO much fun\r\nand stuff", fb8));
//get the height of the footer
float footer_height = clsPDF.GetTotalHeightOfParagraph(fp);
Console.WriteLine("Footer height {0}", footer_height.ToString());
//get the total amount of "writeable" space per page
//(taking top and bottom margins into consideration)
float avail = doc.PageSize.Height - (doc.TopMargin + doc.BottomMargin);
//declare a variable to assist in calculating
//the total amount of "writeable" room remaining
//on the last page;
//start with with the current height of the master table
//(will do math below to calculate just what it's using
// on the last page)
float mas_tbl_last_page_height = mas_tbl.TotalHeight;
mas_tbl_last_page_height = mas_tbl_last_page_height % avail;
avail = avail - mas_tbl_last_page_height;
Console.WriteLine(clsPDF.GetTotalHeightOfParagraph(fp).ToString());
//float ft_top = avail - mas_tbl_last_page_height - clsPDF.GetTotalHeightOfParagraph(fp) - doc.BottomMargin;
float ft_top = doc.BottomMargin + clsPDF.GetTotalHeightOfParagraph(fp);
ftbl.AddCell(fp);
if (avail < clsPDF.GetTotalHeightOfParagraph(fp))
{
stamper.InsertPage(pdf_rdr.NumberOfPages + 1, pdf_rdr.GetPageSize(1));
pcb = stamper.GetOverContent(pdf_rdr.NumberOfPages);
ft_top = doc.PageSize.Height - doc.TopMargin;
}
ftbl.WriteSelectedRows(0, -1, doc.LeftMargin, ft_top, pcb);
// Set the flattening flag to true, as the editing is done
stamper.FormFlattening = true;
// close the pdf stamper
stamper.Close();
//close the PDF reader
pdf_rdr.Close();
content = output.ToArray();
}
//write the content to a PDF file
using (FileStream fs = File.Create(strpath))
{
fs.Write(content, 0, (int)content.Length);
fs.Flush();
}

Rotate PDF page contents and not the actual page

I have researched this and tried to rotate a single page PDF's contents. I am able to rotate the page 90, 180 or 270 degrees. I don't want to rotate the page but rather the contents.
Here's the method I have adapted so far:
public static byte[] RotatePdf(byte[] fileBytes, int degreesClockwise)
{
if (degreesClockwise % 90 != 0)
throw new ApplicationException(string.Format("degreesClockwise must be 0, 90, 180, 360: {0}", degreesClockwise));
PdfReader reader = new PdfReader(fileBytes);
using (var fs = new MemoryStream())
{
PdfStamper stamper = new PdfStamper(reader, fs);
PdfDictionary pageDict = reader.GetPageN(1);
int desiredRotation = degreesClockwise; // x degrees clockwise from what it is now
PdfNumber rotation = pageDict.GetAsNumber(PdfName.ROTATE);
if (rotation != null)
{
desiredRotation += rotation.IntValue;
desiredRotation %= 360; // must be 0, 90, 180, or 270
}
pageDict.Put(PdfName.ROTATE, new PdfNumber(desiredRotation));
stamper.Close();
return fs.ToArray();
}
}
Any suggestions would be greatly appreciated.
I accomplished the code using the PdfSharp library as I could not find any examples or answers for iTextSharp unfortunately.
Here is the code I used to accomplish what I wanted:
// Create the output document
PdfDocument outputDocument = new PdfDocument();
// Show single pages
// (Note: one page contains two pages from the source document)
outputDocument.PageLayout = PdfPageLayout.SinglePage;
// Open the external document as XPdfForm object
XPdfForm form = XPdfForm.FromFile(filename);
for (int i = 0; i < form.PageCount; i++)
{
// Add a new page to the output document
PdfPage page = outputDocument.AddPage();
page.Orientation = PageOrientation.Landscape;
double width = page.Width;
double height = page.Height;
int rotate = page.Elements.GetInteger("/Rotate");
XGraphics gfx = XGraphics.FromPdfPage(page);
XRect box = new XRect(0, 0, width, height * 2);
// Draw the page identified by the page number like an image
gfx.DrawImage(form, box);
}
// Save the document...
filename = "RotatedAndStretched_tempfile.pdf";
outputDocument.Save(filename);

Add image watermark over another image in pdf c#

All,
I am trying to add image watermark in pdf using itextsharp. Watermark is appearing on all the pages as expected but with ones that already have image. I want my watermarking image to come on top of the existing image on the pdf.
I am using following code to add image
using (Stream output = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, output))
{
for (int pageIndex = 1; pageIndex <= pdfReader.NumberOfPages; pageIndex++)
{
pdfStamper.FormFlattening = false;
iTextSharp.text.Rectangle pageRectangle = pdfReader.GetPageSizeWithRotation(pageIndex);
PdfContentByte pdfData = pdfStamper.GetUnderContent(pageIndex);
pdfData.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 10);
PdfGState graphicsState = new PdfGState();
graphicsState.FillOpacity = 0.4F;
pdfData.SetGState(graphicsState);
pdfData.BeginText();
iTextSharp.text.Image jpeg = iTextSharp.text.Image.GetInstance(wtrmrkimg, BaseColor.GREEN);
float width = pageRectangle.Width;
float height = pageRectangle.Height;
jpeg.ScaleToFit(width, height);
jpeg.SetAbsolutePosition(width / 2 - jpeg.Width / 2, height / 2 - jpeg.Height / 2);
jpeg.SetAbsolutePosition(50, 50);
jpeg.Rotation = 45;
pdfData.AddImage(jpeg);
pdfData.EndText();
}
pdfStamper.Close();
}
output.Close();
output.Dispose();
}
I am attaching output of the current code also :
I just got it working by replacing
PdfContentByte pdfData = pdfStamper.GetUnderContent(pageIndex);
with
PdfContentByte pdfData = pdfStamper.GetOverContent(pageIndex);
Replace
jpeg.SetAbsolutePosition(width / 2 - jpeg.Width / 2, height / 2 - jpeg.Height / 2);
With
jpeg.SetAbsolutePosition(width / 2 - jpeg.ScaledWidth / 2, height / 2 - jpeg.ScaledHeight / 2);
and remove
jpeg.SetAbsolutePosition(50, 50);
to get watermark centered

Categories

Resources