It was simple enough to make a script to resize an image using Image Events but I find I need
to resize images in both the vertical and horizontal dimensions…which is where I’m
having trouble getting anything to work.
I need a fixed final size of 460 x 300 regardless of the dimensions of the original.
I realize this will distort some images but that’s fine for my purpose.
Not really cropping the image at all, just forcing it to new dimensions.
So far I have:
set fs to "/Library/Application Support/Perceptive Automation/Images/Sonos/Living Room_art.jpg"
property pngFile : "/Library/Application Support/Perceptive Automation/Indigo 6/IndigoWebServer/images/controls/variables/photo+sonos.png"
property targetSize : 460
tell application "Image Events"
launch
set theImageReference to open fs
-- create the png file
scale theImageReference to size targetSize
save theImageReference as PNG in pngFile with icon
close theImageReference
end tell
Any help getting this to work would be greatly appreciated!
Image Events scales the longer dimension to the target size and scales the shorter one proportionately. You can scale the shorter dimension to a particular size by calculating what the longer one needs to be scaled to to get the required result, but you can’t change the ratio between the dimensions.
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.
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}
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}
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.)
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)
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.