Method to merge PDFs

Is there an AppleScriptObjC method to merge PDFs?
I’m using a Python shell script for a couple of years now, but I would like to modernize it.

And subsequently, (I love this old school word in french, subséquemment) how to get the PDF files actually selected in the Finder?

Thanks.

Found this post (from a certain Shane Stanley): http://macscripter.net/viewtopic.php?pid=181312#p181312

Its’s right what I am looking for, except one thing:
It would be great if the script could import image files as well as pdf pages.
Is it possible with PDFKit?

:wink:

You can convert an image to a PDF easily enough:

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

set thePath to POSIX path of (choose file of type {"public.image"} with prompt "Chosse your image files:")
set thePath to current application's NSString's stringWithString:thePath
set newPath to thePath's stringByDeletingPathExtension()'s stringByAppendingPathExtension:"pdf"
set theImage to current application's NSImage's alloc()'s initWithContentsOfFile:thePath
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 thePDFData to theImageView's dataWithPDFInsideRect:theRect
set {theResult, theError} to thePDFData's writeToFile:newPath options:0 |error|:(reference)

So the original script could be rewritten to something like this:

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:")
its combineFiles:inFiles savingTo:destPosixPath

on combineFiles:inFiles savingTo: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 old PDF
			set thePDFPage to (newDoc's pageAtIndex:(i - 1)) -- zero-based indexes
			-- insert the page
			(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 new PDF
	(theDoc's writeToURL:outNSURL)
end combineFiles:savingTo:

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:

Thanks Shane. You’re awesome!

Aside from that, AppleScriptObjC is really discouraging for those who are not developers.
After more than 2 hours of search, I haven’t found any clue on how to filter the Finder’s selection by file type.
I’d like to use UTI spec, something like: files of selection whose file type is “pulic.image”.

The Finder has a file type property but it always returns missing value.
So I’m stuck with info for from Scripting Additions that returns a too much precise UTI like “public.jpeg”.

Anyway, your script runs like a charm and (only with your help) I’m able to do what I need.
Thanks again.

How about using the ‘Kind’ property instead?

@sphil

Yes, I could. But there’s no benefit.
Kind, name extension, end of name or even file type of info for force us to deal with a list of different values where the UTI “public.image” englobes every type of image.

edit:
…let me think…
In my remembers the kind of an image always ends with the word 'image".
Maybe if we can get the kind as text…
It deserves a try!

:wink:

Does this help?

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

tell application id "com.apple.finder" -- Finder.app
	set theFiles to selection as alias list
end tell
set theList to {}
set theWorkspace to current application's NSWorkspace's sharedWorkspace()
repeat with aFile in theFiles
	set theURL to (current application's |NSURL|'s fileURLWithPath:(POSIX path of aFile))
	set {theResult, theUTI} to (theURL's getResourceValue:(reference) forKey:(current application's NSURLTypeIdentifierKey) |error|:(missing value))
	if (theWorkspace's |type|:theUTI conformsToType:"public.image") as boolean then
		set end of theList to aFile as item
	end if
end repeat
return theList

Of course it helps!

I made some changes and plan to put the script in a library.
I could then have the choice to pass one “global” UTI like “public.image” or be more precise and restrict to “public.tiff” and “com.adobe.psd”.

-- crée la liste des fichiers compatibles
set sourceList to {}
set theTypes to {"public.image", "com.adobe.pdf"}
set theWorkspace to current application's NSWorkspace's sharedWorkspace()
repeat with aFile in finderSel
	set theURL to (current application's |NSURL|'s fileURLWithPath:(POSIX path of aFile))
	set {theResult, theUTI} to (theURL's getResourceValue:(reference) forKey:(current application's NSURLTypeIdentifierKey) |error|:(missing value))
	repeat with atype in theTypes
		if (theWorkspace's |type|:theUTI conformsToType:atype) as boolean then set end of sourceList to aFile as text
	end repeat
end repeat

Thank you again!
:wink:

Hello

Am’I doing something wrong ?
In every thread of this list, when I enter it I’m said that I didn’t login although I did that for the first thread I entered.
Having to login so often is a bit annoying.

Yvan KOENIG running El Capitan 10.11.6 in French (VALLAURIS, France) lundi 12 septembre 2016 17:47:14