I want to clone a pdf, and make slight changes to the document at some point during or after copying.
I managed to do that with the pages but I am trying to copy also all metadata, form fields, acrofields etc.
How will I be able to do that using iTextSharp ?
Document document = new Document();
FileStream fs = new FileStream(OutputFile, FileMode.Create, FileAccess.Write, FileShare.None)
PdfCopy copy = new PdfCopy(document, fs);
document.Open();
for (int i = 1; i <= reader.NumberOfPages; i++)
{
PdfImportedPage importedPage = copy.GetImportedPage(reader, i);
copy.AddPage(importedPage);
}
copy.Outlines = SimpleBookmark.GetBookmark(reader);
fs.Flush();
PdfCopyFields copyf = new PdfCopyFields(fs);
You cannot make identical-byte copies with iTextSharp. You can make identical copies with System.IO.File.Copy.
You are then free to open it with iTextSharp to make further adjustments to the copy.
You use a PdfCopy based solution.
For your task, though, i.e. to take a single PDF and apply some changes to it, the appropriate solution is PdfStamper based. That would look like this:
PdfReader reader = ...;
[...apply changes using PdfReader methods...]
FileStream fs = new FileStream(OutputFile, FileMode.Create, FileAccess.Write, FileShare.None)
PdfStamper stamper = new PdfStamper(reader, fs);
[...apply changes using PdfStamper methods...]
stamper.Close();
Related
I have created one pdf file that i want to use as template page (contain header and border), so when i add new page to existing pdf it automatically set header and border to newly added page.
I am using ITextSharp PDF library.
I have try using PdfImportedPage as below but it's not working:
PdfReader templateFile;
templateFile = new PdfReader("D:\\templatefile.pdf");
PdfImportedPage template_page;
var fileStream1 = new FileStream("D:\\temp.pdf", FileMode.Create, FileAccess.Write);
var stamper1 = new PdfStamper(templateFile, fileStream1);
template_page = stamper1.GetImportedPage(templateFile, 1);
// now i want to add this template_page to existing pdf at specific position
//this is the file(existingpdf.pdf) in which i want to add template_page create above using stamper
var bytes = File.ReadAllBytes("D:\\existingpdf.pdf");
var reader = new PdfReader(bytes);
var numberofPages = reader.NumberOfPages;
var fileStream = new FileStream("D:\\result.pdf", FileMode.Create, FileAccess.Write);
//stamper of result pdf
var stamper = new PdfStamper(reader, fileStream);
stamper.InsertPage(numberofPages + 1, templateFile.GetPageSize(1));
//below code i have tried to add template but its not working in result pdf
stamper.GetUnderContent(2).AddTemplate(template_page, 0, 0);
stamper.Close();
I'm using ITextSharp to split multi-page PDF files into single page files. I also managed to add those single page PDFs to a zip file using MemoryStream.
Now, I need to add password protection to those PDFs using PdfStamper, before adding them into a zip file. But whenever I tried this, an ObjectDisposedException - Cannot access a closed Stream. is being throwed.
Ionic.Zip.ZipFile zipFile = new Ionic.Zip.ZipFile();
int cnt = 0;
try
{
iTextSharp.text.pdf.PdfReader reader = new iTextSharp.text.pdf.PdfReader(new iTextSharp.text.pdf.RandomAccessFileOrArray(sourcePdfPath), new ASCIIEncoding().GetBytes(""));
for (cnt = 1; cnt <= reader.NumberOfPages; cnt++)
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (iTextSharp.text.Document document = new iTextSharp.text.Document())
{
iTextSharp.text.pdf.PdfWriter writer = iTextSharp.text.pdf.PdfWriter.GetInstance(document, memoryStream);
using (PdfStamper stamper = new PdfStamper(reader, memoryStream))
{
stamper.SetEncryption(
null,
Encoding.ASCII.GetBytes("password_here"),
PdfWriter.ALLOW_PRINTING,
PdfWriter.ENCRYPTION_AES_128);
}
memoryStreamForZipFile = new MemoryStream(memoryStream.ToArray());
memoryStreamForZipFile.Seek(0, SeekOrigin.Begin);
}
}
}
zipFile.Save(destinationFolder + "/" + fileName.Replace(".pdf", ".zip"));
reader.Close();
reader.Dispose();
}
catch
{
}
finally
{
GC.Collect();
}
return cnt - 1;
I have removed some codes above for clarity.
If I'll remove the PdfStamper "using" block, the code works just fine. I also tried to juggle the position of PdfStamper to see if I used it in the wrong place.
Am I not using using blocks properly? Or I have to fix some code sequence in here?
You removed some lines that are essential are wrong; for instance: I assume that you are adding a PdfImportedPage to the PdfContentByte of a PdfWriter. If that's so, you are ignoring all the warnings given in the official documentation.
You should replace your code by something like this:
PdfReader reader = new PdfReader(pathToFile);
int n = reader.NumberOfPages;
int cnt;
for (cnt = 1; cnt <= reader.NumberOfPages; cnt++)
{
reader = new PdfReader(pathToFile);
reader.SelectPages(cnt.ToString());
MemoryStream memoryStream = new MemoryStream();
using (PdfStamper stamper = new PdfStamper(reader, memoryStream))
{
stamper.SetEncryption(
null,
Encoding.ASCII.GetBytes("password_here"),
PdfWriter.ALLOW_PRINTING,
PdfWriter.ENCRYPTION_AES_128);
}
reader.Close();
// now do something with the memoryStream.ToArray()
}
As you can see, there is no need to introduce a Document or a PdfWriter object. If you use those classes, you throw away all interactivity that exists in the original pages. You also get into trouble if the page size of the original pages is different from A4.
Note that you can't reuse the PdfReader instance when using PdfStamper. Once you pass a PdfReader instance to a PdfStamper, that instance is tampered.
I was trying with below code to fill multiple rows in xfa pdf using FillXfaForm() method in C#.net. Anyone please guide me what is wrong on this code. We are using itexsharp.dll version 5.5.4.0.
public void manipulatePdf()
{
using (FileStream existingPdf = new FileStream "existingPdf.pdf",FileMode.Open))
using (FileStream sourceXml = new FileStream("sourceXml.xml", FileMode.Open))
using (FileStream newPdf = new FileStream("mymergedPdf.pdf", FileMode.Create))
{
// Open existing PDF
PdfReader pdfReader = new PdfReader(existingPdf);
// PdfStamper, which will create
PdfStamper stamper = new PdfStamper(pdfReader, newPdf);
AcroFields form = stamper.AcroFields;
XfaForm xfa = form.Xfa;
xfa.FillXfaForm(sourceXml);
stamper.Close();
pdfReader.Close();
}
}
I'm struggling to insert images on a multi-page PDF.
To create several pages I'm using PdfConcatenate, and it works. I get to add pages of my template perfectly. The problem starts when I try to add images. It just doesn't load them.
Here's the code that works to add images:
string pdfTemplate = #"Tools\template.pdf";
string targetPdfPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), fileName + ".pdf");
FileStream output = new FileStream(targetPdfPath, FileMode.Create);
PdfConcatenate pdfConcatenate = new PdfConcatenate(output);
PdfReader pdfReader = new PdfReader(pdfTemplate);
MemoryStream memoryStream = getMemoryStream(output);
PdfStamper pdfStamper = new PdfStamper(pdfReader, output);
int cardIndex = 1;
foreach (Registry reg in registries)
{
setFields(reg, pdfStamper, cardIndex);
if (cardIndex == 4)
{
pdfConcatenate.AddPages(pdfReader);
pdfReader = new PdfReader(pdfTemplate);
pdfStamper = new PdfStamper(pdfReader, output);
cardIndex = 1;
}
else
{
cardIndex++;
}
}
//if (cardIndex != 1)
// pdfConcatenate.AddPages(pdfReader);
//make the form no longer editable
pdfStamper.FormFlattening = true;
pdfStamper.Close();
pdfReader.Close();
//pdfConcatenate.Close();
If use MemoryStream for PdfStamper and uncomment these lines:
//if (cardIndex != 1)
// pdfConcatenate.AddPages(pdfReader);
//pdfConcatenate.Close();
I get it to add pages, but without images.
Any idea of what is wrong?
SOLUTION: (Thanks to #mkl)
string pdfTemplate = #"Tools\template.pdf";
string targetPdfPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), fileName + ".pdf");
FileStream output = new FileStream(targetPdfPath, FileMode.Create);
PdfConcatenate pdfConcatenate = new PdfConcatenate(output);
PdfReader pdfReader = new PdfReader(pdfTemplate);
MemoryStream memoryStream = new MemoryStream();
PdfStamper pdfStamper = new PdfStamper(pdfReader, memoryStream);
int cardIndex = 1;
foreach (Registry reg in registries)
{
setFields(reg, pdfStamper, cardIndex);
if (cardIndex == 4)
{
pdfStamper.FormFlattening = true;
pdfStamper.Close();
PdfReader tempReader = new PdfReader(memoryStream.ToArray());
pdfConcatenate.AddPages(tempReader);
memoryStream = new MemoryStream();
pdfReader = new PdfReader(pdfTemplate);
pdfStamper = new PdfStamper(pdfReader, memoryStream);
cardIndex = 1;
}
else
{
cardIndex++;
}
}
if (cardIndex != 1)
{
pdfStamper.FormFlattening = true;
pdfStamper.Close();
PdfReader tempReader = new PdfReader(memoryStream.ToArray());
pdfConcatenate.AddPages(tempReader);
tempReader.Close();
}
pdfStamper.Close();
pdfReader.Close();
pdfConcatenate.Close();
The problem most likely is some misconception on how PdfStamperworks. You seem to think it somehow manipulates the data in the PdfReader it stamps, and also pages exported from that reader beforehand. This is not the case, a PdfStamper generates a new PDF file (in its output stream) based on the data in the reader but the contents of the reader itself are not updated to also reflect all the changes (the PdfReader object may be touched in the process, though, and not be reusable afterwards). So...
As already mentioned in the comment, you have the PdfConcatenate and an unknown number of PdfStamper instances all writing the same `FileStream' output. As each of these objects creates an independant PDF, you are lucky if one of then wins because then you'll get at least a proper PDF as output. Otherwise you either get some exception or garbage consisting of multiple intermingled PDFs. Thus, make only PdfConcatenate target your output file.
If your actual intent is to repeatedly fill the template fields with the content of 4 cards each time and combine the results, you should not add the pages from the PdfReader of the template to the PdfConcatenate --- the pages in that reader are not filled in! --- but instead have the PdfStamper output to a MemoryStream, fill its fields, flatten its form, close it, open its output in a new PdfReader, and add all the pages in that reader to the PdfConcatenate.
I don't dare to put that into code as I'm predominantly using Java and writing down untested C# code most likely would include multiple errors... ;)
PS: Currently you count on all the PdfReader instances you open to be implicitly closed somewhere. While that is true currently, recent check-ins in the iText SVN repository seem to indicate that these implicit close calls are removed from the code. Thus, please also start explicitly closing PdfReader instances you dont't use anymore. Otherwise you will soon have to deal with memory leaks due to readers closing much too late..
I try to fill a PDF form with C#. But somehow it does not work. The problem: the fields object (in the line: fields.SetField("Name", "Peter");) seems to be null.
Here is my code:
public static void FillForm()
{
String pdfTemplate = #"c:\Users\Hagen\Desktop\formular.pdf";
String newFile = #"c:\Users\Hagen\Desktop\formular_fertig.pdf";
PdfReader pdfReader = new PdfReader(pdfTemplate);
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(newFile, FileMode.Create));
AcroFields fields = pdfStamper.AcroFields;
fields.SetField("Name", "Peter");
pdfStamper.Close();
}
I remember having a similar problem when I first tried to fill in form fields. The line you have that initializes the pdfStamper;
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(newFile, FileMode.Create));
Try adding ReadWrite permissions to the stamper object like so.
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(newFile, FileMode.Create, FileAccess.ReadWrite));
That MIGHT be your problem. I don't recall exactly how I fixed this problem myself, but that is what jumps out to me initially. It may very well be trying to write in the field value, but the stamper doesn't have the FileAccess it requires to accomplish this.
Hope this helps