Merge pictures into a PDF

Hello,
My goal would be to merge picture files nested in sub-folders into a PDF file.
I’ve a lot of sub-folders which picture files needs to be merged, so doing it manually or with automator isn’t exactly the way wanna go…

I found 2 articles related to my research, but unfortunately, the first post is outdated, at least for me as I installed my Os fresh over snow leopard… The second posts merges just PDF files, and fails with picture files.
Some suggestion?

https://macscripter.net/viewtopic.php?id=20761
https://macscripter.net/viewtopic.php?id=22558

This should get you started:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
use framework "AppKit" -- for NSImage
use framework "Quartz" -- required for PDF stuff

set inFiles to (choose file of type {"public.image", "com.adobe.pdf"} with prompt "Choose your  files:" with multiple selections allowed)
set destPosixPath to POSIX path of (choose file name default name "Combined.pdf" with prompt "Save new PDF to:")
my combineFiles:inFiles savingToPDF:destPosixPath

on combineFiles:inFiles savingToPDF:destPosixPath
	--  make URL of the first file
	set inNSURL to current application's |NSURL|'s fileURLWithPath:(POSIX path of item 1 of inFiles)
	-- make PDF document from the URL
	if (inNSURL's pathExtension()'s isEqualToString:"pdf") as boolean then
		set theDoc to current application's PDFDocument's alloc()'s initWithURL:inNSURL
	else
		set theDoc to my pdfDocFromImageURL:inNSURL
	end if
	-- loop through the rest
	set oldDocCount to theDoc's pageCount()
	set inFiles to rest of inFiles
	repeat with aFile in inFiles
		--  make URL of the next PDF
		set inNSURL to (current application's |NSURL|'s fileURLWithPath:(POSIX path of aFile))
		-- make PDF document from the URL
		if (inNSURL's pathExtension()'s isEqualToString:"pdf") as boolean then
			set newDoc to (current application's PDFDocument's alloc()'s initWithURL:inNSURL)
		else
			set newDoc to (my pdfDocFromImageURL:inNSURL)
		end if
		-- loop through, moving pages
		set newDocCount to newDoc's pageCount()
		repeat with i from 1 to newDocCount
			-- get page of  PDF
			set thePDFPage to (newDoc's pageAtIndex:(i - 1)) -- zero-based indexes
			-- insert the page into main PDF
			(theDoc's insertPage:thePDFPage atIndex:oldDocCount)
			set oldDocCount to oldDocCount + 1
		end repeat
	end repeat
	set outNSURL to current application's |NSURL|'s fileURLWithPath:destPosixPath
	-- save the main PDF
	(theDoc's writeToURL:outNSURL)
end combineFiles:savingToPDF:

on pdfDocFromImageURL:inNSURL
	set theImage to current application's NSImage's alloc()'s initWithContentsOfURL:inNSURL
	set theSize to theImage's |size|()
	set theRect to {{0, 0}, theSize}
	set theImageView to current application's NSImageView's alloc()'s initWithFrame:theRect
	theImageView's setImage:theImage
	set theData to theImageView's dataWithPDFInsideRect:theRect
	return current application's PDFDocument's alloc()'s initWithData:theData
end pdfDocFromImageURL:

Great Shane,
Works exactly as expected.
I tried to modify your previous script by myself but that kind of coding isn’t yet in my reach. Still I read your code with interest.
Doing the same with Automator requires a lot of fiddling, some 3rd party actions and then the results aren’t optimal.
Thanks for sharing AppleScriptObjC with us all! (PDF is always useful) :cool:

Shane’s suggestion is excellent and clearly the script to use.

I have no knowledge of scripting additions and thought I would try to do this with basic Applescript using utilities included with macOS. I’ve copied my script below.

A significant flaw of my script is that it uses join.py to merge PDF files, and it is very slow. Substituting another utility–such as PDFtk Server, cpdf, or Ghostscript–is easily done and would eliminate this flaw (although Shane’s script is still preferred). My script has been tested on Sierra only.


--Set variable to temp folder.
set tempFolder to "/Users/bob/Temp/"

--Prompt for picture folder.
choose folder default location (path to home folder)
set pictureFolder to quoted form of (text 1 thru -2 of POSIX path of result)

--Set variable to picture files.
try
	do shell script "find " & pictureFolder & " -type f  -iname *.png -or -iname *.jpg"
	set pictureFiles to paragraphs of result
on error errorMessage
	display dialog "The Find utility reported an error while searching for picture files." buttons {"View Error Message", "OK"} ¬
		cancel button 2 default button 2 with title "Picture Merge" with icon stop
	display dialog errorMessage buttons {"OK"} ¬
		cancel button 1 default button 1 with title "Picture Merge"
end try

--Notify if no or a large number of picture files in the selected Folder.
set pictureCount to (count pictureFiles)
if pictureCount = 0 then
	display dialog "No picture files in selected folder." buttons {"OK"} ¬
		cancel button 1 default button 1 with title "Picture Merge" with icon stop
else if pictureCount > 200 then
	display dialog (pictureCount as text) & " picture files in selected folder." buttons {"Cancel", "Continue"} ¬
		cancel button 1 default button 1 with title "Picture Merge" with icon stop
end if

--Prompt for PDF file name.
choose file name with prompt "" default name "Merged Picture Files.pdf" default location (path to desktop folder)
set pdfFile to result as text

--Set variable to PDF file name.
if pdfFile does not end with ".pdf" then set pdfFile to pdfFile & ".pdf"
set pdfFile to quoted form of POSIX path of pdfFile

--Convert picture files to PDF format.
set fileNumber to 0
repeat with aFile in pictureFiles
	set tempFile to "Picture_merge_temp_" & (text -4 thru -1 of ("000" & fileNumber)) & ".pdf"
	do shell script "sips --setProperty format pdf " & (quoted form of aFile) & " --out " & tempFolder & tempFile
	set fileNumber to fileNumber + 1
end repeat

--Merge temporary files.
set pdfUtility to "'/System/Library/Automator/Combine PDF Pages.action/Contents/Resources/join.py'"
do shell script pdfUtility & " -o " & pdfFile & " " & tempFolder & "*.pdf"

--Delete temporary files.
tell application "System Events" to ¬
	delete (every file in folder tempFolder whose name begins with "Picture_merge_temp_")