Crop Specific Portion of Image

Hey,

Somehow this has become a lot more difficult than I would have thought.
Just need to crop an image to a specified size from a specified point on the image.

The image I’m cropping I’m downloading using Paparazzi! which works great.
Here’s the script for that if anyone is interested.

tell application "Paparazzi!.app"
	activate
	set minsize to {1004, 3870}
	set fileName to "whitefishT.jpg"
	set iconame to (true)
	«event Pzi!Capt» "http://www.onthesnow.com/montana/whitefish-mountain-resort/skireport.html?XE_AFF=rss" given «class cSiz»:minsize
	repeat while «class pBzy»
		-- To wait until the page is loaded.
	end repeat
	save as «constant sFMTJPEG» in "Macintosh HD:Users:TL:desktop:Ski Images:" & fileName
	quit application "Paparazzi!.app"
end tell

I hear that iMagine Photo can do the crop but I’m not having any luck with a script for it.
Here’s what I have so far:

set thisFile to "Macintosh HD:Users:TL:desktop:Ski Images:whitefishT.jpg"
set exportFile to "Macintosh HD:Users:TL:desktop:Ski Images:whitefish.jpg"

tell application "iMagine Photo"
	set thisImporter to thisFile
	set {x, y, xDim, yDim} to thisImporter
	tell thisImporter to make exporter
	set the export file location of thisImporter to exportedFile
	set theTop to (yDim / 4) as integer
	set theLeft to (xDim / 4) as integer
	set theRight to ((xDim / 2) + theLeft) as integer
	set theBottom to ((yDim / 2) + theTop) as integer
	set the source rectangle of thisImporter to {theLeft, theTop, theRight, theBottom}

	export thisImporter

end tell


set thisFile to "Macintosh HD:Users:TL:desktop:Ski Images:whitefishT.jpg"
tell application "iMagine Photo"
	set exporterTypes to the available exporter types
	set theFolder to "Macintosh HD:Users:TL:desktop:Ski Images:"
	set fileName to "whitefish.jpg"
	set thisImporter to import graphic thisFile
	if the component error of thisImporter is not equal to 0 then
		close thisImporter
		return
	end if
	tell thisImporter to make exporter with properties {export file type:exportType, export folder location:theFolder}
	set theExtension to the export file extension of thisImporter
	set the export file name of thisImporter to (fileName & theExtension)
	export thisImporter
	close thisImporter
end tell

It seems to get hung up with the path to the image which I know is correct as it’s the same one I used
in the Paparazzi! script.

Maybe some other way way to crop an image with a script? I tried Image Events but it will only crop from the center.

Here’s the cropped portion I’m trying to end up with: http://www.cidesignhouse.com/ski_image.jpg

Any ideas or info greatly appreciated!

Thanks,

Carl

FWIW, you can do this fairly easily in AppleScriptObjC. You’d need to save your code as a Cocoa-AppleScript application from AppleScript Editor:

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 theImage to current application's NSImage's alloc()'s initWithContentsOfFile_(thisFile)
set theSize to (theImage's |size|()) as record
set theHeight to height of theSize
set theWidth to width of theSize
set newRect to {{x:theWidth / 4, y:theHeight / 4}, {width:theWidth / 2, height:theHeight / 2}}
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)

Alternatively, you could save it as a normal AS script, using ASObjC Runner to run the AppleScriptObjC part:

script cropPic
	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 theSize to (theImage's |size|()) as record
	set theHeight to height of theSize
	set theWidth to width of theSize
	set newRect to {{x:theWidth / 4, y:theHeight / 4}, {width:theWidth / 2, height:theHeight / 2}}
	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 "Macintosh HD:Users:TL:desktop:Ski Images:whitefishT.jpg"
set exportFile to POSIX path of "Macintosh HD:Users:TL:desktop:Ski Images:whitefish.jpg"
tell application "ASObjC Runner" to run the script {cropPic} passing {thisFile, exportFile}

Thanks a bunch. I’m trying the second version that uses ASObjC Runner. I have it installed
but the script won’t compile. Gets stuck on “passing” in the last line:

tell application "ASObjC Runner" to run the script {cropPic} passing {thisFile, exportFile}

Really appreciate the help!

Carl

Hi ckeyes888,

The ASObjC Runner wouldn’t compile after the first run for me. I can’t remember what I did exactly, but probably: repair disk permissions, cold start, zap the PRAM, and I might have made it 64 bit I think in the info window. Oh, and try quitting it in the status menu.

Edited: if you don’t have the menu icon, then:
tell app “ASObjC Runner” to quit

gl,
kel

Restarted everything and the script is running fine.
Just having issues with the height and width settings. Are they percentages do you know?
Been experimenting with them but can’t seem to come up with any pattern to how they work.

I assume one set of them is the final image size and the second the position it crops from?

Thanks!

Carl

I think height and width is usually pixels.

Edited: here’s the rectangle definition:

Edited: note that the origin might be the upper left corner instead of the lower left. I’m not sure and haven’t run the script yet.

gl,
kel

Got it. Can’t thank you enough for the excellent solution!
Just took a lot of number combinations.

It’s amazingly fast as well :slight_smile:

Carl

Funny how they never mention that a ‘rectangle’ is an array of dictionaries. How would you even know this?

Sorry – the x and y values are the origin, and the others are the width and height. But the origin is the bottom-left, not top-left.

It’s much quicker than using apps that display images first.

It’s not, though. It’s actually a struct, which is C thing that you can use a bit like a dictionary or record, but really just packs all the bits together in a structured way. There’s no direct AS equivalent because, apart from anything else, AS doesn’t support primitive data types – everything in AS is really an object.

Anyway, ASObjC gets around this by automatically converting between a handful of structs and AS records. So an NSRect is returned as:

{origin:{x:x1, y:y1}, |size|:{|width|:theWidth, height:theHeight}} 

The origin value is another struct, NSPoint, and the size is also a struct: NSSize.

The other one you’ll strike often in ASObjC is NSRange, which is how ranges of text are typically described: {|location|:theLocation, |length|:theLength} . The location is the zero-based offset of a string, and the length is the number of characters in the range.

Perfect…you guys are tha men.

Thanks,

Carl

Interesting. The script works perfectly but returns an error: unrecognized function size (-10000)
when I move it to an identical machine running the same ASObjC Runner and OSX version.

Tried just changing a few size numbers but the error persists.

Any idea what it may be?

Thanks,

Carl

Hi Shane,

Thanks for the great quick tutorial. :slight_smile: It looks more like a record of records.

Kel

Does the term “size” still appear in pipes? Any third-party scripting additions?

For completeness. I’ve fixed the errors in the first part of Carl’s original script so that it works for me. There were numerous errors but your initial problem was that the path needs to be made into a file or alias object for iMagine Photo to know what to do with it. See script below.

In terms of performance I’d think that this would give Shane’s excellent solution a run for its money.

I wouldn’t however recommend using iMagine Photo as I haven’t updated it since 2006 and it is not going to be updated.

Kevin


set thisFile to "MacintoshHD:Users:ktam:Phone Pictures:07-08-2011 17.18.35.jpg" as alias
set exportFile to "MacintoshHD:Users:ktam:Desktop:cropped.jpg"

tell application "iMagine Photo"
	set thisImporter to import graphic thisFile
	set {x, y, xDim, yDim} to source rectangle of thisImporter
	tell thisImporter to make exporter
	set the export file location of thisImporter to file exportFile
	set theTop to (yDim / 4) as integer
	set theLeft to (xDim / 4) as integer
	set theRight to ((xDim / 2) + theLeft) as integer
	set theBottom to ((yDim / 2) + theTop) as integer
	set the source rectangle of thisImporter to {theLeft, theTop, theRight, theBottom}
	export thisImporter
	close thisImporter
end tell

Presumably we’re both doing much the same thing. The big factor is avoiding screen redraw/UI.

Is there some reason for not updating, other than, say, better things to do with your time? Just curious…

I’ve been doing other things for the last 10 years. Though I did do some updates to iMagine Photo for the first few years. I am however working for myself again so I’m onto a new project.

I know that iMagine Photo will run in the next version of OS X but I hadn’t expected it to.

I don’t see any point in updating iMagine Photo now as it depends on the carbon API of Quicktime which is 32 bit bound and I can’t see it surviving post Mavericks.

I am now working on a replacement for iMagine Photo but it won’t be applescript, but instead a mixture of unix shell scripts and json. I will have an alpha version released late October early November. It will be missing a lot of the final functionality I have planned but will have a lot of useful functionality. I am expecting to finish coding for the first alpha version release within a couple of weeks and I’ll then be onto writing the documentation.

In some ways the new tool is similar to iMagine Photo. It is running as a LaunchAgent (a user process daemon). iMagine Photo can be run as a UIElement faceless application. Like iMagine Photo the LaunchAgent stays alive between each message it receives as long as it is maintaining state (there are still objects alive that can be referenced) and maintains an idle time which keeps the tool alive for a specified period after all state is destroyed.

The new tool will be free. It will only run on Mavericks or later.

When I do the alpha release I’ll be looking for testers.

Kevin

What tool are you using to crop your images?

Can we see the script you using?

Kevin

Cropping should have very little effect on the image quality, but if you’re starting with a PDF and going to any sort of bitmap, type will have to suffer. You could increase the DPI, but although that would help with the type, it would probably do awful things with any pictures – if you’re getting 72dpi, it’s because the original is probably 72dpi.

The dpi is irrelevant – what matters is the number of pixels.