Duplicating PDF pages creates corrupted file - c#

My program is suppost to take a single paged PDF document and duplicating the page while adding some content from an Excel table.
Everything works for editing the first page, but beyond that it creates a corrupt PDF file.
I used an if else statement in the foreach loop that is iteraing trough the excel table(for every row it creates a new page and adds it).
What it does is that there are two same copies of content on every page. The if else statement simply add the content once on the upper and the next on the lowe half and so on.
Here is the code:(ignore the non-english comments)
// open the reader
PdfReader reader = new PdfReader(btn_izberiPole.Content.ToString());
iTextSharp.text.Rectangle size = reader.GetPageSizeWithRotation(1);
Document document = new Document(size);
// open the writer
FileStream fs = new FileStream(btn_izberiCiljnoMapo.Content.ToString(), FileMode.Create, FileAccess.Write); //todo: preveri če je odprto
PdfWriter writer = PdfWriter.GetInstance(document, fs);
document.Open();
int count = 1;
var stamper = new PdfStamper(reader, fs);
foreach (string sifra in seznamSifer) //iterates trough every number to be added
{
if (count % 2 != 0) //za prvo polovico pol
{
// the pdf content
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page = writer.GetImportedPage(reader, 1); //add old page
cb.AddTemplate(page, 0, 0);
var pdfContentByte = stamper.GetOverContent(1);
//prvi je sivi
iTextSharp.text.Image barcode = iTextSharp.text.Image.GetInstance(izdelajCrtnoKodo(System.Drawing.Color.LightGray, sifra), System.Drawing.Imaging.ImageFormat.Jpeg);
//barcode.ScaleToFit(200f, 15f); //tole za velikost zgornjih črtnih kod
barcode.SetAbsolutePosition(80, 235.9f);
barcode.ScaleAbsolute(new iTextSharp.text.Rectangle(91, 9.4f));
pdfContentByte.AddImage(barcode);
//druga crtna koda
barcode = iTextSharp.text.Image.GetInstance(izdelajCrtnoKodo(System.Drawing.Color.White, sifra), System.Drawing.Imaging.ImageFormat.Jpeg);
barcode.ScaleAbsolute(new iTextSharp.text.Rectangle(91, 9.4f));
barcode.SetAbsolutePosition(367, 217.4f);
pdfContentByte.AddImage(barcode);
//tretja crtna koda
barcode.ScaleAbsolute(new iTextSharp.text.Rectangle(79.4f, 8.5f)); //tole za velikost spodnje črtne kode //
barcode.SetAbsolutePosition(381.5f, 172.6f);
pdfContentByte.AddImage(barcode);
}
else //za drugo polovico
{
// the pdf content
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page = writer.GetImportedPage(reader, 1); //add old page
cb.AddTemplate(page, 0, 0);
// var stamper = new PdfStamper(reader, fs);
var pdfContentByte = stamper.GetOverContent(1);
//prvi je sivi
iTextSharp.text.Image barcode = iTextSharp.text.Image.GetInstance(izdelajCrtnoKodo(System.Drawing.Color.LightGray, sifra), System.Drawing.Imaging.ImageFormat.Jpeg);
barcode.SetAbsolutePosition(80, 35.9f); //org 235.9f
barcode.ScaleAbsolute(new iTextSharp.text.Rectangle(91, 9.4f));
pdfContentByte.AddImage(barcode);
//druga crtna koda
barcode = iTextSharp.text.Image.GetInstance(izdelajCrtnoKodo(System.Drawing.Color.White, sifra), System.Drawing.Imaging.ImageFormat.Jpeg);
barcode.ScaleAbsolute(new iTextSharp.text.Rectangle(91, 9.4f));
barcode.SetAbsolutePosition(367, 217.4f);
pdfContentByte.AddImage(barcode);
//tretja crtna koda
barcode.ScaleAbsolute(new iTextSharp.text.Rectangle(79.4f, 8.5f)); //tole za velikost spodnje črtne kode //
barcode.SetAbsolutePosition(381.5f, 172.6f);
pdfContentByte.AddImage(barcode);
// stamper.Close(); //tale more bit namesto doc.close
document.NewPage();
}
count++;
/* if (count == 5) */break;
}
stamper.Close(); //tale more bit namesto doc.close
I tried several combinations by adding the file stream to be created in loop each time and some other methods. None worked so far. Any suggestions?
EDIT: I removed PDF stamper and used only writer for adding content.
One last problem I am encountering: document.Add(image) is adding images below the main layer. I can select those images in PDF but they are not visible. How can I solve this?
LAST EDIT: I solved this by using pdfContentByte.AddImage(barcode) instead of document.Add(barcode)
Thank you for your help guys! Next time I will for sure read the documentation first.

Related

Resize PDF Document with Digital Signature

I am using iTextSharp in my code to resize PDF documents and it is working very well, as shown below:
public byte[] ResizePdf(byte[] data) {
PdfReader reader = new PdfReader(data);
Document document = new Document(PageSize.A4);
MemoryStream stream = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(document, stream);
document.Open();
PdfContentByte cb = writer.DirectContent;
for (int i = 1; i <= reader.NumberOfPages; i++) {
document.NewPage();
PdfImportedPage page = writer.GetImportedPage(reader, i);
cb.AddTemplate(page, 0.8, 0, 0, 0.8, 25f, 60f);
}
document.Close();
return stream.ToArray();
}
However, when a PDF document is signed, when I try to resize it, I lose the signature on my new resized document.
I've tried to create a copy of the document (follow the code) and it works fine, but I can't resize it.
public byte[] Test(byte[] data) {
PdfReader reader = new PdfReader(data);
Document document = new Document(PageSize.A4);
MemoryStream stream = new MemoryStream();
PdfCopy copy = new PdfCopy(document, stream);
document.Open();
PdfContentByte cb = copy.DirectContent;
for (int i = 1; i <= reader.NumberOfPages; i++) {
document.NewPage();
PdfImportedPage page = copy.GetImportedPage(reader, i);
cb.AddTemplate(page, 0.8, 0, 0, 0.8, 0, 0);
copy.AddPage(page);
}
document.Close();
return stream.ToArray();
}
Does anyone have any tips or anything that can help me?
Thanks in advance!

PDF modify takes time in C#

I'm using iTextSharp to modify a pdf file and to add specific data into it.
Here is the scenario I have, I have a DataTable that contains thousands of rows, each row represents a customer or client, and I have one pdf template.
I have to modify the pdf template for each row (client or customer) to add their id to the file in addition to other data and then it will be added to the DataTable for that client.
I'm using this code to do the needed job, but it times out when processing huge amount of rows or it takes at least 15 mins, 4k rows in my case- because this means opening the pdf file 4k times and modifying it as needed.
// file is the pdf tmeplate, id is the customer's id - represens 1 row in the DataTable, landingPage: is client's specific page should be added to the file
private static byte[] GeneratePdfFromPdfFile(byte[] file, int id, string landingPage)
{
try
{
using (var ms = new MemoryStream())
{
//Create an iTextSharp Document which is an abstraction of a PDF but **NOT** a PDF
var doc = new iTextSharp.text.Document();
//Create a writer that's bound to our PDF abstraction and our stream
var writer = PdfWriter.GetInstance(doc, ms);
//Open the document for writing
doc.Open();
PdfContentByte cb = writer.DirectContent;
////parse html code to xml
//iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, srHtml);
PdfReader reader = new PdfReader(file);
for (int pageNumber = 1; pageNumber < reader.NumberOfPages + 1; pageNumber++)
{
doc.SetPageSize(reader.GetPageSizeWithRotation(1));
doc.NewPage();
//Insert to Destination on the first page
PdfImportedPage page = writer.GetImportedPage(reader, pageNumber);
int rotation = reader.GetPageRotation(pageNumber);
if (rotation == 90 || rotation == 270)
{
cb.AddTemplate(page, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(pageNumber).Height);
}
else
{
cb.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);
}
}
// Add a new page to the pdf file
doc.NewPage();
// set pdf open action to open the link embedded in the file.
string _embeddedURL = "http://" + landingPage + "/Default.aspx?code=" + id;
PdfAction act = new PdfAction(_embeddedURL);
writer.SetOpenAction(act);
doc.Close();
return ms.ToArray();
}
}
catch { return null; }
}
Note: I'm using ForEach loop to iterate through the DataTable rows
Your question (the text) doesn't correspond with your code (the C# part). You are asking one thing (add content to an existing PDF), and doing another thing (add an option action to an existing PDF), but regardless of what it is that you want to do, you shouldn't use PdfWriter to make a shallow copy of every page of an existing PDF (throwing away all interactivity).
You can significantly reduce the lines of code you wrote by using PdfStamper:
PdfReader reader = new PdfReader(file);
MemoryStream ms = new MemoryStream();
PdfStamper stamper = new PdfStamper(reader, ms);
string _embeddedURL = "http://" + landingPage + "/Default.aspx?code=" + id;
PdfAction act = new PdfAction(_embeddedURL);
stamper.Writer.SetOpenAction(act);
stamper.Close();
reader.Close();
return ms.ToArray();
Please read chapter 6 of my book to see why PdfWriter is the wrong class for you. PdfStamper is meant to manipulate an existing PDF document, keeping all its existing features intact.
Also be aware that you're using an old version of iText. The most recent version is iText 7. Please consult the Jump-Start tutorial for more info on using the latest iText version.

ItextSharp MVC5 C# - text in front of existing pdf

I'm building a web app for editing PDF files using iTextSharp.
When I try to write to the PDF, the text is getting printed behind an existing content, however I need to print it on top of it.
Can someone explain to me how can I set a depth property for my text?
This is my code
using (var reader = new PdfReader(oldFile))
{
using (var fileStream = new FileStream(newFile, FileMode.Create, FileAccess.Write))
{
var document = new Document(reader.GetPageSizeWithRotation(1));
var writer = PdfWriter.GetInstance(document, fileStream);
document.Open();
try
{
PdfContentByte cb = writer.DirectContent;
cb.BeginText();
try
{
cb.SetFontAndSize(BaseFont.CreateFont(), 12);
cb.SetTextMatrix(10, 100);
cb.ShowText("Customer Name");
}
finally
{
cb.EndText();
}
PdfImportedPage page = writer.GetImportedPage(reader, 1);
cb.AddTemplate(page, 0, 0);
}
finally
{
document.Close();
writer.Close();
reader.Close();
}
}
}
Can someone explain to me how can I set a depth property for my text?
Pdf does not have an explicit depth or z-axis property. What is drawn first, therefore, is covered by what is drawn later.
So if you want to have the template under your added text, you should pull the code adding the template before the code adding the text:
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page = writer.GetImportedPage(reader, 1);
cb.AddTemplate(page, 0, 0);
cb.BeginText();
try
{
cb.SetFontAndSize(BaseFont.CreateFont(), 12);
cb.SetTextMatrix(10, 100);
cb.ShowText("Customer Name");
}
finally
{
cb.EndText();
}
Alternatively you can make use of am itextsharp feature: it actually created two content streams, the direct content and the under content, and puts the under content before the direct content.
Thus, if rearranging the code as above is not an option for you, you can instead add the background to the under content instead of the direct content.

Merge and Renumber Pages with ITextSharp

We are trying to merge two page numbered PDFs into a new PDF. We want to have the new PDF start with the page number from 1 e.g.
PDF pages are sorted like this 1,2,3,4,5
PDF pages are sorted like this 1,2,3,4,5
Merged PDF should have the page number 1,2,3,4,5,6,7,8,9,10 and other old page labels should not be seen on the newly merged PDF.
This is our sample code but Labels are not showing on page.
string output_file = "~/output/output.pdf";
Document document = new Document();
using (var inputPdfStream = new FileStream(#"C:\Test.pdf", FileMode.Open))
{
PdfReader reader = new PdfReader(inputPdfStream);
PdfReader.unethicalreading = true;
using (PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(Server.MapPath(output_file), FileMode.Create)))
{
document.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page;
for (int i = 1; i <= reader.NumberOfPages; i++)
{
page =writer.GetImportedPage(reader, i);
document.NewPage();
cb.AddTemplate(page, 0, 0);
PdfPageLabels oLabel = new PdfPageLabels();
oLabel.AddPageLabel(i, PdfPageLabels.DECIMAL_ARABIC_NUMERALS);
writer.PageLabels = oLabel;
}
document.Close();
}
}

ITextSharp insert text to an existing pdf

The title sums it all.
I want to add a text to an existing PDF file using iTextSharp, however i can't find how to do it anywhere in the web...
PS: I cannot use PDF forms.
I found a way to do it (dont know if it is the best but it works)
string oldFile = "oldFile.pdf";
string newFile = "newFile.pdf";
// open the reader
PdfReader reader = new PdfReader(oldFile);
Rectangle size = reader.GetPageSizeWithRotation(1);
Document document = new Document(size);
// open the writer
FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write);
PdfWriter writer = PdfWriter.GetInstance(document, fs);
document.Open();
// the pdf content
PdfContentByte cb = writer.DirectContent;
// select the font properties
BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252,BaseFont.NOT_EMBEDDED);
cb.SetColorFill(BaseColor.DARK_GRAY);
cb.SetFontAndSize(bf, 8);
// write the text in the pdf content
cb.BeginText();
string text = "Some random blablablabla...";
// put the alignment and coordinates here
cb.ShowTextAligned(1, text, 520, 640, 0);
cb.EndText();
cb.BeginText();
text = "Other random blabla...";
// put the alignment and coordinates here
cb.ShowTextAligned(2, text, 100, 200, 0);
cb.EndText();
// create the new page and add it to the pdf
PdfImportedPage page = writer.GetImportedPage(reader, 1);
cb.AddTemplate(page, 0, 0);
// close the streams and voilá the file should be changed :)
document.Close();
fs.Close();
writer.Close();
reader.Close();
I hope this can be usefull for someone =) (and post here any errors)
In addition to the excellent answers above, the following shows how to add text to each page of a multi-page document:
using (var reader = new PdfReader(#"C:\Input.pdf"))
{
using (var fileStream = new FileStream(#"C:\Output.pdf", 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;
contentByte.BeginText();
contentByte.SetFontAndSize(baseFont, 12);
var multiLineString = "Hello,\r\nWorld!".Split('\n');
foreach (var line in multiLineString)
{
contentByte.ShowTextAligned(PdfContentByte.ALIGN_LEFT, line, 200, 200, 0);
}
contentByte.EndText();
contentByte.AddTemplate(importedPage, 0, 0);
}
document.Close();
writer.Close();
}
}
This worked for me and includes using OutputStream:
PdfReader reader = new PdfReader(new RandomAccessFileOrArray(Request.MapPath("Template.pdf")), null);
Rectangle size = reader.GetPageSizeWithRotation(1);
using (Stream outStream = Response.OutputStream)
{
Document document = new Document(size);
PdfWriter writer = PdfWriter.GetInstance(document, outStream);
document.Open();
try
{
PdfContentByte cb = writer.DirectContent;
cb.BeginText();
try
{
cb.SetFontAndSize(BaseFont.CreateFont(), 12);
cb.SetTextMatrix(110, 110);
cb.ShowText("aaa");
}
finally
{
cb.EndText();
}
PdfImportedPage page = writer.GetImportedPage(reader, 1);
cb.AddTemplate(page, 0, 0);
}
finally
{
document.Close();
writer.Close();
reader.Close();
}
}
Here is a method that uses stamper and absolute coordinates showed in the different PDF clients (Adobe, FoxIt and etc. )
public static void AddTextToPdf(string inputPdfPath, string outputPdfPath, string textToAdd, System.Drawing.Point point)
{
//variables
string pathin = inputPdfPath;
string pathout = outputPdfPath;
//create PdfReader object to read from the existing document
using (PdfReader reader = new PdfReader(pathin))
//create PdfStamper object to write to get the pages from reader
using (PdfStamper stamper = new PdfStamper(reader, new FileStream(pathout, FileMode.Create)))
{
//select two pages from the original document
reader.SelectPages("1-2");
//gettins the page size in order to substract from the iTextSharp coordinates
var pageSize = reader.GetPageSize(1);
// PdfContentByte from stamper to add content to the pages over the original content
PdfContentByte pbover = stamper.GetOverContent(1);
//add content to the page using ColumnText
Font font = new Font();
font.Size = 45;
//setting up the X and Y coordinates of the document
int x = point.X;
int y = point.Y;
y = (int) (pageSize.Height - y);
ColumnText.ShowTextAligned(pbover, Element.ALIGN_CENTER, new Phrase(textToAdd, font), x, y, 0);
}
}
Here is a method To print over images:
taken from here.
Use a different layer for your text you're putting over the images, and also make sure to use the GetOverContent() method.
string oldFile = "FileWithImages.pdf";
string watermarkedFile = "Layers.pdf";
// Creating watermark on a separate layer
// Creating iTextSharp.text.pdf.PdfReader object to read the Existing PDF Document
PdfReader reader1 = new PdfReader(oldFile);
using (FileStream fs = new FileStream(watermarkedFile, FileMode.Create, FileAccess.Write, FileShare.None))
// Creating iTextSharp.text.pdf.PdfStamper object to write Data from iTextSharp.text.pdf.PdfReader object to FileStream object
using (PdfStamper stamper = new PdfStamper(reader1, fs))
{
// Getting total number of pages of the Existing Document
int pageCount = reader1.NumberOfPages;
// Create New Layer for Watermark
PdfLayer layer = new PdfLayer("Layer", stamper.Writer);
// Loop through each Page
for (int i = 1; i <= pageCount; i++)
{
// Getting the Page Size
Rectangle rect = reader1.GetPageSize(i);
// Get the ContentByte object
PdfContentByte cb = stamper.GetOverContent(i);
// Tell the cb that the next commands should be "bound" to this new layer
cb.BeginLayer(layer);
BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
cb.SetColorFill(BaseColor.RED);
cb.SetFontAndSize(bf, 100);
cb.BeginText();
cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "Some random blablablabla...", rect.Width / 2, rect.Height / 2, - 90);
cb.EndText();
// Close the layer
cb.EndLayer();
}
}

Categories

Resources