/AF reference to file embedded into a PDF with iTextSharp - pdf

I am struggling to include into the PDF Catalog an "/AF" reference to an Embedded File object just added by the iTextSharp library. The following code works, but the string literal PdfLiteral("[2 0 R]") is unbearable, because the reference to an embedded file may of course have any other number than "2 0":
PdfReader reader = new PdfReader("C:\\ZUGFeRD\\zugferd_2p1_EN16931_Einfach_stripped.pdf");
FileStream outputstream = new FileStream("C:\\ZUGFeRD\\zugferd_2p1_EN16931_Einfach2.pdf", FileMode.Create);
PdfStamper stamp = new PdfStamper(reader, outputstream);
PdfWriter writer = stamp.Writer;
byte[] bytes = System.IO.File.ReadAllBytes("C:\\ZUGFeRD\\factur-x.xml");
// Sample spec: Desc(factur-x.xml) / EF <</ UF 4 0 R / F 4 0 R >>/ Type / Filespec / AFRelationship / Alternative / F(factur-x.xml) / UF(factur - x.xml)
PdfFileSpecification fs = PdfFileSpecification.FileEmbedded(writer, "", "factur-x.xml", bytes, false, "text/xml", null);
fs.Put(PdfName.AFRELATIONSHIP, new PdfName("Source"));
stamp.AddFileAttachment("factur-x.xml", fs);
stamp.Writer.ExtraCatalog.Put(PdfName.AF, new PdfLiteral("[2 0 R]"));
stamp.Close();
How can I write it better?

Related

Error on HTTP response when exporting PDF file

I've been stuck with this question for a while, already tried several variations of the code but always with the same error. The error is "Server cannot set content type after HTTP headers have been sent."
I create my pdf with pdfptables, I suspect it is trying to export before it generates the Document but I have no clue. This is the last part of the code:
string filename = String.Format("productionstagereport-{0}", DateTime.Now.ToString("yyyyMMdd"));
MemoryStream ms = new MemoryStream();
Document document = new Document(PageSize.A4.Rotate());
document.Open();
foreach (PdfPTable content in masterTable)
document.Add(content);
document.Close();
PdfWriter writer = PdfWriter.GetInstance(document, ms);
writer.Close();
Response.ContentType = "pdf/application";
Response.AddHeader("content-disposition", "attachment;filename=" + filename + ".pdf");
Response.OutputStream.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
Response.Flush();

Adding external pdf content generated from SVG using apache batik to Source PDF using Itext with header and footer

I have the below requirement.
Convert the SVG to PDF using Apache batik
Prepare source PDF document with Header and Footer using IText 7
Take the converted PDF and embed it in the content of the source PDF
I have seen IText supports converting an SVG to Image but the output is not proper. The output from batik seems to be perfect.
Below is my code. Can anyone please suggest a proper approach ? I am not able to achieve it
SVG to PDF using batik
FileInputStream inputStream = new FileInputStream(new File(Paths.get("Input").toAbsolutePath()+"/test.svg"));
byte[] bytes = IOUtils.toByteArray(inputStream);
FileOutputStream pdfOutputStream = new FileOutputStream(new File(Paths.get("Output").toAbsolutePath()+"/convertedSvg.pdf"));
Transcoder transcoder = new PDFTranscoder();
TranscoderInput transcoderInput = new TranscoderInput(new ByteArrayInputStream(bytes));
TranscoderOutput transcoderOutput = new TranscoderOutput(pdfOutputStream);
int dpi = 300;
transcoder.addTranscodingHint(PDFTranscoder.KEY_WIDTH, new Float(dpi * 29.7));
transcoder.addTranscodingHint(PDFTranscoder.KEY_HEIGHT, new Float(dpi * 42.0));
transcoder.addTranscodingHint(PDFTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER,(25.4f / 72f));
transcoder.transcode(transcoderInput, transcoderOutput);
iText Code
PdfWriter writer = new PdfWriter(new FileOutputStream(new File(Paths.get("Output").toAbsolutePath()+"/final.pdf")));
PdfDocument pdfDoc = new PdfDocument(writer);
pdfDoc.setDefaultPageSize(PageSize.A3.rotate());
NormalPageHeader headerHandler = new NormalPageHeader(Paths.get("images").toAbsolutePath() + "\\logo.png", pdfFontMap);
pdfDoc.addEventHandler(PdfDocumentEvent.START_PAGE, headerHandler);
PageEndEvent pageEndEvent = new PageEndEvent(Paths.get("images").toAbsolutePath() + "\\FooterLineExternal.png" ,pdfFontMap);
pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, pageEndEvent);
Document doc = new Document(pdfDoc);
doc.getPageEffectiveArea(PageSize.A3.rotate());
Table imageTable = new Table(1);
imageTable.setBorder(Border.NO_BORDER);
imageTable.setWidth(UnitValue.createPercentValue(100));
Cell cell = new Cell();
Paragraph paragraph = new Paragraph("Horizontal Trajectory");
paragraph.setVerticalAlignment(VerticalAlignment.TOP);
cell.add(paragraph);
cell.setBorder(Border.NO_BORDER);
cell.setPaddingTop(50);
imageTable.addCell(cell);
doc.add(imageTable);
doc.close();

In iText, is it possible to preserve the reading-order of XFA PDF, as stored in the <traversal> and <traverse> elements, when flattening to PDF/A 1a?

How can I preserve reading-order when using iText to fill and flatten an XFA PDF creating a PDF/A 1a?
The reading-order of the pre-flattened PDF is stored in the and elements, but this information is not being expressed in the flattened tagged PDF/A 1a document.
Specifically, my two-column form, which is read properly by JAWS prior to flattening, is incorrectly read left-to-right from top to bottom all the way across both columns instead of being reading down one column and then proceeding to the beginning of the second column.
The iText Java code looks like this:
public void manipulatePdf(String src, String xml, File dest)
throws IOException, DocumentException, InterruptedException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, baos);
AcroFields form = stamper.getAcroFields();
XfaForm xfa = form.getXfa();
stamper.close();
Document document = new Document();
PdfAWriter writer = PdfAWriter.getInstance(document,
new FileOutputStream(dest), PdfAConformanceLevel.PDF_A_1A);
writer.setTagged();
document.addLanguage("en-us");
document.open();
ICC_Profile iccProfile = ICC_Profile.getInstance(new FileInputStream(
colorProfile));
writer.setOutputIntents("Custom", "", "http://www.color.org",
"sRGB IEC61966-2.1", iccProfile);
PdfICCBased iccBased = new PdfICCBased(iccProfile);
iccBased.remove(PdfName.ALTERNATE);
PdfDictionary outputIntent = new PdfDictionary(PdfName.OUTPUTINTENT);
outputIntent.put(PdfName.OUTPUTCONDITIONIDENTIFIER, new PdfString(
"sRGB IEC61966-2.1"));
outputIntent.put(PdfName.INFO, new PdfString("sRGB IEC61966-2.1"));
outputIntent.put(PdfName.S, PdfName.GTS_PDFA1);
outputIntent.put(PdfName.DESTOUTPUTPROFILE, writer.addToBody(iccBased)
.getIndirectReference());
writer.getExtraCatalog().put(PdfName.OUTPUTINTENTS,
new PdfArray(outputIntent));
PdfDictionary markInfo = new PdfDictionary(PdfName.MARKINFO);
markInfo.put(PdfName.MARKED, new PdfBoolean(true));
writer.getExtraCatalog().put(PdfName.MARKINFO, markInfo);
XFAFlattener xfaf = new XFAFlattener(document, writer);
xfaf.flatten(new PdfReader(baos.toByteArray()), false);
document.close();
System.out.println("The form is flattened");
}

Get and set metadata for itext pdf document

I have an iText Document object and I want to write some metadata into it or read from it.
How can I do that?
Imagine that the document is beeing passed to a method like :
public void prePreccess(Object document) {
Document pdfDocument = ((Document) document);
//What to do here with pdfDocument?
}
Do you want to populate the info dictionary of a PDF? That's explained in the MetadataPdf example:
// step 1
Document document = new Document();
// step 2
PdfWriter.getInstance(document, new FileOutputStream(filename));
// step 3
document.addTitle("Hello World example");
document.addAuthor("Bruno Lowagie");
document.addSubject("This example shows how to add metadata");
document.addKeywords("Metadata, iText, PDF");
document.addCreator("My program using iText");
document.open();
// step 4
document.add(new Paragraph("Hello World"));
// step 5
document.close();
Do you want to set the XMP metadata? This is explained in the MetadataXmp example:
// step 1
Document document = new Document();
// step 2
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(RESULT1));
ByteArrayOutputStream os = new ByteArrayOutputStream();
XmpWriter xmp = new XmpWriter(os);
XmpSchema dc = new com.itextpdf.text.xml.xmp.DublinCoreSchema();
XmpArray subject = new XmpArray(XmpArray.UNORDERED);
subject.add("Hello World");
subject.add("XMP & Metadata");
subject.add("Metadata");
dc.setProperty(DublinCoreSchema.SUBJECT, subject);
xmp.addRdfDescription(dc);
PdfSchema pdf = new PdfSchema();
pdf.setProperty(PdfSchema.KEYWORDS, "Hello World, XMP, Metadata");
pdf.setProperty(PdfSchema.VERSION, "1.4");
xmp.addRdfDescription(pdf);
xmp.close();
writer.setXmpMetadata(os.toByteArray());
// step 3
document.open();
// step 4
document.add(new Paragraph("Hello World"));
// step 5
document.close();
Note that this method is deprecated: we have replaced the XMP functionality recently, but we still have to write some examples using the new code.
Maybe you want to set populate the info dictionary and create the XMP metadata at the same time:
// step 1
Document document = new Document();
// step 2
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filename));
document.addTitle("Hello World example");
document.addSubject("This example shows how to add metadata & XMP");
document.addKeywords("Metadata, iText, step 3");
document.addCreator("My program using 'iText'");
document.addAuthor("Bruno Lowagie");
writer.createXmpMetadata();
// step 3
document.open();
// step 4
document.add(new Paragraph("Hello World"));
// step 5
document.close();
If I were you, I'd use this option because it's the most complete solution.
You should not read the metadata from a Document object.
You can read the XMP stream from an existing PDF like this:
public void readXmpMetadata(String src, String dest) throws IOException {
PdfReader reader = new PdfReader(src);
FileOutputStream fos = new FileOutputStream(dest);
byte[] b = reader.getMetadata();
fos.write(b, 0, b.length);
fos.flush();
fos.close();
reader.close();
}
You can read the entries in the info dictionary like this:
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
Map<String, String> info = reader.getInfo();
The info object will contain a series of keys and values that are stored as metadata inside the PDF.

Splitted PDF size is larger when using the iTextSharp

Dear Team,
In my application, i want to split the pdf using itextsharp. If i upload PDF contains 10 pages with file size 10 mb for split, After splitting the combine file size of each pdfs will result into above 20mb file size. If this possible to reduce the file size(each pdf).
Please help me to solve the issue.
Thanks in advance
This may have to do with the resources in the file. If the original document uses an embedded font on each, for example, then there will only be one instance of the font in the original file. When you split it, each file will be required have that font as well. The total overhead will be n pages × sizeof(each font). Elements that will cause this kind of bloat include fonts, images, color profiles, document templates (aka forms), XMP, etc.
And while it doesn't help you in your immediate problem, if you use the PDF tools in Atalasoft dotImage, your task becomes a 1 liner:
PdfDocument.Separate(userpassword, ownerpassword, origPath, destFolder, "Separated Page{0}.pdf", true);
which will take the PDF in orig file and create new pages in the dest folder each named with the pattern. The bool at the end is to overwrite an existing file.
Disclaimer: I work for Atalasoft and wrote the PDF library (also used to work at Adobe on Acrobat versions 1, 2, 3, and 4).
Hi Guys i modified the above code to split a PDF file into multiple Pdf file.
iTextSharp.text.pdf.PdfReader reader = null;
int currentPage = 1;
int pageCount = 0;
//string filepath_New = filepath + "\\PDFDestination\\";
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
//byte[] arrayofPassword = encoding.GetBytes(ExistingFilePassword);
reader = new iTextSharp.text.pdf.PdfReader(filepath);
reader.RemoveUnusedObjects();
pageCount = reader.NumberOfPages;
string ext = System.IO.Path.GetExtension(filepath);
for (int i = 1; i <= pageCount; i++)
{
iTextSharp.text.pdf.PdfReader reader1 = new iTextSharp.text.pdf.PdfReader(filepath);
string outfile = filepath.Replace((System.IO.Path.GetFileName(filepath)), (System.IO.Path.GetFileName(filepath).Replace(".pdf", "") + "_" + i.ToString()) + ext);
reader1.RemoveUnusedObjects();
iTextSharp.text.Document doc = new iTextSharp.text.Document(reader.GetPageSizeWithRotation(currentPage));
iTextSharp.text.pdf.PdfCopy pdfCpy = new iTextSharp.text.pdf.PdfCopy(doc, new System.IO.FileStream(outfile, System.IO.FileMode.Create));
doc.Open();
for (int j = 1; j <= 1; j++)
{
iTextSharp.text.pdf.PdfImportedPage page = pdfCpy.GetImportedPage(reader1, currentPage);
pdfCpy.SetFullCompression();
pdfCpy.AddPage(page);
currentPage += 1;
}
doc.Close();
pdfCpy.Close();
reader1.Close();
reader.Close();
}
Have you tried setting the compression on the writer?
Document doc = new Document();
using (MemoryStream ms = new MemoryStream())
{
PdfWriter writer = PdfWriter.GetInstance(doc, ms);
writer.SetFullCompression();
}