Is it possible to merge multiple pdf files into a single pdf without page breaks?
For example - Merging 1.pdf (containing 2 pages, but the content spread only on 1 and a half page) and 2.pdf (containing 3 pages). The merged document should be such that as soon as the content of the first pdf ends, the content of the second pdf should begin. It should not start from the next page.
The current code that I am using is -
File mergedDoc = new File("MergedResponse.pdf");
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(mergedDoc));
Document document = new Document(pdfDoc);
Map<Integer, PdfDocument> filesToMerge = new TreeMap<Integer, PdfDocument>();
//String[] files - contains the location and name of files to be merged
for (int i = 0; i < files.length; i++) {
filesToMerge.put(i, new PdfDocument(new PdfReader(files[i])));
}
for (Map.Entry<Integer, PdfDocument> entry : filesToMerge.entrySet()) {
int n = entry.getValue().getNumberOfPages();
for (int i = 1; i <= n; i++) {
entry.getValue().copyPagesTo(i, i, pdfDoc);
}
}
I also tried merging using the below code -
File mergedDoc = new File("MergedResponse.pdf");
PdfDocument pdf = new PdfDocument(new PdfWriter(mergedDoc));
PdfMerger merger = new PdfMerger(pdf);
PdfDocument firstSourcePdf = new PdfDocument(new PdfReader(files[0]));
merger.merge(firstSourcePdf, 1, firstSourcePdf.getNumberOfPages());
//Add pages from the second pdf document
PdfDocument secondSourcePdf = new PdfDocument(new PdfReader(files[1]));
merger.merge(secondSourcePdf, 1, secondSourcePdf.getNumberOfPages());
firstSourcePdf.close();
secondSourcePdf.close();
But both the codes generate the merge pdf where the second document starts from a new page and not just follows the end of the first document.
Any help is appreciated.
Related
I'm working on a rather complex solution that takes an html-like input and converts it to a pdf. One of the many items that I'm trying to solve for is adding barcodes (all types, 3 of 9, PDF417, and qr code) to the footer of documents.
A couple details that give me pause on how to implement:
Bar code will contain current page number
Bar code will contain total page count
Bar code will be inside other itext elements (like a table cell or paragraph) and (in the final solution) needs to be parsed out ahead of time
Knowing those details, I'm struggling a bit on how to combine barcodes with something like the page x of y strategy of using a template to replace page count after rendering all the content.
I assume that each bar code will need it's own template because of the page count, and keep track of the templates until all the content is rendered and then update each individual template with the appropriate bar code. But because the footer is parsed out ahead of time, I need a template that represents a bar code so that the footer will have the correct height and content can be adjusted appropriately.
I believe that each of these pieces need to be handled in the event handler for end of page, is that a correct assessment?
UPD Edited to include code sample. I pulled out quite a bit of the other stuff I was trying to accomplish from this example. As for the parsed ahead of time, instead of going over a loop from 1 to 20 and creating random elements, some other process creates all the elements that need to be present on the document and will pass in that list of elements to the renderer. That does include the footer content as well. In this case I'm creating the footer table in the constructor of the HeaderHandler as that is close to the same concept. The reason I bring this up is that I won't be able to create the table in the HandleEvent of the handler like in most examples I have seen about tables in footers. Hope that makes sense.
void Main()
{
PdfDocument pdf = new PdfDocument(new PdfWriter(Dest));
PageSize pageSize = PageSize.A4;
Document doc = new Document(pdf, pageSize, true);
HeaderHandler hh = new HeaderHandler(doc);
...
some other object generation
...
// create random paragraphs to fill up multiple pages in the final solution this would have already happened.
for (var i = 0; i < 20; i++)
AddItemToList(elementList, i, objects);
// add random elements back to the document
foreach (var e in elementList)
{
... add each item just added to elementList to the document ...
}
renderer.Flush();
hh.UpdateTotal(pdf);
// I think I need to update all the barcodes and print them out here so that page count part of the barcode can be written
doc.Close();
}
class HeaderHandler : IEventHandler
{
Table Footer;
Document Doc;
public Margin First;
public Margin Middle;
public Margin Last;
public Dictionary<int, Margin> PageMargins { get; set; }
public float HeaderHeight { get; }
public float FooterHeight { get; }
PdfFormXObject PgCount;
Text PageNumber;
Dictionary<string, PdfFormXObject> BarcodeImages;
public HeaderHandler(Document doc)
{
Doc = doc;
Footer = new Table(new float[] { 4, 2, 4}).SetAutoLayout();
PageMargins = new Dictionary<int, Margin>();
BarcodeImages = new Dictionary<string, PdfFormXObject>();
var pageSize = Doc.GetPdfDocument().GetDefaultPageSize();
var width = pageSize.GetRight() - pageSize.GetLeft() - Doc.GetLeftMargin() - Doc.GetRightMargin();
// page total
PgCount = new PdfFormXObject(new Rectangle(0,0, 13, 13));
Footer.AddCell(new Cell().Add(new Paragraph("info 1")));
PageNumber = new Text("{page}");
var cell = new Cell().Add(new Paragraph().Add(PageNumber).Add(" of ").Add(new Image(PgCount)).Add(" pages").SetTextAlignment(TextAlignment.CENTER));
Footer.AddCell(cell);
Footer.AddCell(new Cell().Add(new Paragraph("info 2")));
Footer.AddCell("footer 1");
Footer.AddCell("footer 2");
// I think I need to add a template here for the barcode as a placeholder so that when the renderersubtree is ran it provides space for the barcode
Footer.AddCell(new Cell().Add(new Paragraph("{barcode} {qr code - {page} | {pagect} | doc name}")));
TableRenderer fRenderer = (TableRenderer)Footer.CreateRendererSubTree();
using (var s = new MemoryStream())
{
fRenderer.SetParent(new Document(new PdfDocument(new PdfWriter(s))).GetRenderer());
FooterHeight = fRenderer.Layout(new LayoutContext(new LayoutArea(0, PageSize.A4))).GetOccupiedArea().GetBBox().GetHeight();
}
}
public void UpdateTotal(PdfDocument pdf) {
Canvas canvas = new Canvas(PgCount, pdf);
canvas.ShowTextAligned(pdf.GetNumberOfPages().ToString(), 0, -3, TextAlignment.LEFT);
}
//draw footer and header tables
public void HandleEvent(Event e)
{
PdfDocumentEvent docEvent = e as PdfDocumentEvent;
if (docEvent == null)
return;
PdfDocument pdf = docEvent.GetDocument();
PdfPage page = docEvent.GetPage();
PdfCanvas pdfCanvas = new PdfCanvas(page.GetLastContentStream(), page.GetResources(), pdf);
int pageNum = pdf.GetPageNumber(page);
var pageSize = Doc.GetPdfDocument().GetDefaultPageSize();
Margin activeMargin = new Margin();
if (PageMargins.ContainsKey(pageNum))
activeMargin = PageMargins[pageNum];
var width = pageSize.GetRight() - pageSize.GetLeft() - activeMargin.Left - activeMargin.Right;
Header.SetWidth(width);
Footer.SetWidth(width);
var pageReferences = new List<TextRenderer>();
// update page number text so it can be written to in the footer
PageNumber.SetText(pageNum.ToString());
// draw the footer
rect = new Rectangle(pdf.GetDefaultPageSize().GetX() + activeMargin.Left, activeMargin.Bottom - GetFooterHeight(), 100, GetFooterHeight());
canvas = new Canvas(pdfCanvas, pdf, rect);
// I think it's here that I need to be able to add a barcode placeholder to something that can be called
canvas.Add(Footer);
}
public float GetFooterHeight()
{
return FooterHeight;
}
}
I have been successful in creating image from PDF using iTextSharp. It creates images equal to number of pages in PDF but generated images does not preview in any image viewer software. It says image is corrupted. Below is the code I have created.
try
{
PdfReader reader = null;
int currentPage = 1;
int pageCount = 0;
string destinationFolderPath = string.Format(#"{0}PageImages\{1}", BaseDataPath, Convert.ToString(documentId));
if (!Directory.Exists(destinationFolderPath))
{
Directory.CreateDirectory(destinationFolderPath);
}
reader = new PdfReader(filePath);
reader.RemoveUnusedObjects();
pageCount = reader.NumberOfPages;
string ext = ".png";
for (int i = 1; i <= pageCount; i++)
{
PdfReader reader1 = new PdfReader(filePath);
string destinationFilePath = string.Format(#"{0}/{1}{2}", destinationFolderPath, Convert.ToString(i), ext);
reader1.RemoveUnusedObjects();
Document doc = new Document(reader1.GetPageSizeWithRotation(currentPage));
PdfCopy pdfCpy = new PdfCopy(doc, new FileStream(destinationFilePath, FileMode.Create));
doc.Open();
for (int j = 1; j <= 1; j++)
{
PdfImportedPage page = pdfCpy.GetImportedPage(reader1, currentPage);
//pdfCpy.SetFullCompression();
pdfCpy.AddPage(page);
currentPage += 1;
}
doc.Close();
pdfCpy.Close();
reader1.Close();
reader.Close();
}
}
catch (Exception ex)
{
throw ex;
}
Could someone please suggest what is wrong here?
Thanks
You are creating a PDF file using PdfCopy, but you are storing that PDF as if you were creating a PNG file:
string ext = ".png";
string destinationFilePath =
string.Format(#"{0}/{1}{2}",
destinationFolderPath, Convert.ToString(i), ext);
PdfCopy pdfCpy = new PdfCopy(doc,
new FileStream(destinationFilePath, FileMode.Create));
You can't open a .png file in a PDF viewer. Your operating system will try to open the file you're creating as if it were an image, but the bytes of that "image" will be PDF bytes and your image viewer won't recognize it.
Change this line:
string ext = ".png";
To this:
string ext = ".pdf";
And you'll be able to open your file in a PDF viewer.
By the way: your code is awkward. For instance. I don't understand why you'd create a look to execute something only once:
for (int j = 1; j <= 1; j++)
Also: if it's your intention to convert PDF pages to PNG, reconsider. iTextSharp doesn't convert PDF to images.
How can I concatenate disparate chunks and add them to a paragraph, the paragraph to a cell, then the cell to a table using iTextSharp (in generating a PDF file)?
I am able to get to a certain "place" in my PDF file generation, so that it looks like so (the right side of the page is blank, as it should be):
This is the code I'm using for that:
using (var ms = new MemoryStream())
{
using (var doc = new Document(PageSize.A4, 50, 50, 25, 25))
{
//Create a writer that's bound to our PDF abstraction and our stream
using (var writer = PdfWriter.GetInstance(doc, ms))
{
//Open the document for writing
doc.Open();
var courierBold11Font = FontFactory.GetFont(FontFactory.COURIER_BOLD, 11, BaseColor.BLACK);
var docTitle = new Paragraph("Mark Twain", courierBold11Font);
doc.Add(docTitle);
var timesRoman9Font = FontFactory.GetFont("Times Roman", 9, BaseColor.BLACK);
var subTitle = new Paragraph("Roughing It", timesRoman9Font);
doc.Add(subTitle);
var courier9RedFont = FontFactory.GetFont("Courier", 9, BaseColor.RED);
var importantNotice = new Paragraph("'All down but nine; set 'em up on the other alley, pard' - Scotty Briggs", courier9RedFont);
importantNotice.Leading = 0;
importantNotice.MultipliedLeading = 0.9F; // reduce the width between lines in the paragraph with these two settings
PdfPTable table = new PdfPTable(1);
PdfPCell cellImportantNote = new PdfPCell(importantNotice);
cellImportantNote.BorderWidth = PdfPCell.NO_BORDER;
table.WidthPercentage = 50;
table.HorizontalAlignment = Element.ALIGN_LEFT;
table.AddCell(cellImportantNote);
doc.Add(table);
doc.Close();
}
var bytes = ms.ToArray();
String PDFTestOutputFileName = String.Format("iTextSharp_{0}.pdf", DateTime.Now.ToShortTimeString());
PDFTestOutputFileName = PDFTestOutputFileName.Replace(":", "_");
var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), PDFTestOutputFileName);
File.WriteAllBytes(testFile, bytes);
MessageBox.Show(String.Format("{0} written", PDFTestOutputFileName));
}
}
However, I need to break up the red text so that part of it is bolded, parts of it are anchor tags/hrefs, etc.
I thought I could do it this way:
var courier9RedBoldFont = FontFactory.GetFont(FontFactory.COURIER_BOLD, 9, BaseColor.RED);
// Build up chunkified version of "important notice"
Chunk boldpart = new Chunk("All down but nine - set 'em up on the other alley, pard", courier9RedBoldFont);
Chunk attribution = new Chunk("Scotty Briggs", courier9RedFont);
PdfPTable tbl = new PdfPTable(1);
tbl.WidthPercentage = 50;
tbl.HorizontalAlignment = Element.ALIGN_LEFT;
var par = new Paragraph();
par.Chunks.Add(boldpart);
par.Chunks.Add(attribution );
PdfPCell chunky = new PdfPCell(par);
chunky.BorderWidth = PdfPCell.NO_BORDER;
tbl.AddCell(chunky);
doc.Add(tbl);
...but that's not adding anything at all to the PDF file, but why not? Doesn't a cell take a paragraph, and cannot a paragraph be comprised of Chunks?
Instead of para.Chunks.Add() just use par.Add(); The Chunks that are returned from Paragraph actually come from the base class Phrase. If you look at the code for that property you'll see that the collection returned is actually a temporary collection created on the fly so it is effectively read-only.
I'm adding a list of images from a directory using an arraylist.When images are added,my ScrollPane gets crowded.How can I keep spacings between images ?
here's my code
File file = new File("D:\\SERVER\\Server Content\\Apps\\icons");
File[] filelist1 = file.listFiles();
ArrayList<File> filelist2 = new ArrayList<>();
hb = new HBox();
for (File file1 : filelist1) {
filelist2.add(file1);
}
System.out.println(filelist2.size());
gridpane.setPadding(new Insets(50,50,50,50));
gridpane.setHgap(20);
gridpane.setVgap(20);
int imageCol = 0;
int imageRow = 0;
for (int i = 0; i < filelist2.size(); i++) {
System.out.println(filelist2.get(i).getName());
image = new Image(filelist2.get(i).toURI().toString());
pic = new ImageView();
pic.setFitWidth(130);
pic.setFitHeight(130);
pic.setImage(image);
hb.getChildren().add(pic);
gridpane.add(pic, imageCol, imageRow );
imageCol++;
// To check if all the 4 images of a row are completed
if(imageCol > 2){
// Reset Column
imageCol=0;
// Next Row
imageRow++;
}
Try using HBox and VBox.
Basically, they are like little containers where you store your stuff and you can add gaps into it!
HBox ab = new HBox(10); <--The 10 is adding space (Answer to your question)
If you want to add stuff into HBox, simply write
ab.getChildren().addAll(your content here);
If I go to Apache POI XSLF there should be samples for both OLE2 and OpenXML specs, but there are only the OLE2 based Horrible Slide Layout Format examples.
Could please anybody help me out with XML Slide Layout Format example ? The API is quite different.
It is not like with spreadsheet where one just change the implementation of HSSFWorkbook to XSSFWorkbook.
How would this look like with XSLF implementation ? POI apparently can't create a document from scratch, so we need an existing empty dummy document, right ?
//table data
String[][] data = {
{"INPUT FILE", "NUMBER OF RECORDS"},
{"Item File", "11,559"},
{"Vendor File", "300"},
{"Purchase History File", "10,000"},
{"Total # of requisitions", "10,200,038"}
};
SlideShow ppt = new SlideShow();
Slide slide = ppt.createSlide();
//create a table of 5 rows and 2 columns
Table table = new Table(5, 2);
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
TableCell cell = table.getCell(i, j);
cell.setText(data[i][j]);
RichTextRun rt = cell.getTextRun().getRichTextRuns()[0];
rt.setFontName("Arial");
rt.setFontSize(10);
cell.setVerticalAlignment(TextBox.AnchorMiddle);
cell.setHorizontalAlignment(TextBox.AlignCenter);
}
}
//set table borders
Line border = table.createBorder();
border.setLineColor(Color.black);
border.setLineWidth(1.0);
table.setAllBorders(border);
//set width of the 1st column
table.setColumnWidth(0, 300);
//set width of the 2nd column
table.setColumnWidth(1, 150);
slide.addShape(table);
table.moveTo(100, 100);
FileOutputStream out = new FileOutputStream(file);
ppt.write(out);
out.close();
It is not implemented yet, org.apache.poi version 3.8-beta3, when it will be implemented is very unknown to me.
XMLSlideShow.java
public MasterSheet createMasterSheet() throws IOException {
throw new IllegalStateException("Not implemented yet!");
}
public Slide createSlide() throws IOException {
throw new IllegalStateException("Not implemented yet!");
}