In the code below I want to be able to read in a PDF file and add some encryption and then resave the file. what is the best way to do that? I dont see a Save method in pdfDocument is there another object I should use?
PdfReader pdfReader = null;
byte[] bytesPassword = System.Text.ASCIIEncoding.UTF8.GetBytes("PassWord");
WriterProperties writerProperties = new WriterProperties();
PdfDocument pdfDocument = null;
using (MemoryStream ms = new MemoryStream())
{
pdfReader = new PdfReader(destFile);
writerProperties.SetStandardEncryption(null, bytesPassword, EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_256);
pdfDocument = new PdfDocument(pdfReader, new PdfWriter(ms, writerProperties));
pdfDocument.Close();
}
//pdfDocument.Save(FilePath1)
//pdfDocument.Save(FilePath2)
Related
I have been trying to get a grip of iText7 c# with little luck.
My goal is:
Load a pdf (one page) with a form (multiple fields) as a template
Fill out the form, Flatten and copy the filled forms page to a new document
repeat #2 x number of times with different data
Save to Memory Stream
I have the different parts working , but i cant get it to work together
var memoryStream = new MemoryStream();
PdfReader reader = new PdfReader("untitled-1.pdf"); //Iput
PdfWriter writer = new PdfWriter(memoryStream); //output
PdfDocument pdfDoc = new PdfDocument(reader, writer);
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdfDoc, true);
var fields = form.GetFormFields();
if(fields.ContainsKey("address")) {
fields["address"].SetValue("first\nlast");
}
form.FlattenFields();
pdfDoc.Close();
byte[] b = memoryStream.ToArray();
File.WriteAllBytes(#"t.pdf", b);
clone page:
// create clone page x times
PdfDocument pdfDoc = new PdfDocument(new PdfWriter("output.pdf").SetSmartMode(true));
pdfDoc.InitializeOutlines();
PdfDocument srcDoc;
for (int i = 0; i<5; i++) {
srcDoc = new PdfDocument(new PdfReader("untitled-1.pdf"));
// copy content to the resulting PDF
srcDoc.CopyPagesTo(1, srcDoc.GetNumberOfPages(), pdfDoc);
}
pdfDoc.Close();
got an idea just after writing this question. Here is one solution to this problem
Create a pdf-file with a form and a text field named address to use as template, save as untitled1-pdf.
This code will create an empty document and then for each user in users load and fill the field address whit the user.
The filled form will then be flatten and copied into the new document.
When all is done, the document will be saved as result.pdf
//b.
static void Main(string[] args)
{
List<string> users = new List<string> { "Peter", "john", "Carl" };
byte[] result = createPdf(users, "untitled-1.pdf");
File.WriteAllBytes(#"result.pdf", result);
}
public static byte[] createPdf(List<string> users,string templateFile)
{
// create clone page for each user in users
using (MemoryStream memoryStream = new MemoryStream())
{
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(memoryStream).SetSmartMode(true));
pdfDoc.InitializeOutlines();
PdfDocument srcDoc;
foreach (var u in users)
{
MemoryStream m = new MemoryStream(fillForm(u,templateFile));
srcDoc = new PdfDocument(new PdfReader(m));
// copy content to the resulting PDF
srcDoc.CopyPagesTo(1, srcDoc.GetNumberOfPages(), pdfDoc);
}
pdfDoc.Close();
return memoryStream.ToArray();
}
}
public static byte[] fillForm(string user,string templateFile)
{
using (var memoryStream = new MemoryStream())
{
PdfReader reader = new PdfReader(templateFile); //Iput
PdfWriter writer = new PdfWriter(memoryStream); //output
PdfDocument pdfDoc = new PdfDocument(reader, writer);
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdfDoc, true);
var fields = form.GetFormFields();
if (fields.ContainsKey("address"))
{
fields["address"].SetValue(user);
}
form.FlattenFields();
pdfDoc.Close();
byte[] b = memoryStream.ToArray();
return b;
}
}
I have a System.Net.Mail.MailMessage which shall have it's html body and pdf attachments converted into one single pdf.
Converting the html body to pdf works for me with this answer
Converting the pdf attachments into one pdf works for me with this answer
However after ~10 hours of trying I can not come up with a combined solution which does both. All I'm getting are NullReferenceExceptions somewhere in IText source, "the document is not open", etc...
For example, this will throw no error but the resulting pdf will only contain the attachments but not the html email body:
Document document = new Document();
StringReader sr = new StringReader(mail.Body);
HTMLWorker htmlparser = new HTMLWorker(document);
using (FileStream fs = new FileStream(targetPath, FileMode.Create))
{
PdfCopy writer = new PdfCopy(document, fs);
document.Open();
htmlparser.Parse(sr);
foreach (string fileName in pdfList)
{
PdfReader reader = new PdfReader(fileName);
reader.ConsolidateNamedDestinations();
for (int i = 1; i <= reader.NumberOfPages; i++)
{
PdfImportedPage page = writer.GetImportedPage(reader, i);
writer.AddPage(page);
}
PRAcroForm form = reader.AcroForm;
if (form != null)
{
writer.CopyAcroForm(reader);
}
reader.Close();
}
writer.Close();
document.Close();
}
I'm using the LGPL licensed ITextSharp 4.1.6
From v4.1.6 fanboy to v4.1.6 fanboy :D
Looks like the HTMLWorker is closing the documents stream right after parsing. So as a workaround, you could create a pdf from your mailbody in memory. And then add this one together with the attachment to your final pdf.
Here is some code, that should do the trick:
StringReader htmlStringReader = new StringReader("<html><body>Hello World!!!!!!</body></html>");
byte[] htmlResult;
using (MemoryStream htmlStream = new MemoryStream())
{
Document htmlDoc = new Document();
PdfWriter htmlWriter = PdfWriter.GetInstance(htmlDoc, htmlStream);
htmlDoc.Open();
HTMLWorker htmlWorker = new HTMLWorker(htmlDoc);
htmlWorker.Parse(htmlStringReader);
htmlDoc.Close();
htmlResult = htmlStream.ToArray();
}
byte[] pdfResult;
using (MemoryStream pdfStream = new MemoryStream())
{
Document doc = new Document();
PdfCopy copyWriter = new PdfCopy(doc, pdfStream);
doc.Open();
PdfReader htmlPdfReader = new PdfReader(htmlResult);
AppendPdf(copyWriter, htmlPdfReader); // your foreach pdf code here
htmlPdfReader.Close();
PdfReader attachmentReader = new PdfReader("C:\\temp\\test.pdf");
AppendPdf(copyWriter, attachmentReader);
attachmentReader.Close();
doc.Close();
pdfResult = pdfStream.ToArray();
}
using (FileStream fs = new FileStream("C:\\temp\\test2.pdf", FileMode.Create, FileAccess.Write))
{
fs.Write(pdfResult, 0, pdfResult.Length);
}
private void AppendPdf(PdfCopy writer, PdfReader reader)
{
for (int i = 1; i <= reader.NumberOfPages; i++)
{
PdfImportedPage page = writer.GetImportedPage(reader, i);
writer.AddPage(page);
}
}
Ofc you could directly use a FileStream for the final document instead of a MemoryStream as well.
I am using ITextSharp to merge PDFs.
My problem is when I merge huge PDFs, it takes a very long time to do it (many minutes). It appears that it takes all this time on the "document.close()".
Here is my code :
iTextSharp.text.Document doc = new iTextSharp.text.Document();
PdfCopy copy = new PdfCopy(doc, msOutput);
copy.SetMergeFields();
doc.Open();
byte[] byteArray = Convert.FromBase64String("someString");
PdfReader reader = new PdfReader(byteArray);
copy.AddDocument(reader);
doc.Close(); // <== It takes time here !
byte[] form = msOutput.ToArray();
Is there anything I did wrong ?
How can I improve this merging time ?
You are missing some Close() calls - this may help to bring your time down:
byte[] form
using (var msOutput = new MemoryStream())
{
iTextSharp.text.Document doc = new iTextSharp.text.Document();
byte[] byteArray = Convert.FromBase64String("someString");
PdfCopy copy = new PdfCopy(doc, msOutput);
copy.SetMergeFields();
doc.Open();
PdfReader reader = new PdfReader(byteArray);
copy.AddDocument(reader);
reader.Close();
copy.Close();
doc.Close();
form = msOutput.ToArray();
}
You should also be sure you are properly disposing of your stream after use.
I'm getting an error while closing my document. It's thrown when calling the function "FixTaggedStructure" from PdfCopy
Dictionary<int, PdfIndirectReference> numTree = structureTreeRoot.NumTree;
My debugger shows that "structureTreeRoot" is null, but I don't know why.
My code is very simple. I am trying to convert a PDF to an PDF/A-1 referring to
Convert PDF to PDF/A3 or PDF/A-1 to PDF/A-3
Document doc = new Document();
FileStream fs = new FileStream(destPdfA, FileMode.Create);
PdfReader reader = new PdfReader(pdfParth);
PdfCopy copy = new PdfCopy(doc, fs);
copy.SetPdfVersion(PdfCopy.PDF_VERSION_1_4);
copy.SetTagged();
copy.CreateXmpMetadata();
doc.Open();
ICC_Profile icc = ICC_Profile.GetInstance(new FileStream(ICM, FileMode.Open));
PdfDictionary outi = new PdfDictionary(PdfName.OUTPUTINTENT);
outi.Put(PdfName.OUTPUTCONDITIONIDENTIFIER, new PdfString("sRGB IEC61966-2.1"));
outi.Put(PdfName.INFO, new PdfString("sRGB IEC61966-2.1"));
outi.Put(PdfName.S, PdfName.GTS_PDFA1);
// get this file here: http://old.nabble.com/attachment/10971467/0/srgb.profile
PdfICCBased ib = new PdfICCBased(icc);
ib.Remove(PdfName.ALTERNATE);
outi.Put(PdfName.DESTOUTPUTPROFILE, copy.AddToBody(ib).IndirectReference);
copy.ExtraCatalog.Put(PdfName.OUTPUTINTENTS, outi);
copy.AddDocument(reader);
doc.Close();
I would like to get a pdf, keep somes pages, then save it to another destination without losing fieldstructure.
Here the code perfectly working for copying:
string sourceFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string sourceFile = Path.Combine(sourceFolder, "POMultiple.pdf");
string fileName = #"C:\Users\MyUser\Desktop\POMultiple.pdf";
byte[] file = System.IO.File.ReadAllBytes(fileName);
public static void removePagesFromPdf(byte[] sourceFile, String destinationFile, params int[] pagesToKeep)
{
//Used to pull individual pages from our source
PdfReader r = new PdfReader(sourceFile);
//Create our destination file
using (FileStream fs = new FileStream(destinationFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
using (Document doc = new Document())
{
PdfWriter writer = PdfWriter.GetInstance(doc, fs);
//Open the desitination for writing
doc.Open();
//Loop through each page that we want to keep
foreach (int page in pagesToKeep)
{
//Add a new blank page to destination document
doc.NewPage();
//Extract the given page from our reader and add it directly to the destination PDF
writer.DirectContent.AddTemplate(writer.GetImportedPage(r, page), 0, 0);
}
//Close our document
doc.Close();
}
}
}
But when I open "TestOutput.pdf" file in acrobat reader all my fields are empty.
Any Help ?
You need something like this:
PdfReader reader = new PdfReader(sourceFile);
reader.SelectPages(2-4,8-9);
PdfStamper stp = new PdfStamper(reader, new FileStream(destinationFile, FileMode.Create));
stp.Close();
reader.Close();