I have multiple PDF documents that I am merging into a single document. The goal is to create a brand new outline. Each of these sub-documents could have there own outline, I need to remove them and have one entry in the outline per document. If I click on the outline in the merged document, the user has to be taken to the specific page where the sub-document was inserted.
I am merging and removing the existing outline as follows:
InputStream intputSteam = googleDriveService.executeMediaAsInputStream(fileId);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
PdfDocument pdfDocument1 = new PdfDocument(new PdfReader(bais));
PdfDocument pdfDocument2 = new PdfDocument(new PdfReader(intputSteam));
PdfDocument mergedDocument = new PdfDocument(new PdfWriter(baos));
PdfMerger merger = new PdfMerger(mergedDocument);
merger.setCloseSourceDocuments(true)
.merge(pdfDocument1, 1, pdfDocument1.getNumberOfPages())
.merge(pdfDocument2, 1, pdfDocument2.getNumberOfPages());
mergedDocument.getCatalog().remove(PdfName.Outlines);
mergedDocument.close();
The merged document is uploaded to the Google Drive. Later in the execution, the merged document is loaded into memory from Google Drive and I am adding an outline as follows:
InputStream inputStream = driveService.files().get(fileId).executeMediaAsInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfReader pdfReader = new PdfReader(inputStream);
PdfWriter pdfWriter = new PdfWriter(baos);
PdfDocument doc = new PdfDocument(pdfReader, pdfWriter);
PdfOutline pdfOutine = doc.getOutlines(false);
pdfOutine.addOutline("test #1").addAction(PdfAction.createGoTo(PdfExplicitDestination.createFit(5)));
doc.close();
// Upload the document to Google Drive
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
File fileMetadata = new File();
fileMetadata.setName("generated-doc.pdf");
InputStreamContent inputStreamContent = new InputStreamContent("application/pdf", bais);
driveService.files().create(fileMetadata, inputStreamContent)
.execute();
In the resulting document, the outline from the sub-documents has been removed, but the new outline has not been added. Is there something wrong with the way I am adding the outline?
Related
I'm trying to use custom fonts for my itext7 to allow my pdf to write Arabic texts. what I did is the following:
var path2 = global::Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
filePath = System.IO.Path.Combine(path2.ToString(), "myfile3.pdf");
stream = new FileStream(filePath, FileMode.Create);
iText.Layout.Element.Table table = new iText.Layout.Element.Table(3, false);
table.SetWidth(400).SetFixedLayout();
string[] sources = new string[] { "يوم","شهر 2020" };
PdfWriter writer2 = new PdfWriter(stream);
PdfDocument pdfDocument = new PdfDocument(writer2);
Document document2 = new Document(pdfDocument);
PdfFont arab= PdfFontFactory.CreateFont("NotoNaskhArabic-Regular.ttf");
document2.SetFont(arab);
foreach (string source in sources)
{
Paragraph paragraph = new Paragraph();
Bidi bidi = new Bidi(source, Bidi.DirectionDefaultLeftToRight);
if (bidi.BaseLevel != 0)
{
paragraph.SetTextAlignment(iText.Layout.Properties.TextAlignment.RIGHT);
}
paragraph.Add(source);
table.AddCell(new Cell(1,1).SetTextAlignment(iText.Layout.Properties.TextAlignment.CENTER).Add(paragraph));
}
document2.Add(table);
document2.Close();
I tried different paths for my font. I put it in my resources folder, in my assets, tried to reach it from C:\Windows\Fonts\ARIAL.TTF when I tried using arial font, but all of those didn't work, I don't get it, what should my path be so I won't get this exception: System.IO.IOException: path to ttf file not found as file or resource.'
Once you have your file in assets, you could use AssetManager to read the bytes from the font.Then create the font by the bytes.
You could refer to this and convert it to C# code.
I convert Jpanel to PDF using iText PDF, but certain special (Turkish) characters are not being displayed in the resulting PDF document.
My code is shown below:
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(path));
document.open();
document.newPage();
Rectangle rec = new Rectangle(0,0,panel.getWidth(), panel.getHeight());
document.setPageSize(rec);
PdfContentByte contentByte = writer.getDirectContent();
PdfGraphics2D g2 = new PdfGraphics2D(contentByte,panel.getWidth(),panel.getHeight());
panel.print(g2);
g2.dispose();
My application is grabbing pdf bytes from our db and sending the pdf to an iframe, using the itextsharp library. When the pdf is displayed in the iframe, the toolbar and navigation pane show, but we'd like to hide those. When I load a pdf document by simply typing in the pdf's url with #toolbar=0&navpanes=0, I see the result I'm looking for.
The application logic is using PdfStamper to add some buttons and other data to the pdf. When I write the pdf to the Response.Outputstream, the pdf shows up with the added buttons, and all is good except that I can't get rid of the toolbar and navpanes. I've tried adding "toolbar=0&navpanes=0" to the url in the response header, but to no avail.
I've written a test application which shows that using PdfSmartCopy instead of the stamper works perfectly - the pdf is shown in the browser which hides the toolbar and navpane by default.
The problem is that I still need to add some buttons to the pdf via the stamper. I've written a test app which adds the buttons via the stamper, then the smart copy grabs each page from the stamper and writes all this out to the Response.Output. The pdf shows in the browser with no toolbar or navpanes, but the buttons are not there.
Here is the code which uses both the stamper and the smart copy - your help is greatly appreciated:
private void SendStamperToCopy()
{
try
{
String filePath = #"C:\debug\PerfIndicWithDefaults.pdf";
byte[] pdfBytes = ReadFile(filePath);
Document document = new Document();
PdfSmartCopy copy = new PdfSmartCopy(document, Response.OutputStream);
document.Open();
MemoryStream memStream = new MemoryStream();
PdfReader reader = new PdfReader(pdfBytes);
PdfStamper pdfStamper = new PdfStamper(reader, memStream);
// add a button with the stamper
iTextSharp.text.Rectangle rectCancel = new iTextSharp.text.Rectangle(50, 50, 20, 20);
PushbuttonField btnCancel = new PushbuttonField(pdfStamper.Writer, rectCancel, "Cancel");
btnCancel.Text = "Cancel";
iTextSharp.text.pdf.PdfAnnotation fieldCancel = btnCancel.Field;
pdfStamper.AddAnnotation(fieldCancel, 1);
int numOfPgs = reader.NumberOfPages;
for (int n = 1; n <= numOfPgs; n++)
{
copy.AddPage(pdfStamper.GetImportedPage(reader, n));
}
String headerStr = "inline; filename=PerfIndicWithDefaults.pdf";
Response.AppendHeader("content-disposition", headerStr);
Response.ContentType = "application/pdf";
Response.OutputStream.Flush();
document.Close();
Response.OutputStream.Close();
}
catch (Exception ex)
{
Console.Write(ex);
Response.OutputStream.Flush();
Response.OutputStream.Close();
}
}
If I understand your question correctly, you want to use PdfStamper to add a button and you want to change the viewer preferences. This can be done like this:
PdfReader reader = new PdfReader(source);
System.IO.MemoryStream m = new System.IO.MemoryStream();
PdfStamper stamper = new PdfStamper(reader, m);
PdfStamper.ViewerPreferences = PdfWriter.HideToolbar | PdfWriter.PageModeUseNone;
stamper.Close();
reader.Close();
The HideToolbar will hide the toolbar, whereas PageModeUseNone means that you don't show any panels (such as the bookmarks panel, etc...).
It is not clear why you would need PdfSmartCopy in this context. Maybe I'm missing something. Also: there are some strange errors in your code: you never close the stamper instance, yet you import a page from the stamper into the copy instance. I've never seen any one try that. It's certainly not what I had in mind when I wrote iText. Your code is very confusing to me.
We're replacing Adobe LiveCycle Server with iText 5.4.1 in an existing webapp to merge XML data with LiveCycle Designer-generated PDF templates, generating editable PDF files from several hundred templates.
This code combines the data with the template, returning a PDF byte array:
// Import data into the PDF form
if (pdfTemplateFileName != null && inputXmlDataFile != null) {
// set up the objects
template = new PdfReader(pdfTemplateFileName);
filledPDF = new ByteArrayOutputStream();
stamper = new PdfStamper(template, filledPDF);
AcroFields form = stamper.getAcroFields();
// fill in the form with the data
XfaForm xfa = form.getXfa();
xfa.fillXfaForm(inputXmlDataFile);
//closing the stamper is necessary to flush to filledPDF
stamper.close();
returnPDF = filledPDF.toByteArray();
}
This code combines the PDF byte arrays into a portfolio:
List<byte[]> assemblingPdfList = assemblingPdfMap.get("newStyleForms");
// create PDF portfolio of editable documents
com.itextpdf.text.Document document = new com.itextpdf.text.Document();
ByteArrayOutputStream mergedPDFOutput = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, mergedPDFOutput);
document.open();
Paragraph coverSheet = new Paragraph("Multiple files are bound together in this PDF Package");
coverSheet.setAlignment(com.itextpdf.text.Element.ALIGN_CENTER);
document.add(coverSheet);
// define the collection
PdfCollection collection = new PdfCollection(PdfCollection.DETAILS);
PdfCollectionSchema schema = new PdfCollectionSchema();
PdfCollectionField filename = new PdfCollectionField("Name", PdfCollectionField.FILENAME);
filename.setOrder(0);
schema.addField("FILENAME", filename);
PdfCollectionField description = new PdfCollectionField("Description", PdfCollectionField.TEXT);
description.setOrder(1);
schema.addField("DESCRIPTION", description);
PdfCollectionField modified = new PdfCollectionField("Modified", PdfCollectionField.MODDATE);
modified.setOrder(2);
schema.addField("MODIFIED", modified);
PdfCollectionField size = new PdfCollectionField("Size", PdfCollectionField.SIZE);
size.setOrder(3);
schema.addField("SIZE", size);
collection.setSchema(schema);
writer.setCollection(collection);
// loop through the PDF documents and add each to the portfolio
PdfFileSpecification fs;
PdfCollectionItem item;
int iNum = 0;
for (byte[] pdf : assemblingPdfList) {
fs = PdfFileSpecification.fileEmbedded(writer, null,
String.format("StylesResult_%s.pdf", iNum++), pdf);
fs.addDescription("Styles Result File", false);
item = new PdfCollectionItem(schema);
item.addItem("DESCRIPTION", "Styles Result File");
item.addItem("MODIFIED", new PdfDate() );
fs.addCollectionItem(item);
writer.addFileAttachment(fs);
}
// close document
document.close();
mergedPDFOutput.flush();
mergedPDFOutput.close();
return mergedPDFOutput.toByteArray();
At first, iText would not populate the form fields. We used LiveCycle Designer to change the data binding of most fields from Normal to Global, which enabled iText to populate most of them correctly. The exception were the repeating (think 'table') rows of data; setting the binding to 'Global' caused the first data value to be repeated down the column for each of the data records. Setting the repeating fields' bindings back to 'Normal' seemed to work.
The iText-merged editable PDF portfolios are launched in Internet Explorer 10. If we click 'Open File' to open an individual PDF in Adobe Acrobat XI Pro, all the data is there. However, if we click 'File' / 'Save As' in Acrobat Pro to save to a new PDF file, then open the new file, some or all of the form data has disappeared (In one case, the 'first generation' save left most of the data intact, but repeating subform data was erased. Saving again, creating a 'second generation' save, erased all data.)
My failed solution attempts include: (a) initializing PdfStamper in 'append' mode; (b) Modifying my PdfStamper with 'stamper.setEncryption(false, "", "", PdfWriter.ALLOW_{everything}...)'.
Adobe LiveCycle Server-generated portfolios do not lose data, no matter how many generations of saves are made.
I am trying to add javascript into a pdf using itext and later merge it with another pdf.
But the final merged pdf does not contain the javascript. The javascript is working fine if the pdf is not merged with another pdf.
Merging code :
FileOutputStream sectionR = new FileOutputStream(RESULT);
PdfCopyFields copier = new PdfCopyFields(sectionR);
for (String curInPath : listFile) {
PdfReader reader = new PdfReader(curInPath);
copier.addDocument(reader);
}
copier.close();
I tried to add JS to the resulting merged pdf, but it is not taking it. I guess its not editable.
Below is the code adding JS to pdf which is not merged yet.
FileOutputStream section1Pdf = new FileOutputStream("newPDFSection");
PdfReader readerSection1 = new PdfReader("Existing PDF - Section 1");
PdfStamper stamperSection1 = new PdfStamper(readerSection1,section1Pdf);
stamperSection1.addJavaScript(
"var nameField = this.getField('txtOwnerCity');" + "nameField.setAction('Keystroke'," +"'forceUpperCase()');" +
"" +"function forceUpperCase(){" +
"if(!event.willCommit)event.change = " +
"event.change.toUpperCase();" +
"}");
When I tried adding JS to the resulting merged pdf, it does not allow me saying it is not editable anymore.
This is how I am trying to add
FileOutputStream sectionR = new FileOutputStream(RESULT);
PdfCopyFields copier = new PdfCopyFields(sectionR);
for (String curInPath : listFile) {
PdfReader reader = new PdfReader(curInPath);
copier.addDocument(reader);
}
copier.close();
PdfReader readersectionResult = new PdfReader("result.pdf");
PdfStamper stamper = new PdfStamper(readersectionResult, new FileOutputStream("newResult.pdf"));
stamper.addJavaScript(some JS);
The error I am getting is ' WARNING: Cannot set header. Response already committed.'
I am not sure if I am doing it right above, All I am trying to do is get pdfstamper of resulting pdf to add new JS to it.
When I am trying to edit form filed values, it says not editable anymore.
AcroFields acro= stamper .getAcroFields();
acro.setField("txtOfficerName"+officerChar,officerSO.getFullName());