Remove page numbers from PDFsharp page merge when merging with another document - c#

I used PDFsharp to merge 2 PDF files. My code adds page numbering to the bottom of each page. Now I need to merge the created document with another PDF the same way. The issue I get is the page numbers on the part created from the last document are fine. The document created from the first merge has the new page number added over the top of the first set so there are now two page numbers on top of each other in the first set of pages. So in one spot I have both of these "Page 1 of 40" and Page "1 of 110" on top of each other.
Here is the code I used to merge the PDFs
using PdfSharp.Drawing;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;
namespace SomeProject.Helpers
{
public static class PDFHelper
{
public static void MergePDFFiles(string[] pdfFiles, string outputFilePath)
{
PdfDocument document = new PdfDocument();
foreach (string pdfFile in pdfFiles)
{
PdfDocument inputPDFDocument = PdfReader.Open(pdfFile, PdfDocumentOpenMode.Import);
document.Version = inputPDFDocument.Version;
foreach (PdfPage page in inputPDFDocument.Pages)
{
document.AddPage(page);
}
}
// Set font for paging
XFont font = new XFont("Verdana", 9);
XBrush brush = XBrushes.Black;
// Create variable that store page count
string noPages = document.Pages.Count.ToString();
// Set for loop of document page count and set page number using DrawString function of PdfSharp
for (int i = 0; i < document.Pages.Count; ++i)
{
PdfPage page = document.Pages[i];
// Make a layout rectangle.
XRect layoutRectangle = new XRect(240 /*X*/ , page.Height - font.Height - 10 /*Y*/ , page.Width /*Width*/ , font.Height /*Height*/ );
using (XGraphics gfx = XGraphics.FromPdfPage(page))
{
gfx.DrawString("Page " + (i + 1).ToString() + " of " + noPages, font, brush, layoutRectangle, XStringFormats.Center);
}
}
document.Save(outputFilePath);
}
}
}

A clean solution: only add the page numbers to the final documents. Keep copies of intermediate files without page numbers or create the files twice as needed.
A hack: draw a white rectangle below the new page numbers to hide anything that is already in that area. The PDF will have both page numbers, but only the most recent and current page number will be visible.
Removing page numbers is a bit complicated.

Related

IText 7 multiline field not auto breaking lines

We recently switched from ITextSharp to IText 7, and it all seemed to work fine.
But then one of our customer send us back the pdf he got, and it didn't seem that the multiline field is auto breaking the lines, like it did on the ITextSharp.
Our fix right now is to split our string every 130 characters, and put in a \n on the closest space. For anyone having the same problem, here is the code we use:
public static void SetFormatted(this PdfFormField field, string txt)
{
var rect = field.GetPdfObject().GetAsRectangle(new PdfName("Rect"));
var fontSize = field.GetFontSize();
var div = fontSize / 2.2;
int length = (int)(rect.GetWidth() / div);
field.SetValue(Format(txt, length));
}
private static string Format(string text, int length)
{
if (text.Length > length)
{
if (text.IndexOf(' ') == 0)
text = text.Substring(1);
string temp = text.Substring(0, length);
int indexOfN = temp.IndexOf("\n");
if (indexOfN > 0)
{
return temp.Substring(0, indexOfN) + Format(text.Substring(indexOfN), length);
}
int index = temp.LastIndexOf(' ');
temp = temp.Substring(0, index) + "\n";
return temp + Format(text.Substring(index), length);
}
return text;
}
But this is more of a temporary fix, and not a solution.
(I know I said 130 characters, but it is what it split with in our field. It calculates what it should be. I don't gguarantee that it would work 100% for you)
We have tried to use field.SetRichText(ourTxt) but then it just didn't show, and the field is RTF enabled.
This is what it used to look like:
But this is what it looks like with IText 7:
I've been having this same problem and it's driving me crazy. My fields would not wrap... until I set a background color:
using iText.Forms;
using iText.Forms.Fields;
using iText.IO.Font.Constants;
using iText.Kernel.Colors;
using iText.Kernel.Font;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
// Create a new PDF document
PdfDocument pdf = new PdfDocument(new PdfWriter("my_document.pdf"));
// Create a page and add it to the document
PdfPage page = pdf.AddNewPage();
// Create an AcroForm and add it to the document
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdf, true);
// Create a multiline text field that should wrap but does not.
PdfTextFormField nonWrapping = PdfFormField.CreateText
(pdf,
new Rectangle(25, 727, 100, 100),
"multiline-field-without-wrapping",
String.Concat(Enumerable.Repeat("Hello World ", 10)),
PdfFontFactory.CreateFont(StandardFonts.HELVETICA),
9.0F);
nonWrapping.SetMultiline(true);
form.AddField(nonWrapping);
// Create a multiline text field that DOES wrap but only because we set a background color.
PdfTextFormField wrapping = PdfFormField.CreateText
(pdf,
new Rectangle(150, 727, 100, 100),
"multiline-field-without-wrapping",
String.Concat(Enumerable.Repeat("Hello World ", 10)),
PdfFontFactory.CreateFont(StandardFonts.HELVETICA),
9.0F);
wrapping.SetMultiline(true);
wrapping.SetBackgroundColor(new DeviceRgb(0.9F, 0.9F, 0.99F));
form.AddField(wrapping);
// Close the document
pdf.Close();
I'm using .NET 7.0.0, iText7 7.2.4 and viewing the PDFs in Preview on Mac with Montery 12.6.1.
In both cases, the field sort of wraps when you click into it but only the field with the background color remains wrapped after the field loses focus.

iText 7 C# creating a pdf from a template and adding text to it

I have a one page pdf template and need to create a new document with several pages. Each page needs to be as the first page of the template. Then i need to add text to each page. The pages are copied but the text is not added.
This is my code:
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(stream));
PdfDocument cover = new PdfDocument(new PdfReader(templatePath));
//First copy the pages
var totalPages=5;
var coverPage = cover.GetPage(1);
for (int i = 0; i < totalPages; i++)
{
//If i do it to a blank page the text is visible
//pdfDoc.AddNewPage();
//I have tried both methods:
pdfDoc.AddPage(coverPage.CopyTo(pdfDoc));
//cover.CopyPagesTo(1, 1, pdfDoc);
}
//Now i try to add text
Document doc = new Document(pdfDoc);
var font = PdfFontFactory.CreateFont(fontPath);
for (int i = 1; i <= totalPages; i++)
{
//Edited
Rectangle pagesize = pdfDoc.GetPage(i).GetPageSize();
doc.ShowTextAligned(new Paragraph("HEADER").SetFont(font).SetFontSize(22), pagesize.GetLeft(), pagesize.GetBottom(), i, TextAlignment.LEFT, VerticalAlignment.BOTTOM, 0);
//doc.ShowTextAligned(new Paragraph("HEADER").SetFont(font), 100, 700, i, TextAlignment.CENTER, VerticalAlignment.TOP, 0);
}
doc.Close();
cover.Close();
pdfDoc.Close();
I have tried this options:
Canvas instead of document with no result (see code below)
If i use the AddNewPage() and not the cover page, then the text is added to the blank page (both document and canvas methods).
If i open and write directly to the template document the text is visible but the size is very small and position of the text is different compared to 2)
This is the canvas code inside the for instruction:
var canvas = new PdfCanvas(pdfDoc.GetPage(i));
canvas.BeginText()
.SetFontAndSize(font, 22) //Edited
.MoveText(100, 700)
.ShowText("HEADER")
.EndText();
//UPDATED
Following the solution contributed by #mkl, i have changed the way i add the pages:
var coverPage = cover.GetPage(1);
Rectangle coverSize = coverPage.GetPageSize();
for (int i = 0; i < totalPaginas; i++)
{
//Taken from this example: https://kb.itextpdf.com/home/it7kb/ebooks/itext-7-jump-start-tutorial-for-java/chapter-6-reusing-existing-pdf-documents
PdfPage page = pdfDoc.AddNewPage(PageSize.A4);
PdfCanvas canvas = new PdfCanvas(page);
AffineTransform transformationMatrix = AffineTransform.GetScaleInstance(
page.GetPageSize().GetWidth() / coverSize.GetWidth(),
page.GetPageSize().GetHeight() / coverSize.GetHeight());
canvas.ConcatMatrix(transformationMatrix);
var pageCopy = coverPage.CopyAsFormXObject(pdfDoc);
canvas.AddXObjectAt(pageCopy, 0, 0);
//pdfDoc.AddNewPage();
//pdfDoc.AddPage(coverPage.CopyTo(pdfDoc));
//cover.CopyPagesTo(1, 1, pdfDoc);
}
Now i can see the text added, but the font size is much smaller than if instead of copying i do "pdfDoc.AddNewPage()", why is it? i would like it to be the correct font size.
Your code works in my tests. Maybe (100,700) is outside of the visual page area, which would typically be the case if your template page does not have its lower left corner at (0,0).
This should put the text in the lower left corner:
Rectangle pagesize = pdfDoc.GetPage(i).GetPageSize();
doc.ShowTextAligned(new Paragraph("HEADER"), pagesize.GetLeft(),
pagesize.GetBottom(), i, TextAlignment.LEFT, VerticalAlignment.BOTTOM, 0);
If that works, you can work from the pagesize rectangle to calculate the appropriate position for the text.
The solution to why the text dont appear is updated in my question at the bottom.
The reason why the coordinates dont match and the size is so small is the source template pdf that was exported with a very high px/inch for high level printing. Reducing it to 72ppp was the fix.

Merging PDFs with different orientations with iTextSharp

I have two PDF files with different orientations (first document is A4 format and the second A4 landscape).
I want to merge them but I need to preserve the original orientation of each page.
I tried with the rotation with this code:
float width = pdfImportedPage.Width;
float height = pdfImportedPage.Height;
if (width > height)
{
PdfDictionary pageDict = reader.GetPageN(documentPage);
pageDict.Put(PdfName.ROTATE, new PdfNumber(270));
}
After the rotation I call the AddPage method like this:
copy.AddPage(pdfImportedPage);
But the result is an A4 format document with the second part with the text that goes out of the page. For me is good if the text in the second part is horizontal but I need that also the orientation of the page will be as the original document (horizontal).
I'm using iTextSharp version 5.5.13.
I've just discovered that the problem was in another part of the code, after that, when I add the page number.
By the way, a good way to preserve the page orientation is to use the SetPageSize and the NewPage methods, like this piece of code:
for (int page = 1; page <= reader.NumberOfPages; page++)
{
copy.RotateContents = true;
doc.SetPageSize(reader.GetPageSizeWithRotation(page));
doc.NewPage();
importedPage = copy.GetImportedPage(reader, page);
copy.AddPage(importedPage);
}

Where does bottom and right border come from in abcPdf

Why I am getting border on bottom and right when rendering html using abcAdf.
PS I got professional license using (ABCpdf9-64.dll)
My process is to create page:
I use master / child layout template in mvc (works)
I point to this html using abcPdf to convert into pdf
Html rendered
When my html gets rendered (plain) format : each originating from its respective location.
<h1>Layout</h1>
<p>
content
</p>
C# code to render pdf
My code is as follows:
using (var pdf = new Doc())
{
pdf.HtmlOptions.Timeout = 600000;
pdf.HtmlOptions.AddTags = true;
pdf.Page = pdf.AddPage();
var id = pdf.AddImageUrl(url, true, 1024, true);
if (allowPaging)
{
while (true)
{
if (!pdf.Chainable(id))
{
break;
}
pdf.Page = pdf.AddPage();
id = pdf.AddImageToChain(id);
}
for (int i = 1; i <= pdf.PageCount; i++)
{
pdf.PageNumber = i;
pdf.Flatten();
}
////reset back to page 1 so the pdf starts displaying there
if (pdf.PageCount > 0)
{
pdf.PageNumber = 1;
}
}
return store(pdf);
}
Output
My text/html gets rendered ok but I get borders that I have not asked for.
Rendered output:
Please note the hairline in bottom of the image.
After hours of googling about setting margin in abcpdf, I found nothing and took it as a challenge to find it myself.
I tried experimenting with everything I found relevant in the abcpdf documentation and finally made a chart myself
for setting the margins. I have successfully implemented this in many situations. Hope this helps others.
Here is a code snippet that shows how to set margins-
string html; // my html content that should be shown in the pdf page
Doc pdf = new Doc();
// adjust the default rotation and save
double w = pdf.MediaBox.Width;
double h = pdf.MediaBox.Height;
double l = pdf.MediaBox.Left;
double b = pdf.MediaBox.Bottom;
// explicitly giving page size
pdf.MediaBox.String = "A4";
pdf.Transform.Rotate(90, l, b);
pdf.Transform.Translate(w, 0);
pdf.Rect.Width = h;
pdf.Rect.Height = w;
int theID1 = pdf.GetInfoInt(pdf.Root, "Pages");
pdf.SetInfo(theID1, "/Rotate", "90");
int theID;
pdf.Rect.String = "17 55 823 423";
theID = pdf.AddImageHtml(html.ToString()); //Writes the HTML image to PDF
Here is a picture that describes margin layout for some junk values. Here
20 suggests that your content starts 20 pixels away from left of your pdf page
770 suggests that your content ends 770 pixels away from left of your pdf page
75 suggests that your content starts 55 pixels above the bottom of your pdf page
600 suggests that your content ends 600 pixels above the bottom of your pdf page
In your case you have to add
pdf.Rect.String = "20 75 770 600"; // giving junk values
right before
var id = pdf.AddImageUrl(url, true, 1024, true);
NOTE: In this example I explicitly set landscape mode instead of portrait mode. But orientation doesn't matter for setting
margins.

Creating PDF with overflow layout via iTextSharp

I'm successfully creating a PDF document from a DataTable via iTextSharp, but I can't get the layout in a desireable format.
Though unlikely, the DataTable has the potential for dozens of columns. Imagine the following DataTable - each number represents the area that can fit on a page:
|------------|
| 1 : 2 : 3 |
|------------|
| 4 : 5 : 6 |
|------------|
This should export as a 6 page PDF document in the order I've numbered the sections. Instead, it's currently generating as a two page document with 40-some columns squished on each page with a font so small it literally has no detail.
The simplest way to explain what I want is: When a generated PDF prints, I want it to print like a very wide Excel sheet rather than squishing all the content together.
My code is as follows:
public static void ExportAsPDF(DataTable Table, IList<string> Columns, string filename)
{
int ColumnCount = Table.Columns.Count;
int RowCount = Table.Rows.Count;
iTextSharp.text.Table BodyTable = new iTextSharp.text.Table(ColumnCount, RowCount);
BodyTable.AutoFillEmptyCells = true;
foreach (string s in Columns)
{
BodyTable.AddCell(s);
}
foreach (object o in from DataRow row in Table.Rows from o in row.ItemArray select o)
{
BodyTable.AddCell(o.ToString());
}
Document doc = new Document();
PdfWriter.GetInstance(doc, HttpContext.Current.Response.OutputStream);
doc.Open();
doc.Add(BodyTable);
doc.Close();
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment; filename={0}.pdf", filename));
HttpContext.Current.Response.End();
}
All input and help is much appreciated. Thanks
Okay, two options.
Draw everything yourself by hand with PdfContentByte and ColumnText for the text layout part.
Convince the normal iText Layout code that your page is wide enough to hold an entire row, then split those pages into pieces later. Not Pretty, but probably easier than the alternative.
First you need to define a page that is 3 times wider than normal.
Rectangle triplePageRect = new Rectangle(PageSize.LETTER);
float origWidth = triplePageRect.getWidth();
triplePageRect.setWidth(origWidth * 3f);
Document doc = new Document(triplePageRect);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(doc, baos);
Then you draw your table pretty much the way you are now... BUT you must be sure that a column edge lines up with your two page edges so you can easily break up the pages later. Bonus points if you can create an empty row centered on where the page break will be so you have a margin.
//Your Code Here
Finally, you need to save your PDF, open it again, and chop it to ribbons. I'm thinking PdfStamper.
// write everything out to the baos.
doc.close();
// and suck it right back up again. Hurray for efficiency. Or something.
PdfReader reader = new PdfReader(baos.toByteArrayOrWhateverItsCalled());
PdfStamper stamper = new PdfStamper( reader, new FileOutputStream(outputPath));
// duplicate the pages. I'll assume only one page, but you'll get the idea.
PdfDictionary origPage = reader.getPageN(1);
for (int i = 0; i < 2; ++i) {
// initial size is irrelevant, we're going to change it, but !null
stamper.insertPage(2+i, PageSize.LETTER);
PdfDictionary newPageDict = reader.getPage(2 + i);
// copy the original page... note that this is a shallow copy
newPageDict.putAll(origPageDict);
// duplicate the page rect so each page will have its own copy
PdfArray pageRect = newPageDict.getAsArray(PdfName.MEDIABOX);
// also a shallow copy, but changes to this array will be localized to the page.
PdfArray newRect = new PdfArray(pageRect);
// page rects are defined as [llx lly urx ury], so we need to change 0 and 2.
newRect.set(0, new PdfNumber(origWidth * (i+1));
newRect.set(2, new PdfNumber(origWidth * (i+2));
}
//Smoke'em if you've got 'em folks, we're done.
stamper.close();
Damn I'm good. Oooh ooh! And modest! Let's not forget good looking, brave, courteous, witty...

Categories