iMagine Photo: Serious Image Power for AppleScripters and Automators

If you edit images, iMagine Photo is a good tool to add to your arsenal. It’s not just AppleScriptable, it was specifically designed to be controlled by AppleScript. That’s good news for both AppleScript and Automator users. And the best news is that it’s free.

iMagine Photo works very much like Image Events. For the uninitiated, Image Events is a faceless app on your Mac that can be controlled by Applescript and other apps. For those using Automator, the complete gamut of Image Events effects is available in the Preview library of actions. These effects include: applying a color profile, darkening, lightening, sepiatone, bluetone, black and white, monotone, changing filetype, cropping, flipping, adding an icon, padding an image with a black frame, rotating, and scaling. Most of what you can do with the Preview app. In essence, Preview is just a face for Image Events.

iMagine Photo can work in the background, like Image Events, but uses the more powerful array of QuickTime effects. For instance, Image Events can crop an image, but only crops to the center. iMagine Photo can crop anywhere. Capabilities include, blur, sharpen, RGB balance, color style, brightness and contrast, detect edges within an image, emboss, hue, saturate, lighten, center gradient, colorsync, color tint, set screen resolution, draw shapes, text and pixels, control metadata, hot pixel processing, set transparency, convert type, blend images, and chroma key. And iMagine Photos can do much of it’s work with movies as well as images.

iMagine Photo already has a small group of solid Automator actions:
Add Border to Image - with control of size and color.
Add Metadata to Image - copyright, author, GPS, notes, original exif or no.
Apply Watermark - Choose an image to watermark with, set the size, and opacity.
Chroma Key - makes a color range transparent.
Draw Text on Image - A field for the text, choose font, size, color, background and location on image.
Get Image File Metadata - Copies image metadata to a text file.
Scale To - Gives compression options.

For both AppleScripters and Automators there are a lot of uses you’ll find for iMagine Photo. For instance, Mac loves the 72dpi resolution setting for photos. I regularly need the DPI set to 150 for image files I put in PDFs so the viewer can zoom without seeing pixels. Seems like a simple thing both iPhoto and Preview should be able to do. But it’s not within Image Events’ power. The following in an AppleScriptlet that can be popped into the Run AppleScript action in Automator. Replace the entire text in the Run AppleScript action with this:


on run {input, parameters}
--Set DPI in iMagine Photo.
-- This will replace the contents of the original file.
tell application "iMagine Photo"
repeat with theItem in input
set thisImporter to import graphic theItem
-- error checking - only process files that quicktime knows about.
if the component error of thisImporter is equal to 0 then
my CreateReplacingExporterLikeImporter(thisImporter)
set the export resolution of thisImporter to {150.0, 150.0}
-- set the export custom icon of thisImporter to true
export thisImporter
end if
close thisImporter -- the importer needs to be closed whether an error occured or not
end repeat
end tell
return input
end run
on GetExportTypeFromImportType(theimportType)
if theimportType is equal to "Photo - JPEG" then
return "JPEG"
else if theimportType contains "TIFF" then
return "TIFF"
else if theimportType is equal to "QuickDraw" then
return "PICT"
else if theimportType is equal to "Planar RGB" then
return "Photoshop"
else if theimportType is equal to "JPEG 2000" then
return "JP2"
else
return theimportType
end if
end GetExportTypeFromImportType
on CreateReplacingExporterLikeImporter(theInitialImporter)
tell application "iMagine Photo"
try
tell theInitialImporter
set theImporterType to the graphic type
set exportType to my GetExportTypeFromImportType(theImporterType)
make exporter with properties {export file type:exportType}
if the export component error is not equal to 0 then
set the export file type to "TIFF"
end if
set exportProperties to {}
if (exportType is equal to "JPEG") then
set exportProperties to exportProperties & {export compression quality:lossless, export exif user data:file location as alias}
else if theImporterType is equal to "TIFF (Uncompressed)" then
set exportProperties to ¬
{export compression method:not packbits, export exif user data:file location as alias}
end if
if the image count is equal to 2 then
set exportProperties to exportProperties & {export thumbnail state:{1, 128, 128}}
end if
set exportProperties to exportProperties & {export file location:file location as alias}
set export properties to exportProperties
end tell
end try
end tell
end CreateReplacingExporterLikeImporter

This takes passed images and sets the dpi to 150. The way iMagine Photo works is that it sets up an Importer window and a Exporter window. They can be visible or not, it’s your choice. Thanks to Kevin Meaney of Yarra Valley software for this script. Kevin made this to mimic an Automator action, so it has the flexibility to process all the QuickTime compatible Image file types and do multiple images.

I used the above script on one of my eBook manuscripts. The doc was written in TextEdit. I had re-rezed all the iPhoto images in the doc to 150 dpi by hand in iPhoto with GraphicConverter originally. And for whatever reason, when I opened the manuscript to do revisions, about half the images were reset back to 72 dpi. I figured that it would take hours to drag the images back in from iPhoto or drag them to the desktop and reset the dpi to 150 by hand in GC.

I put the script in a Run AppleScript action in Automator and saved the workflow as an app on the desktop. I opened the TextEdit doc and dragged the affected images to the Automator app. When I reopened the doc, all the images were still in place and back to 150 dpi. The two"150.0"s can be changed to “300.0” or whatever screen resolution you choose.

As iMagine Photo is not only integrated with AppleScript, but relies on it, the possibilities for creating Automator actions are huge. And the movie capability, which I haven’t touched on here, is vast too.

Below is a script that will blend two images, using the alpha channel information in the alpha image. The script has two assumptions. That both images have the same dimensions and that the export file type is “JPEG”.

Most of the script comes from the transparency documentation section on my website:
http://www.yvs.eu.com/documentation/transparency.html

Kevin


on run
	set thisFile to choose file with prompt "Choose image file without alpha channel: "
	set thisFile2 to choose file with prompt "Choose image file with alpha channel: "
	tell application "iMagine Photo"
		set thisImporter1 to import graphic thisFile
		if the component error of thisImporter1 is not equal to 0 then
			close thisImporter1
			return
		end if
		set thisImporter2 to import graphic thisFile2
		if the component error of thisImporter2 is not equal to 0 then
			close thisImporter1
			close thisImporter2
			return
		end if
		set {x, y, xDim, yDim} to the natural bounds of thisImporter1
		set thisDocument to make new window document with properties {dimensions:{xDim, yDim}}
		set the drawing destination of thisImporter1 to thisDocument
		draw thisImporter1
		close thisImporter1
		set the drawing destination of thisImporter2 to thisDocument
		set the graphics mode of thisImporter2 to straight alpha
		draw thisImporter2
		close thisImporter2
		set outputFile to choose file name with prompt "File to save new image as:"
		set export file location of thisDocument to outputFile
		export thisDocument
		close thisDocument
	end tell
end run

Kevin at Yara Valley has been kind enough to give us another Automator script. This one adds a drop shadow to any image that supports transparency. So JPEGs don’t work but, JPEG 2000 s, TIFFs, PNGs, and TGAs do.

“The first three properties at the beginning of the script can be modified. The first property can be true or false and indicates whether the width of the drop shadow border should be calculated as a percentage of the longest side of the image, or specified in pixels. The next two properties after that allow you to set the percentage width or the border width in pixels.”

To use this action, create a workflow by dragging the images you can’t to effect into Automator. Then insert the script into a Run Applescript action. Replace all text with it. When run, this is change the original image. If you want a copy, you’ll need to create one first.


-- Script to add a drop shadow to the edge of the image. Replaces the contents of the original image.

property byPercentage : false
property thePercentage : 2 -- width of the border added to the image. Percentage of the longest side of the image. Used only if byPercentage is true.
property borderWidth : 15 -- width of the border added to the image, in pixels. Used if byPercentage is false.
property alphaParam : 1.0 -- calculated by script dont touch.

on run {input, parameters}
	-- This will replace the contents of the original file.
	tell application "iMagine Photo"
		repeat with theItem in input
			set thisImporter to import graphic theItem
			set doFile to (the component error of thisImporter is equal to 0)
			if doFile then
				set theType to the graphic type of thisImporter
				set doFile to (theType is equal to "JPEG 2000")
				set doFile to doFile or (theType contains "TIFF")
				set doFile to doFile or (theType is equal to "PNG")
				set doFile to doFile or (theType is equal to "TGA")
			end if
			if doFile then
				set {x, y, xDim, yDim} to the natural bounds of thisImporter
				if byPercentage then
					if xDim > yDim then
						set actualBorderWidth to (thePercentage * xDim) div 100
					else
						set actualBorderWidth to (thePercentage * yDim) div 100
					end if
				else
					set actualBorderWidth to borderWidth
				end if
				set totalWidth to xDim + 2 * actualBorderWidth
				set totalHeight to yDim + 2 * actualBorderWidth
				set thisDocument to make new graphic document with properties {dimensions:{totalWidth, totalHeight}}
				my ModifyDocExporterToImporter(thisImporter, thisDocument)
				my CalcAlphaParams(actualBorderWidth)
				repeat with i from 1 to actualBorderWidth
					set alphaVal to my CalcAlpha(actualBorderWidth + 1 - i, actualBorderWidth + 1)
					tell thisDocument to create composition element with properties {class:filled rectangle, bounds rectangle:{i - 1, i - 1, totalWidth + 1 - i, totalHeight + 1 - i}, color:{alphaVal, alphaVal, alphaVal}}
				end repeat
				tell thisDocument to create composition element with properties {class:filled rectangle, bounds rectangle:{actualBorderWidth, actualBorderWidth, totalWidth - actualBorderWidth, totalHeight - actualBorderWidth}, color:{65535, 65535, 65535}}
				set the alpha channel of thisDocument to {source document:thisDocument, color channel:red channel, inverted:false}
				tell thisDocument to create composition element with properties {class:filled rectangle, bounds rectangle:{0, 0, totalWidth, totalHeight}, color:{0, 0, 0}}
				set the drawing destination of thisImporter to thisDocument
				set the top left point of thisImporter to {actualBorderWidth, actualBorderWidth}
				draw thisImporter
				-- tell thisDocument to create composition element with properties {
				-- set the export custom icon of thisImporter to true
				export thisDocument
				close thisDocument
			end if
			close thisImporter -- the importer needs to be closed whether an error occured or not
		end repeat
	end tell
	return input
end run

on CalcAlphaParams(actualBorderWidth)
	--	set root20 to 4.472135955
	--	set alphaParam to (root20 - 1) / (actualBorderWidth + 1)
	-- set root10 to 3.162277660168
	-- set alphaParam to (root10 - 1) / (actualBorderWidth + 1)
	set root5 to 2.2360679775
	set alphaParam to (root5 - 1) / (actualBorderWidth + 1)
end CalcAlphaParams

on CalcAlpha(theInc, xn1)
	return (6.5535E+4 * ((1.0 / ((alphaParam * theInc + 1.0) ^ 2)) - (theInc / xn1) * 0.199)) as integer
end CalcAlpha

on GetExportTypeFromImportType(theimportType)
	if theimportType contains "TIFF" then
		return "TIFF"
	else if theimportType is equal to "JPEG 2000" then
		return "JP2"
	else
		return theimportType
	end if
end GetExportTypeFromImportType

-- When you want to replace the contents of the original file
-- with as little impact as possible except for the desired
-- action, then this handler will set up the graphic exporter
-- to do that for you.
on ModifyDocExporterToImporter(theImporter, theDocument)
	tell application "iMagine Photo"
		try
			set importType to the graphic type of theImporter
			set exportType to my GetExportTypeFromImportType(importType)
			set the export file type of theDocument to exportType
			if the export component error of theDocument is not equal to 0 then
				set the export file type of theDocument to "TIFF"
			end if
			set the export compression depth of theDocument to 32
			set the export file location of theDocument to the file location of theImporter
		end try
	end tell
end ModifyDocExporterToImporter

Thanks to Kevin Meaney for such a great image program and for all his help.