Save clipboard image to desktop file

This script saves an image on the clipboard to a file on the desktop. It prompts the user for a file name with extension and, optionally, for a maximum image width/height in pixels. Valid extensions and the resulting image formats are GIF, JPG, PNG, and TIF.

Examples of user input are

The motivation for this script was:

https://macscripter.net/viewtopic.php?id=47361

The basic procedure employed in this script was obtained from:

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


main()

on main()
	
	display dialog "Enter a file name with extension and, if desired, a maximum image width/height." default button 2 default answer "clipboard image.png" with title "Clipboard Image Save"
	set userInput to text returned of result
	if userInput = "" then errorDialog("A file name was not entered.")
	
	try
		set text item delimiters to " "
		set imageSize to ((text item -1 of userInput) as integer) as text
		set fileName to text 1 thru text item -2 of userInput
		set text item delimiters to ""
		set changeSize to true
	on error
		set fileName to userInput
		set changeSize to false
	end try
	
	set text item delimiters to "."
	set fileExtension to text item -1 of fileName
	set text item delimiters to ""
	if fileExtension is not in {"gif", "jpg", "png", "tif"} then errorDialog("A valid file name or extension was not entered. Supported file extensions are gif, jpg, png, and tif.")
	
	set filePath to ((path to desktop) as text) & fileName
	set filePosixPath to quoted form of POSIX path of filePath
	
	try
		alias filePath
		set fileExists to true
	on error
		set fileExists to false
	end try
	
	if fileExists then display dialog "A file exists with the name " & quote & fileName & quote buttons {"Cancel", "Overwrite"} default button 2 with title "Clipboard Image Save"
	
	try
		if fileExtension = "gif" then
			set theImage to the clipboard as GIF picture
		else if fileExtension = "jpg" then
			set theImage to the clipboard as JPEG picture
		else if fileExtension = "png" then
			set theImage to the clipboard as {«class PNGf»} # thanks Fredrik71
		else if fileExtension = "tif" then
			set theImage to the clipboard as TIFF picture
		end if
	on error
		errorDialog("An image was not found on the clipboard.")
	end try
	
	try
		set openedFile to open for access filePath with write permission
		write theImage to openedFile
		close access openedFile
	on error
		try
			close access openedFile
		end try
	end try
	
	if changeSize then do shell script "sips --resampleHeightWidthMax " & imageSize & " " & filePosixPath
	
end main

on errorDialog(dialogText)
	display dialog dialogText buttons "OK" cancel button 1 default button 1 with title "Clipboard Image Save" with icon stop
end errorDialog

This script is similar to the script contained above but differs in that it:

  • works on the file selected in the Finder;
  • has a simplified dialog;
  • is faster in operation; and
  • reads and writes PDF image files in addition to the other image formats.

To test this script, paste it into Script Editor; open a Finder window; select an image file; and run the script.

set imageFormats to {"gif", "jpg", "pdf", "png", "tif"}

tell application "Finder"
	set sourceFile to selection as alias list
	try
		set sourceFolder to container of item 1 of sourceFile as text
		set sourceFileName to name of item 1 of sourceFile
		set sourceFileExtension to name extension of item 1 of sourceFile
	end try
end tell

if (count sourceFile) ≠ 1 then my errorDialog("Multiple or no files selected.", "")

if sourceFileExtension is not in imageFormats then
	set text item delimiters to {", "}
	errorDialog("Image format of selected file not supported", "Valid formats are " & (imageFormats as text) & ".")
	set text item delimiters to {""}
end if

set sourceFile to item 1 of sourceFile as text
set sourcePosixFile to quoted form of POSIX path of sourceFile

display dialog "Enter a file name with extension. The image format of the newly-created file will be that of the file extension." buttons {"Cancel", "Resize", "OK"} default button 3 default answer sourceFileName
set {resizeOption, targetFileName} to {button returned, text returned} of result
if targetFileName = "" then errorDialog("A file name was not entered.", "")

set text item delimiters to "."
set targetFileExtension to text item -1 of targetFileName
set text item delimiters to ""

if targetFileExtension is not in imageFormats then
	set text item delimiters to {", "}
	errorDialog("The file name entered does not contain a valid extension.", "Supported file extensions are " & (imageFormats as text) & ".")
	set text item delimiters to {""}
end if

if sourceFileExtension = targetFileExtension then
	set changeFormat to false
else
	set changeFormat to true
end if

if resizeOption = "Resize" then
	display dialog "Enter an image size. This number will be used to set the height or width of the image, whichever is greater. Leave blank to skip this step." default answer ""
	set targetImageSize to text returned of result
	if targetImageSize = "" then
		set changeSize to false
	else
		try
			targetImageSize as integer
			set changeSize to true
		on error
			errorDialog("An invalid image size was entered.", "")
		end try
	end if
else
	set changeSize to false
end if

set targetFile to sourceFolder & targetFileName
set targetPosixFile to quoted form of POSIX path of targetFile

try
	alias targetFile
	set fileExists to true
on error
	set fileExists to false
end try

if fileExists then display dialog "A file exists with the name " & quote & targetFileName & quote buttons {"Cancel", "Overwrite"} default button 2 with title "Finder Image Convert"

if targetFileExtension = "jpg" then
	set targetFileExtension to "jpeg"
else if targetFileExtension = "tif" then
	set targetFileExtension to "tiff"
end if

if changeFormat and changeSize then
	do shell script "sips --setProperty format " & targetFileExtension & " --resampleHeightWidthMax " & targetImageSize & " " & sourcePosixFile & " --out " & targetPosixFile
else if changeFormat then
	do shell script "sips --setProperty format " & targetFileExtension & " " & sourcePosixFile & " --out " & targetPosixFile
else if changeSize then
	do shell script "sips --resampleHeightWidthMax " & targetImageSize & " " & sourcePosixFile & " --out " & targetPosixFile
else if not changeFormat and not changeSize then
	if sourcePosixFile = targetPosixFile then error number -128
	do shell script "cp " & sourcePosixFile & " " & targetPosixFile
end if

on errorDialog(dialogText, dialogMessage)
	display alert dialogText message dialogMessage as critical
	error number -128
end errorDialog

The above script was revised on April 9, 2020.

Here I tried to improve the 2nd code (which I consider to be more automated) than the 1st one. I tried:

  1. to minimize code size and operations
  2. as much as possible to limit the user from erroneous data entry
  3. to save the new image in the same folder as the original one, and with the same name + index, calculated automatically by the script itself.

set imageFile to choose file of type {"public.image"}
set theImage to read imageFile as TIFF picture
set the clipboard to theImage

set Ext to choose from list {"tif", "gif", "jpg", "png"} with prompt "CHOOSE DESTINATION IMAGE FORMAT"
if Ext is false then
	display notification "User cancelled. Script terminated."
	return
end if

set Ext to item 1 of Ext
if Ext = "gif" then
	set theImage to the clipboard as GIF picture
else if Ext = "jpg" then
	set theImage to the clipboard as JPEG picture
else if Ext = "png" then
	set theImage to the clipboard as «class PNGf» -- thanks Fredrik71
end if

set baseHfsPath to text 1 thru -5 of (imageFile as text)
set filePath to baseHfsPath & "." & Ext
set n to 0
repeat
	try
		alias filePath
		set n to n + 1
		set filePath to baseHfsPath & "(" & n & ")." & Ext
	on error
		exit repeat
	end try
end repeat

set openedFile to open for access filePath with write permission
write theImage to openedFile
close access openedFile

repeat
	try
		set imageSize to text returned of (display dialog "Change image's max size? Enter the value Or Leave empty if not" buttons {"OK"} default answer "")
		if imageSize as number is not 0 then
			set filePosixPath to quoted form of POSIX path of filePath
			do shell script "sips --resampleHeightWidthMax " & imageSize & " " & filePosixPath
		end if
		return
	on error
		display notification "Invalid max size. Enter valid one, please"
	end try
end repeat

KniazidisR. Thanks for looking at my script and for you suggested script.

As a matter of personal preference, I dislike scripts which present the user with multiple dialogs in succession, and that’s the reason I wrote my script as I did. I acknowledge that my approach can be confusing to the user.

While testing your script, I found that the image-width dialog entered an endless loop whenever I specified an image width/height. Leaving the dialog blank avoided this issue.

I updated the last loop, because indeed I found 1 error in it, as you indicated.

If Ext isn’t false, it will contain a list, so your else statements will fail.

Two methods are used in this thread to convert an image file from one format to the another, and I decided to put them to the test using Script Geek. The source file was a 4-MB JPG file and the destination file format was PNG.

The first script took 2.0 seconds to complete. I tried changing the end of the read command to JPEG picture but that made no difference.

set imageFile to "Macintosh HD:Users:Robert:Working:Test Image.jpg" as alias
set theImage to read imageFile as TIFF picture
set the clipboard to theImage

set theImage to the clipboard as «class PNGf»

set filePath to "Macintosh HD:Users:Robert:Working:Test Image.png"

set openedFile to open for access filePath with write permission
write theImage to openedFile
close access openedFile

The second script took 0.7 seconds to complete:

set imageFile to "Macintosh HD:Users:Robert:Working:Test Image.jpg" as alias
set imageFile to quoted form of POSIX path of imageFile

set filePath to quoted form of POSIX path of "Macintosh HD:Users:Robert:Working:Test Image.png"

do shell script "sips --setProperty format png " & imageFile & " --out " & filePath

The above results are not a surprise, but it’s always useful to quantify stuff. If there are any errors in my scripts, please let me know and I’ll give them a second testing.

Try this with the same file:

use AppleScript version "2.5" -- macOS 10.11 or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

set imageFile to POSIX path of "Macintosh HD:Users:Robert:Working:Test Image.jpg"
set imageRep to current application's NSBitmapImageRep's imageRepWithContentsOfFile:imageFile
set theData to (imageRep's representationUsingType:(current application's NSPNGFileType) |properties|:{NSImageInterlaced:false})
set filePath to POSIX path of "Macintosh HD:Users:Robert:Working:Test Image.png"
theData's writeToFile:filePath atomically:true

That took 0.57 seconds. I reran the sips script and the result was 0.71 seconds.

Thanks. Not a lot in it.

Thanks, I fixed this mistake.