I'm trying to write a powershell script that will loop through a csv file looking for Tiff & PDF files using ItextSharp dll. The desired end result is every image and page of a pdf needs to be in one large pdf.
My thoughts are to create two functions to accomplish this. 1 for images and the other for PDF's. The image function is working properly, but the pdf is throwing a error: Exception calling ".ctor" with "1" argument(s): " not found as file or resource."
Any thoughts on fixing add-pdf function?
Current script is below.
[System.Reflection.Assembly]::LoadFrom("C:\Temp\itextsharp`enter code here`\itextsharp.dll")
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$doc = New-Object itextsharp.text.document
#output PDF with all combined tiff and pdfs
$stream = [IO.File]::OpenWrite("C:\temp\itext\test.pdf")
$writer = [itextsharp.text.pdf.PdfWriter]::GetInstance($doc, $stream)
#$pdfCopy =New-Object iTextSharp.text.pdf.PdfCopy($doc, $stream)
$doc.Open()
$doc.SetMargins(0, 0, 0, 0)
#get the size of image and change pdf
function add-picture( $file2use){
$pic = New-Object System.Drawing.Bitmap($file2use )
$rect = New-Object iTextSharp.text.Rectangle($pic.Width, $pic.Height)
## Set the next page size to those dimensions and add a new page
$doc.SetPageSize( $rect )
$doc.NewPage()
#add image jpg
$img = [iTextSharp.text.Image]::GetInstance($file2use )
$doc.Add($img);
$pic.dispose()
}
function add-pdf( $newPDF){
$pdf2Merge = [System.IO.Path]::Combine("",$newPDF)
$pdfCopy = New-Object iTextSharp.text.pdf.PdfCopy($doc, $stream);
$reader = New-Object iTextSharp.text.pdf.PdfReader($pdf2Merge);
$pageCount = $reader.NumberOfPages;
for ($i = 1; $i -lt $pageCount ; $i++) {
$pdfCopy.AddPage(
$pdfCopy.GetImportedPage($reader, $i ))
# ^^^^^
# your page number here
}
#$pdfCopy.FreeReader($reader);
}
add-picture -file2use "C:\Temp\itext\3-26-04 (1).JPG"
add-picture -file2use "C:\Temp\itext\CCITT_1.TIF"
add-picture -file2use "C:\Temp\itext\CCITT_2.TIF"
add-pdf -file2use "C:\Temp\itext\test2.pdf"
## Cleanup
#$doc.Close()
$stream.Close()
I'm not too good within PowerShell but it looks like you are so you should be able to adapt this C# code very easily. The code in this post is adapted from some code I wrote earlier here.
First off, I really don't recommend keeping global iText abstraction objects around and binding various things to them over and over, that's just looking for trouble.
Instead, for images I'd recommend a simple function that takes a supplied image file and returns a byte array representing that image added to a PDF. Instead of a byte array you could also write the PDF to a temporary file and return that path instead.
private static byte[] ImageToPdf(string imagePath) {
//Get the size of the current image
iTextSharp.text.Rectangle pageSize = null;
using (var srcImage = new Bitmap(imagePath)) {
pageSize = new iTextSharp.text.Rectangle(0, 0, srcImage.Width, srcImage.Height);
}
//Simple image to PDF
using (var m = new MemoryStream()) {
using (var d = new Document(pageSize, 0, 0, 0, 0)) {
using (var w = PdfWriter.GetInstance(d, m)) {
d.Open();
d.Add(iTextSharp.text.Image.GetInstance(imagePath));
d.Close();
}
}
//Grab the bytes before closing out the stream
return m.ToArray();
}
}
Then just create a new Document
and bind a PdfSmartCopy
object to it. You can then enumerate your files, if you have an image, convert it to a PDF first, then just use the PdfSmartCopy
method AddDocument()
to add that entire document to the final output.
The code below just loop through a single folder, grabs images first and then PDFs but you should be able to adapt it pretty easily, hopefully.
//Folder that contains our sample files
var sourceFolder = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "MergeTest");
//Final file that we're going to emit
var finalFile = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.pdf");
//Create our final file, standard iText setup here
using (var fs = new FileStream(finalFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (var doc = new Document()) {
//Use a smart object copies to merge things
using (var copy = new PdfSmartCopy(doc, fs)) {
//Open the document for writing
doc.Open();
//Loop through each image in our test folder
foreach (var img in System.IO.Directory.EnumerateFiles(sourceFolder, "*.jpg")) {
//Convert the image to a byte array
var imageAsPdf = ImageToPdf(img);
//Bind a reader to that PDF
using( var r = new PdfReader(imageAsPdf) ){
//Add that entire document to our final PDF
copy.AddDocument(r);
}
}
//Loop through each PDF in our test folder
foreach (var pdf in System.IO.Directory.EnumerateFiles(sourceFolder, "*.pdf")) {
//Bind a reader to that PDF
using (var r = new PdfReader(pdf)) {
//Add that entire document to our final PDF
copy.AddDocument(r);
}
}
doc.Open();
}
}
}