Resize image and allow width and height distortion

This may not be that useful considering System Events gives quite a few image manipulation tools, but it does not allow you to choose both height and width when resizing. Here’s a function that lets you do it:

use AppleScript version "2.4"
use framework "Foundation"
use framework "AppKit"
use scripting additions

its resizeImageAtPath:"/Users/tneison/Desktop/anInputImg.png" outputTo:"/Users/tneison/Desktop/output.png" width:500.0 height:500.0
on resizeImageAtPath:imgPath outputTo:outputPath width:newWidth height:newHeight
	set sourceImg to current application's NSImage's alloc()'s initWithContentsOfFile:imgPath
	set scaledImg to current application's NSImage's alloc()'s initWithSize:(current application's NSMakeSize(newWidth, newHeight))
	scaledImg's lockFocus()
	set sourceImg's size to (current application's NSMakeSize(newWidth, newHeight))
	set (current application's NSGraphicsContext's currentContext())'s imageInterpolation to 3
	sourceImg's drawInRect:(current application's NSMakeRect(0.0, 0.0, newWidth, newHeight))
	scaledImg's unlockFocus()
	set outputPNGData to (current application's NSBitmapImageRep's imageRepWithData:(scaledImg's TIFFRepresentation))'s representationUsingType:(current application's NSPNGFileType) |properties|:(current application's NSDictionary's dictionary())
	outputPNGData's writeToFile:outputPath atomically:true
end resizeImageAtPath:outputTo:width:height:

An interesting introduction to the ASObjC methods though.

In view of the discussion of property setting in the “Six digit numeric date string creator” thread, I suppose that these lines .

set sourceImg's size to (current application's NSMakeSize(newWidth, newHeight))
set (current application's NSGraphicsContext's currentContext())'s imageInterpolation to 3

. would be preferably rendered as:

sourceImg's setSize:(current application's NSMakeSize(newWidth, newHeight))
(current application's NSGraphicsContext's currentContext())'s setImageInterpolation:(3)

In many cases where an object’s properties can be set, the methods which read them have implied setting equivalents with labels constructed thus:

set someVariable to blahBlah's someProperty() -- Get a property value.
blahBlah's setSomeProperty:(someValue) -- Set it.

I’d go further and suggest:

current application's NSGraphicsContext's currentContext())'s setImageInterpolation:(current application's NSImageInterpolationHigh)

I think it’s generally preferable to use enums rather than raw numbers, for the sake of readability.

FWIW, Objective-C didn’t used to have such things as properties. Instead, you declared an instance variable, and then you wrote two accessor methods for it: the getter, which generally had the same name as the variable (although boolean values were often accessed via isVariable), and the setter, which took the form of setVariable:. The code within these methods would handle the memory management for the value, which would vary depending on the type of value being stored, and the idea was access would be all be done safely via the accessors.

This meant a lot of boilerplate code, and it was also easy to get the memory management code wrong, often resulting in hard-to-trace crashes. Properties were introduced as a replacement; they do what the old code did, reducing both the amount of code that needed to be written, and the possibility of errors. But they still effectively implement the same stuff under the hood.

And lots of other stuff relies on this naming pattern, including application scripting. So if you look at an .sdef file for an app like Mail, you will see the color property is defined as having a cocoa key of foregroundColor. That just tells Cocoa scripting to use -foregroundColor as getter and -setForegroundColor: as setter.

Probably more than you wanted to know…

Actually that is really interesting. The setters don’t appear in the Apple documentations for NSImage so I would have had no way of knowing (unless, I suppose, I knew anything at all about Objective C). I was only able to write this ASOC image resizer because I first saw it written in Swift.

Would you say this is the case most of the time?

On a separate note. I was never able to get the NSImage method drawAtPoint:fromRect:operation:fraction: to work. I wanted to use it to do some compositing.
This is what I attempted:

sourceImg's drawAtPoint:(current application's NSZeroPoint) fromRect:(current application's NSMakeRect(0.0, 0.0, newWidth, newHeight)) operation:(current application's NSCompositingOperationCopy) fraction:1.0

instead of…

sourceImg's drawInRect:(current application's NSMakeRect(0.0, 0.0, newWidth, newHeight))

It gives me the error:


All the time (provided the property is not read-only).

That’s not the correct enum. Try this:

sourceImg's drawAtPoint:(current application's NSZeroPoint) fromRect:(current application's NSMakeRect(0.0, 0.0, newWidth, newHeight)) operation:(current application's NSCompositeCopy) fraction:1.0

I see what you mean about setting properties directly not being reliable. When I subbed in drawAtPoint:, it succeed but the image was garbled. When I changed to setSize:, it worked again.

I think I could do overlays and compositing now. However, I haven’t a reason to do it…

Thanks.