Sunday, December 4, 2022

#1 2022-11-08 10:03:13 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1518

Add Images to PDF

The script included below adds image files in a selected folder to a PDF. The default image folder and dialog position can be set at the top of the displayDialog handler, and the amount of JPEG compression can be set at the top of the makePDF handler. This script uses Shane's Dialog Toolkit Plus script library, which can be downloaded from:

https://latenightsw.com/freeware/

It should be noted that recent versions of macOS have the native ability to add image files to a PDF. This script might be of use to those who are running older versions of macOS or who prefer batch processing of all image files in a folder.

Applescript:

use framework "AppKit"
use framework "Foundation"
use framework "Quartz"
use scripting additions
use script "Dialog Toolkit Plus" version "1.1.0"

on main()
   set {tiffFormat, dateSort, pdfWithImages, imageFolder} to displayDialog()
   set imageFolder to current application's |NSURL|'s fileURLWithPath:imageFolder
   set pdfFile to getPdfFile(imageFolder, pdfWithImages)
   set imageFiles to getImageFiles(imageFolder, dateSort)
   set fileCount to imageFiles's |count|()
   if fileCount = 0 then errorAlert("No image files were found in the selected folder")
   try
       makePDF(imageFiles, fileCount, pdfFile, tiffFormat)
   on error
       errorAlert("An error occurred while adding an image to the PDF")
   end try
   display notification "Images added to PDF: " & fileCount with title "PDF Created"
end main

on displayDialog()
   set dialogPosition to {} -- insert x and y coordinates if desired
   set defaultImageFolder to POSIX path of (path to home folder) -- change if desired
   set dialogWidth to 430
   set verticalSpace to 8
   set {theButtons, minWidth} to create buttons {"Cancel", "OK"} cancel button 1 default button 2
   set {tiffFormat, theTop, newWidth} to create checkbox "Convert images to TIFF format before adding them to the PDF" bottom verticalSpace max width dialogWidth
   set {dateSort, theTop, newWidth} to create checkbox "Add images to the PDF in order of their creation date" bottom theTop + verticalSpace max width dialogWidth
   set {pdfWithImages, theTop, newWidth} to create checkbox "Save the PDF in folder with images files" bottom theTop + verticalSpace max width dialogWidth
   set {optionsMessaage, theTop} to create label "The PDF will be saved on the desktop; images will be added to the PDF in the order of their file name; and images will be converted to JPEG format before being added to the PDF. These can be changed to:" bottom theTop + verticalSpace max width dialogWidth control size regular size
   set {imageFolder, theTop} to create path control defaultImageFolder bottom (theTop + verticalSpace) control width dialogWidth
   set {pathMessage, theTop} to create label "Choose or drag a folder containing image files to:" bottom theTop + verticalSpace max width dialogWidth control size regular size
   set theControls to {tiffFormat, dateSort, pdfWithImages, optionsMessaage, imageFolder, pathMessage}
   set {buttonName, controlsResults} to display enhanced window "Image to PDF" acc view width dialogWidth acc view height theTop acc view controls theControls initial position dialogPosition buttons theButtons without align cancel button
   if buttonName is "Cancel" then error number -128
   return {item 1, item 2, item 3, item 5} of controlsResults
end displayDialog

on getPdfFile(imageFolder, pdfWithImages)
   if pdfWithImages is false then
       set targetFolder to current application's NSHomeDirectory()
       set targetFolder to current application's |NSURL|'s fileURLWithPath:targetFolder
       set targetFolder to targetFolder's URLByAppendingPathComponent:"Desktop" isDirectory:true
   else
       set targetFolder to imageFolder
   end if
   set sourceFolderName to imageFolder's lastPathComponent()
   set pdfFile to sourceFolderName's stringByAppendingString:" Images.pdf"
   set pdfFile to (targetFolder's URLByAppendingPathComponent:pdfFile isDirectory:false)
   repeat with i from 1 to 100
       set fileExists to (pdfFile's checkResourceIsReachableAndReturnError:(missing value))
       if fileExists as boolean is false then return pdfFile
       set pdfFile to (sourceFolderName's stringByAppendingString:(" Images " & i & ".pdf"))
       set pdfFile to (targetFolder's URLByAppendingPathComponent:pdfFile isDirectory:false)
   end repeat
   errorAlert("The PDF file could not be created")
end getPdfFile

on getImageFiles(theFolder, dateSort)
   set theExtensions to {"jpg", "png", "tiff"}
   set fileManager to current application's NSFileManager's defaultManager()
   set {theResult, isDirectory} to (theFolder's getResourceValue:(reference) forKey:(current application's NSURLIsDirectoryKey) |error|:(missing value))
   if isDirectory as boolean is false then errorAlert("The image folder is not recognized as a folder")
   set folderContents to fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{} options:4 |error|:(missing value)
   set thePredicate to current application's NSPredicate's predicateWithFormat_("pathExtension.lowercaseString IN %@", theExtensions)
   set theFiles to (folderContents's filteredArrayUsingPredicate:thePredicate)
   if dateSort is false then
       set sortDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"path" ascending:true selector:"localizedStandardCompare:"
       return theFiles's sortedArrayUsingDescriptors:{sortDescriptor}
   else
       set filePaths to current application's NSMutableArray's new()
       set theKeys to {current application's NSURLPathKey, current application's NSURLCreationDateKey}
       repeat with anItem in theFiles
           (filePaths's addObject:(anItem's resourceValuesForKeys:theKeys |error|:(missing value)))
       end repeat
       filePaths's sortUsingDescriptors:{current application's NSSortDescriptor's sortDescriptorWithKey:(current application's NSURLCreationDateKey) ascending:true}
       set filePaths to (filePaths's valueForKey:(current application's NSURLPathKey))
       set fileURLs to current application's NSMutableArray's new()
       repeat with anItem in filePaths
           set theURL to (current application's |NSURL|'s fileURLWithPath:anItem)
           (fileURLs's addObject:theURL)
       end repeat
       return fileURLs
   end if
end getImageFiles

on makePDF(theFiles, fileCount, pdfFile, tiffFormat)
   set jpegCompression to 0.9 -- 0.0 is maximum compression and 1.0 is no compression
   set pdfDoc to current application's PDFDocument's new()
   repeat with i from 0 to (fileCount - 1)
       set theFile to (theFiles's objectAtIndex:i)
       set imageRep to (current application's NSBitmapImageRep's imageRepWithContentsOfURL:theFile)
       if tiffFormat as boolean is true then
           set theData to (imageRep's representationUsingType:(current application's NSTIFFFileType) |properties|:{NSTIFFCompression:(current application's NSTIFFCompressionLZW)})
       else
           set theData to (imageRep's representationUsingType:(current application's NSJPEGFileType) |properties|:{NSImageCompressionFactor:jpegCompression})
       end if
       set theImage to (current application's NSImage's alloc()'s initWithData:theData)
       set thePDFPage to (current application's PDFPage's alloc's initWithImage:theImage)
       (pdfDoc's insertPage:thePDFPage atIndex:i)
   end repeat
   pdfDoc's writeToURL:pdfFile
end makePDF

on errorAlert(dialogMessage)
   display alert "An error has occurred" message dialogMessage as critical
   error number -128
end errorAlert

main()

Last edited by peavine (2022-11-13 06:59:33 pm)


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#2 2022-11-14 09:56:22 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1518

Re: Add Images to PDF

Forum members occasionally express their dislike for long scripts, and my script in post 1 certainly fits in that category. The following is an abbreviated version--it lacks any options and has no error correction but might be preferred for its brevity.

Applescript:

use framework "AppKit"
use framework "Foundation"
use framework "Quartz"
use scripting additions

set imageFolder to (choose folder)
set pdfFile to POSIX path of ((path to desktop as text) & "PDF Images.pdf")
tell application "Finder" to set imageFiles to (every file in imageFolder whose name extension is in {"jpg", "png", "tiff"}) as alias list
set imageFiles to current application's NSArray's arrayWithArray:imageFiles
set pdfDoc to current application's PDFDocument's new()
repeat with i from 0 to ((imageFiles's |count|()) - 1)
   set imageRep to (current application's NSBitmapImageRep's imageRepWithContentsOfURL:(imageFiles's objectAtIndex:i))
   set theData to (imageRep's representationUsingType:(current application's NSJPEGFileType) |properties|:{NSImageCompressionFactor:0.9})
   set theImage to (current application's NSImage's alloc()'s initWithData:theData)
   set thePDFPage to (current application's PDFPage's alloc's initWithImage:theImage)
   (pdfDoc's insertPage:thePDFPage atIndex:i)
end repeat
pdfDoc's writeToFile:pdfFile

Last edited by peavine (2022-11-14 03:40:12 pm)


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#3 2022-11-16 08:57:07 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1518

Re: Add Images to PDF

This script differs from those above in two respects. First, it works on image files selected in a Finder window. Second. it uses lossy compression (DCTDecode) with a JPG file and lossless compression (FlateDecode) otherwise. This permits high compression of JPEGs in a PDF without degrading the quality of a PNG or TIFF image in the same PDF.

Applescript:

-- revised 2022.11.19

use framework "AppKit" -- for NSImage
use framework "Foundation"
use framework "Quartz"
use scripting additions

on main()
   set pdfFile to POSIX path of (path to desktop) & "PDF Images.pdf"
   tell application "Finder" to set imageFiles to selection as alias list
   if imageFiles = {} then errorAlert("Finder window or file selection not found")
   try
       makePDF(imageFiles, pdfFile)
   on error
       errorAlert("The PDF could not be created. This often happens when a selected file cannot be read.")
   end try
end main

on makePDF(imageFiles, pdfFile)
   set imageFiles to current application's NSArray's arrayWithArray:imageFiles
   set pdfDoc to current application's PDFDocument's new()
   repeat with i from 0 to ((imageFiles's |count|()) - 1)
       set fileExtension to ((imageFiles's objectAtIndex:i)'s pathExtension())'s lowercaseString()
       set imageRep to (current application's NSBitmapImageRep's imageRepWithContentsOfURL:(imageFiles's objectAtIndex:i))
       if (fileExtension's isEqualToString:"jpg") then
           set theData to (imageRep's representationUsingType:(current application's NSJPEGFileType) |properties|:{NSImageCompressionFactor:0.8})
       else
           set theData to (imageRep's representationUsingType:(current application's NSTIFFFileType) |properties|:{NSTIFFCompression:(current application's NSTIFFCompressionLZW)})
       end if
       set theImage to (current application's NSImage's alloc()'s initWithData:theData)
       set thePDFPage to (current application's PDFPage's alloc's initWithImage:theImage)
       (pdfDoc's insertPage:thePDFPage atIndex:i)
   end repeat
   pdfDoc's writeToFile:pdfFile
end makePDF

on errorAlert(dialogMessage)
   display alert "An error has occurred" message dialogMessage as critical
   error number -128
end errorAlert

main()

Last edited by peavine (2022-11-23 06:48:30 am)


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#4 2022-11-16 04:29:35 pm

Fredrik71
Member
Registered: 2019-10-23
Posts: 1091

Re: Add Images to PDF

When you use POSIX path of (path to desktop)... the class is already text
So you do not need to declare it again

ex.

Applescript:

set pdfFile to POSIX path of ((path to desktop as text) & "PDF Images.pdf")
pdfFile's class --> text

set pdfFile to POSIX path of (path to desktop) & "PDF Images.pdf"
pdfFile's class --> text

Your handler on makePDF(imageFiles, pdfFile) arguments use a mix of ASobjC and Vanilla AS
My advice would be to set the NSArray inside the handler instead and before objectAtIndex:

Last edited by Fredrik71 (2022-11-16 04:41:55 pm)


Node-RED makes it easy to automate IoT

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)