Image Events Resize

Preview can scale without proportion if you want to use ui scripting.

That all makes sense. Have to look into scripting Preview.
Odd that Image Events lacks that ability.

Thanks a bunch!

Carl

It looks like you can do it with NSImage also from Cocoa-AppleScript.

And possibly with “sips” in shell script.

So far sips looks the most promising. Having a hard time understanding how to make it resize a file
in one directory and save it with a new name in another directory.

Thanks,

Carl

Yes, although it’s a bit more complex than cropping. You basically make a new bitmap of the required size (using one of the longest Cocoa methods there is), and draw from the original bitmap into it. This is untested, but should work:

script scalePic
	set {thisFile, exportFile, theWidth, theHeight} to current application's NSApp's passedValue() as list
	set theImage to current application's NSImage's alloc()'s initWithContentsOfFile_(thisFile)
	set {width:x1, height:y1} to theImage's |size|() -- get size
	-- make new bitmap rep 
	set newRep to current application's NSBitmapImageRep's alloc()'s initWithBitmapDataPlanes_pixelsWide_pixelsHigh_bitsPerSample_samplesPerPixel_hasAlpha_isPlanar_colorSpaceName_bitmapFormat_bytesPerRow_bitsPerPixel_(missing value, theWidth, theHeight, 8, 4, true, false, current application's NSCalibratedRGBColorSpace, current application's NSAlphaFirstBitmapFormat, 0, 32)
	current application's NSGraphicsContext's saveGraphicsState() -- save graphics context state
	current application's NSGraphicsContext's setCurrentContext_(current application's NSGraphicsContext's graphicsContextWithBitmapImageRep_(newRep)) -- set current graphics context to new image rep
	theImage's drawInRect_fromRect_operation_fraction_({origin:{x:0, y:0}, |size|:{width:theWidth, height:theHeight}}, current application's NSZeroRect, current application's NSCompositeSourceOver, 1.0) -- draw from old rep into graphics context
	current application's NSGraphicsContext's restoreGraphicsState() -- restore graphics state
	set theData to newRep's representationUsingType_properties_(current application's NSJPEGFileType, {NSImageCompressionFactor:0.9})
	theData's writeToFile_atomically_(exportFile, true)
end script

set thisFile to POSIX path of "Macintosh HD:Users:TL:desktop:Ski Images:whitefishT.jpg"
set exportFile to POSIX path of "Macintosh HD:Users:TL:desktop:Ski Images:whitefish.jpg"
set theWidth to 460
set theHeight to 300
tell application "ASObjC Runner" to run the script {scalePic} passing {thisFile, exportFile, theWidth, theHeight}

Hi Shane,

I didn’t understand what the representation is about, so I just resized the image which seems to work. Don’t know if something is wrong with this.

script resizePic
	set {thisFile, exportFile} to current application's NSApp's passedValue() as list
	set theImage to current application's NSImage's alloc()'s initWithContentsOfFile_(thisFile)
	set newSize to {width:460, height:300}
	theImage's setSize_(newSize)
	set theSize to (theImage's |size|()) as record
	set theHeight to height of theSize
	set theWidth to width of theSize
	set newRect to {{x:0, y:0}, {width:theWidth, height:theHeight}}
	theImage's lockFocus()
	set theRep to current application's NSBitmapImageRep's alloc()'s initWithFocusedViewRect_(newRect)
	theImage's unlockFocus()
	set theData to theRep's representationUsingType_properties_(current application's NSJPEGFileType, {NSImageCompressionFactor:0.9})
	theData's writeToFile_atomically_(exportFile, true)
end script

set thisFile to POSIX path of (choose file)
set exportFile to POSIX path of (choose file name)
tell application "ASObjC Runner" to run the script {resizePic} passing {thisFile, exportFile}

Hope it’s not wasting memory or something.

No, that’s fine. In fact the method I posted is overkill – but you’d use it if, say, you wanted to resize and crop at the same time. (In which case you’d use the rect you want to capture instead of NSZeroRect.)

I think I see it. In my script you can’t crop first then scale.

Thanks,
kel

I believe that will work perfectly. Problem I have is turning up a version of ASObjC Runner that will run in
10.5.8

Many thanks,

Carl

Alas, AppleScriptObjC was introduced in 10.6 – it’s not going to work with anything earlier.

Now I really must get upgraded :slight_smile:

thanks,

Carl

That’s right. The other version is essentially saying take this rectangular part of the original and draw it in another rectangle on the new bitmap, squishing it size and shape. You can use the same technique to blend images, using different compositing operations.

This seems to work, assuming both directories already exist:

property targetW : "460"
property targetH : "300"

set fs to "/Library/Application Support/Perceptive Automation/Images/Sonos/Living Room_art.jpg"
set pngFile to "/Library/Application Support/Perceptive Automation/Indigo 6/IndigoWebServer/images/controls/variables/photo+sonos.png"

do shell script ("sips --setProperty format png --resampleHeightWidth " & targetH & space & targetW & space & quoted form of fs & " --out " & quoted form of pngFile)

Hi Nigel,

Great script. I was a little mixed up at first thinking that the file specification (fs) was the file that is being written to. You were just quoting the original file references.

kel

Hello.

I found This blogpost using Image Magick for resizing and sharpening images. I haven’t come around to use it yet, but here it is in case anybody is interested. You’ll have to install ImageMagick, from Macports, or elsewhere, as Image Magick isn’t included in OS X.

Twelve years later, none of these scripts are working for me and I have hundreds of images to resize.

Basically I want to scale proportionately, any suggestions?

sips is still supposed to work. It definitely works on Sequoia.

This is a script where you specify the larger value of width and height of the image and it will be resized preserving the aspect ratio. The script adds the size information to the file name of the resized image.

use AppleScript version "2.5"
use framework "Foundation"
use scripting additions

property targetWH : "480"

set theImagePath to POSIX path of (choose file of type "public.image")
set theURL to current application's NSURL's fileURLWithPath:theImagePath
set fileExtension to theURL's pathExtension() as text
set fileName to theURL's lastPathComponent() as text
set parentFolder to POSIX path of (theURL's URLByDeletingLastPathComponent() as text)
set destinationPath to parentFolder & text 1 thru -((count fileExtension) + 2) of fileName & "_" & targetWH & "." & fileExtension
do shell script "sips -Z " & targetWH & space & quoted form of theImagePath & " --out " & quoted form of destinationPath
1 Like

If you’re dealing with files whose dimensions may fall below the destination size…

do shell script "sips -z " & targetWH & space & targetWH & space & quoted form of theImagePath & " --out " & quoted form of destinationPath

Is there an issue with image events? It strikes me as odd to call out to the shell for something that applescript provides natively.

I modified this script slightly. Basically, specify your source and destination folders. It will get all the matching files in the sources and save the scaled copies with a modified name to a destination folder. It should be easy enough to change those factors depending on the required workflow.

Important: As it can grab files from multiple folders, there may be name conflicts when saving. I’ve set it to skip any image that has a name of an already scaled image to prevent any overwriting.

As to the scaling… as written it takes the longest dimension of the image and scales that to 960 pixels. The opposing dimension will scale accordingly. Adjust as required.

use scripting additions

-- set up default location for 'choose folder' command
set defLoc to (path to pictures folder) -- customize as required

tell application "Finder"
	-- specify destination folder, create as necessary
	try
		set repository to ((path to desktop as text) & "repository:") as alias -- destination
	on error
		set repository to (make new folder at (path to desktop) with properties {name:"repository"}) as alias
	end try
	
	-- specify source folders
	set sourceFolders to (choose folder default location defLoc with prompt "pick some already" with multiple selections allowed) as alias list
	-- set depot to a reference to selection as alias -- finder selection as alternate approach
end tell

-- get jpegs of source folder
tell application "System Events"
	-- set sourceList to files of depot whose type identifier is "public.jpeg"
	set depot to {}
	repeat with folio in sourceFolders
		set end of depot to (files of folio whose type identifier is "public.jpeg")
	end repeat
end tell

-- flatten to simple list
set depot to flatten(depot)

-- cycle images
repeat with eachImage in depot
	-- set up new name and path
	tell application "System Events"
		set nom to name of eachImage
		set ext to name extension of eachImage
		set AppleScript's text item delimiters to "." & ext
		set baseName to text item 1 of nom
		set oldPath to path of eachImage
		set AppleScript's text item delimiters to ""
		-- append 'scaled' to resulting file name
		set newPathName to (repository & baseName & " scaled" & "." & ext) as text
	end tell
	
	-- scale images along longest dimension
	try -- if file with that name already exists, will skip
		alias newPathName
		tell application "Image Events"
			launch
			
			set orig to open oldPath
			scale orig to size 960
			save orig in newPathName -- with icon
		end tell
	end try
	
end repeat
tell application "Finder"
	activate
	select repository
end tell

-- flatten depot lists
on flatten(listOfLists)
	script o
		property fl : {}
		
		on flttn(l)
			script p
				property lol : l
			end script
			
			repeat with i from 1 to (count l)
				set v to item i of p's lol
				if (v's class is list) then
					flttn(v)
				else
					set end of my fl to v
				end if
			end repeat
		end flttn
	end script
	
	tell o
		flttn(listOfLists)
		return its fl
	end tell
end flatten

NB I borrowed Nigel’s recursive list flattener.