Adjust an image size, resolution, exposure and save to the Desktop

If I understand the OP’'s post correctly, he wants an AppleScript that will perform four tasks:

  1. Paste an image file from the clipboard to the desktop. The only way I know to do this is GUI scripting.

  2. Rename the image file once on the desktop–that’s easy.

  3. Change the width of the image file to 500 pixels (3.33" x 150 dpi). Both the sips command-line utility and image events will do this.

  4. Change the exposure/brightness of the image file. I don’t know of any way to do this with macOS utilities within an AppleScript, although ImageMagick can do this if installed.

So, no way to do this that I’m aware of.

Hello peavine.

My understanding isn’t that the OP want the image to be pasted to the Desktop but to be saved in a file named “clippedimage.png” on the desktop.
Doing that doesn’t require GUI scripting.
At this time the unique remaining problem is the requirement upon brightness.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) dimanche 26 janvier 2020 19:28:54

Here is a piece of code adapted from a Shane Stanley’s script.

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

# Adapted from a Shane Stanley's script

set pathToPng to (path to desktop as text) & "clippedimage.png"
my fileFromClipToPath:(pathToPng as «class furl»)


on fileFromClipToPath:thePath
	set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
	-- (pb's types as list) -->	{"public.tiff", "NeXT TIFF v4.0 pasteboard type", "dyn.ah62d4rv4gu8zazwuqm10c6xemf1gq54uqm10c6xenv61a3k", "PVPboardInfoPboardType"}
	set theData to pb's dataForType:(current application's NSPasteboardTypeTIFF) -- get tiff data off pasteboard
	if theData = missing value then error "No tiff data found on clipboard"
	# Convert it into png as asked by the OP
	set newRep to current application's NSBitmapImageRep's imageRepWithData:theData
	set theData to (newRep's representationUsingType:(current application's NSPNGFileType) |properties|:{NSImageInterlaced:false})
	set theResult to (theData's writeToURL:thePath atomically:true)
end fileFromClipToPath:

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) dimanche 26 janvier 2020 21:18:10

That can be done using CoreImage. Here’s your script, suitably adapted:

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

# Adapted from a Shane Stanley's script

set pathToPng to (path to desktop as text) & "clippedimage.png"
my fileFromClipToPath:(pathToPng as «class furl»)


on fileFromClipToPath:thePath
	set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
	set theData to pb's dataForType:(current application's NSPasteboardTypeTIFF) -- get tiff data off pasteboard
	if theData = missing value then error "No tiff data found on clipboard"
	set theCIImage to current application's CIImage's imageWithData:theData
	set theCIFilter to (current application's CIFilter's filterWithName:"CIColorControls" withInputParameters:{inputBrightness:0.15, inputImage:theCIImage}) -- change brightness to suit
	set theCIImage to (theCIFilter's valueForKey:(current application's kCIOutputImageKey))
	set newRep to (current application's NSBitmapImageRep's alloc()'s initWithCIImage:theCIImage)
	set theData to (newRep's representationUsingType:(current application's NSPNGFileType) |properties|:{NSImageInterlaced:false})
	set theResult to (theData's writeToURL:thePath atomically:true)
end fileFromClipToPath:

Thank you Shane.

I tried to add code to change the size as required by the OP.

Here is what I got which is awful but does the job.

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

# Adapted from a Shane Stanley's script

set pathToPng to (path to desktop as text) & "clippedimage.png"
my fileFromClipToPath:(pathToPng as «class furl»)


on fileFromClipToPath:thePath
	set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
	set theData to pb's dataForType:(current application's NSPasteboardTypeTIFF) -- get tiff data off pasteboard
	if theData = missing value then error "No tiff data found on clipboard"
	set theCIImage to current application's CIImage's imageWithData:theData
	
	-- grab the rectangle containing the image
	set {{x, y}, {oldWidth, oldHeight}} to theCIImage's extent()
	-- define the new size
	set theWidth to 500
	set theHeight to theWidth / oldWidth * oldHeight
	
	set theCIFilter to (current application's CIFilter's filterWithName:"CIColorControls" withInputParameters:{inputBrightness:0.15, inputImage:theCIImage}) -- change brightness to suit
	set theCIImage to (theCIFilter's valueForKey:(current application's kCIOutputImageKey))
	set newRep to (current application's NSBitmapImageRep's alloc()'s initWithCIImage:theCIImage)
	set theData to (newRep's representationUsingType:(current application's NSPNGFileType) |properties|:{NSImageInterlaced:false})
	set theResult to (theData's writeToURL:thePath atomically:true)
	-- Reload the image to change its size
	set theImage to current application's NSImage's alloc()'s initWithContentsOfURL:thePath -- load the file as an NSImage
	set newImage to current application's NSImage's alloc()'s initWithSize:(current application's NSMakeSize(theWidth, theHeight)) -- make new blank image
	-- draw from original to new
	newImage's lockFocus()
	theImage's drawInRect:{origin:{x:0, y:0}, |size|:{width:theWidth, height:theHeight}} fromRect:(current application's NSZeroRect) operation:(current application's NSCompositeSourceOver) fraction:1.0
	newImage's unlockFocus()
	set theData to newImage's TIFFRepresentation() -- get bitmap as data
	set newRep to current application's NSBitmapImageRep's imageRepWithData:theData -- make bitmap from data
	set theData to (newRep's representationUsingType:(current application's NSPNGFileType) |properties|:{NSImageInterlaced:false})
	set theResult to (theData's writeToURL:thePath atomically:true)
	
end fileFromClipToPath:

I’m sure that changing the size may be done before the first save action but I failed to do it.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) lundi 27 janvier 2020 12:17:43

I missed the need to scale. It’s probably more efficient to do it first, and it can be done in CoreImage too:

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

set pathToPng to (path to desktop as text) & "clippedimage.png"
my fileFromClipToPath:(pathToPng as «class furl»)


on fileFromClipToPath:thePath
	set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
	set theData to pb's dataForType:(current application's NSPasteboardTypeTIFF) -- get tiff data off pasteboard
	if theData = missing value then error "No tiff data found on clipboard"
	set theCIImage to current application's CIImage's imageWithData:theData
	
	-- grab the rectangle containing the image
	set {{x, y}, {oldWidth, oldHeight}} to theCIImage's extent()
	-- define the new size
	set theWidth to 500 -- points
	set theScale to theWidth / oldWidth
	
	set theCIFilter to (current application's CIFilter's filterWithName:"CILanczosScaleTransform" withInputParameters:{inputScale:theScale, inputImage:theCIImage})
	set theCIImage to (theCIFilter's valueForKey:(current application's kCIOutputImageKey))
	set theCIFilter to (current application's CIFilter's filterWithName:"CIColorControls" withInputParameters:{inputBrightness:0.15, inputImage:theCIImage}) -- change brightness to suit
	set theCIImage to (theCIFilter's valueForKey:(current application's kCIOutputImageKey))
	set newRep to (current application's NSBitmapImageRep's alloc()'s initWithCIImage:theCIImage)
	set theData to (newRep's representationUsingType:(current application's NSPNGFileType) |properties|:{NSImageInterlaced:false})
	set theResult to (theData's writeToURL:thePath atomically:true)
end fileFromClipToPath:

Thank you Shane.
Your code is really neater than mine.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) lundi 27 janvier 2020 13:55:49

Fredrik71. The goal was to save an image, which is on the clipboard, to the desktop. Your suggestion only appears to copy the POSIX path to an image file to the clipboard.

Yvan. My suggestion was to paste (i.e. save) the image file to the desktop and then immediately to rename it to “clippedimage.png”. Shane’s solution does that in one step, which is certainly better, but both accomplish the same thing.

Shane. I opened your script in post 10 in Script Editor and then attempted to use it with a PNG file created with the screencapture utility and with a JPG image from a digital camera. In both cases, I verified that the image files were in the clipboard, and files named clippedimage.png were created on the desktop. I then opened the new desktop image file in Preview and there was no image (just a large icon with “JPEG” and “PNG”). Your script seems to work for other forum members and so I assume this is an issue only for me.

BTW, after copying the PNG image to the clipboard, I ran “clipboard info”, which returned:

I also ran “the clipboard” and it returned the name of the image file.

@peavine.

I tested after copying in the clipboard the contents of : a jpeg, a tiff and a png.
In every cases, the file created on the desktop behaved flawlessly.

My understanding is that you didn’t copied the contents of your files but the files themselves.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) lundi 27 janvier 2020 17:31:16

Thanks Yvan. You are absolutely correct. I copied an image to the clipboard and Shane’s script worked as expected. This also explains your statement I mention in Post 13.

Here is a script which treat both cases:
– the clipboard contain a file image descriptor (what peavine did)
– the clipboard contain the image contents (what Fredrik71, Shane and me did)

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

set pathToPng to ((path to desktop as text) & "clippedimage.png") as «class furl»

try
	clipboard info for {«class furl»}
	set sourceFile to the clipboard as «class furl»
	my fileFromFile:sourceFile toPath:pathToPng
on error
	my fileFromClipToPath:pathToPng
end try

on fileFromClipToPath:thePath
	set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
	set theData to pb's dataForType:(current application's NSPasteboardTypeTIFF) -- get tiff data off pasteboard
	if theData = missing value then error "No tiff data found on clipboard"
	set theCIImage to current application's CIImage's imageWithData:theData
	my shared(theCIImage, thePath)
end fileFromClipToPath:

on shared(theCIImage, thePath)
	-- grab the rectangle containing the image
	set {{x, y}, {oldWidth, oldHeight}} to theCIImage's extent()
	-- define the new size
	set theWidth to 500 -- points
	set theScale to theWidth / oldWidth
	set theCIFilter to (current application's CIFilter's filterWithName:"CILanczosScaleTransform" withInputParameters:{inputScale:theScale, inputImage:theCIImage})
	set theCIImage to (theCIFilter's valueForKey:(current application's kCIOutputImageKey))
	set theCIFilter to (current application's CIFilter's filterWithName:"CIColorControls" withInputParameters:{inputBrightness:0.15, inputImage:theCIImage}) -- change brightness to suit
	set theCIImage to (theCIFilter's valueForKey:(current application's kCIOutputImageKey))
	set newRep to (current application's NSBitmapImageRep's alloc()'s initWithCIImage:theCIImage)
	set theData to (newRep's representationUsingType:(current application's NSPNGFileType) |properties|:{NSImageInterlaced:false})
	set theResult to (theData's writeToURL:thePath atomically:true)
end shared

on fileFromFile:imagePath toPath:thePath
	set theImage to current application's NSImage's alloc()'s initWithContentsOfURL:imagePath -- load the file as an NSImage
	set theData to theImage's TIFFRepresentation() -- get bitmap as data
	set theCIImage to current application's CIImage's imageWithData:theData
	my shared(theCIImage, thePath)
end fileFromFile:toPath:


Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) lundi 27 janvier 2020 18:38:19

Thanks Yvan. I tested your script under both situations and it worked great.

What Fredrik71 described in post #4 is exactly what I’m doing manually and that is the process I would like to automate. Using Preview to create the file from the clipboard and then manually adjusting the image.

I tried running the last script provided and it worked great. Thanks for all your help!

The OP has a great solution from Shane and Yvan.

A question that remains unanswered for me is whether basic AppleScript can be used to save an image on the clipboard as a file. Preview does this but, as the OP notes, it’s convenient to automate this process.

After some Google research I found a procedure which I’ve modified as follows:

try
	set theImage to the clipboard as GIF picture
on error
	display dialog "Image not found on clipboard." buttons "OK" cancel button 1 default button 1
end try

set theFile to ((path to desktop) as text) & "Saved Image.gif"

try
	set openedFile to open for access theFile with write permission
	write theImage to openedFile
	close access openedFile
on error
	try
		close access openedFile
	end try
end try

Is there a better way to do this? Thanks.

Source:
https://discussions.apple.com/thread/2379870

This is the start of a slightly more direct approach:

set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
set theTypes to pb's |types|()
if theTypes's containsObject:(current application's NSPasteboardTypeFileURL) then
	set theURL to (pb's readObjectsForClasses:{current application's NSURL} options:{NSPasteboardURLReadingFileURLsOnlyKey:true})'s firstObject()
	set theCIImage to current application's CIImage's imageWithContentsOfURL:theURL
else if theTypes's containsObject:(current application's NSPasteboardTypeTIFF) then
	set theData to pb's dataForType:(current application's NSPasteboardTypeTIFF) -- get tiff data off pasteboard
	set theCIImage to current application's CIImage's imageWithData:theData
else
	error "Neither file nor image found on clipboard"
end if

Thank you Shane.

Here is the complete script using your proposal.

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

set thePath to ((path to desktop as text) & "clippedimage.png") as «class furl»

set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
set theTypes to pb's |types|() -- the pipes are required with Script Debugger but will be removed by Script Editor!
if theTypes's containsObject:(current application's NSPasteboardTypeFileURL) then
	set theURL to (pb's readObjectsForClasses:{current application's NSURL} options:{NSPasteboardURLReadingFileURLsOnlyKey:true})'s firstObject()
	set theCIImage to current application's CIImage's imageWithContentsOfURL:theURL
else if theTypes's containsObject:(current application's NSPasteboardTypeTIFF) then
	set theData to pb's dataForType:(current application's NSPasteboardTypeTIFF) -- get tiff data off pasteboard
	set theCIImage to current application's CIImage's imageWithData:theData
else
	error "Neither file nor image found on clipboard"
end if

set {{x, y}, {oldWidth, oldHeight}} to theCIImage's extent()
-- define the new size
set theWidth to 500 -- points
set theScale to theWidth / oldWidth
set theCIFilter to (current application's CIFilter's filterWithName:"CILanczosScaleTransform" withInputParameters:{inputScale:theScale, inputImage:theCIImage})
set theCIImage to (theCIFilter's valueForKey:(current application's kCIOutputImageKey))
set theCIFilter to (current application's CIFilter's filterWithName:"CIColorControls" withInputParameters:{inputBrightness:0.15, inputImage:theCIImage}) -- change brightness to suit
set theCIImage to (theCIFilter's valueForKey:(current application's kCIOutputImageKey))
set newRep to (current application's NSBitmapImageRep's alloc()'s initWithCIImage:theCIImage)
set theData to (newRep's representationUsingType:(current application's NSPNGFileType) |properties|:{NSImageInterlaced:false})
set theResult to (theData's writeToURL:thePath atomically:true)

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) mardi 28 janvier 2020 12:21:17

The term type (and hence types) is defined in Script Debugger’s scripting dictionary. So you need pipes in Script Debugger, but not in Script Editor.

Actually, the term is defined by AppleScript itself, as a synonym for type class. Script Debugger uses it in its dictionary, whereas Script Editor doesn’t. Quite why AppleScript doesn’t recognise it in Script Editor is one of those AppleScript mysteries.