Is there a way to load and save raw typed data?

Assuming I have an image in the clipboard, I can retrieve the JPG version of it using this code:

set c to the clipboard as record
set r to JPEG picture of c

Which gives:

Now, is there a generic way to save such data to a file? And is there a way to load data from a file into such a typed value as well?

One possible way is the Cocoa way


use framework "Foundation"

set pasteboard to current application's NSPasteboard's generalPasteboard()
set classArray to {current application's NSImage's |class|()}
set options to current application's NSDictionary's dictionary()
if pasteboard's canReadObjectForClasses:classArray options:options then
	
	set array to pasteboard's readObjectsForClasses:classArray options:options
	set image to array's objectAtIndex:0
	set imageData to image's TIFFRepresentation()
	set imageRep to current application's NSBitmapImageRep's imageRepWithData:imageData
	set imageProps to {NSImageCompressionFactor:1.0}
	set imageData to imageRep's representationUsingType:(current application's NSJPEGFileType) |properties|:imageProps
	
end if


imageData contains an NSData object which can be saved to disk

Cool! So, with this (AS-ObjC, which I never thought of using before), anyone could implement picture conversion between PNG, TIFF, GIF, JPEG etc. using the Pasteboard now.

Has anyone written a pure AS lib based on this, yet?

I have no time to check but as far as I remember there is all needed pieces of code in this old script.

use scripting additions
use framework "Foundation"
use framework "AppKit"

tell application id "com.apple.iWork.Numbers" to tell document 1 to tell sheet 1 to tell table 1
	set selection range to range ("A1:" & name of last cell)
end tell
set the clipboard to "" # guarantee that there is no "public.utf16-external-plain-text" type of data in the clipboard

# Copy the selected cells 
tell application "System Events" to tell process "Numbers"
	set frontmost to true
	keystroke "c" using {command down}
end tell
my wait4cells()
set pathToChart to (path to desktop as text) & "theCells.txt"
my textFileFromClipToPath:(POSIX path of pathToChart)

set pathToChart to (path to desktop as text) & "theCells.png"
my fileFromClipToPath:(POSIX path of pathToChart)

set pathToChart to (path to desktop as text) & "theCells.jpg"
my fileFromClipToPath:(POSIX path of pathToChart)

tell application id "com.apple.iWork.Numbers" to tell document 1 to tell sheet 1
	width of chart 1 # Select the chart
end tell
set the clipboard to "" # guarantee that there is no "public.tiff" in the clipboard

# Copy the selected chart
tell application "System Events" to tell process "Numbers"
	set frontmost to true
	keystroke "c" using {command down}
end tell
my wait4chart()
set pathToChart to (path to desktop as text) & "theChart 08.jpg"
my jpegFromClipToPath:(POSIX path of pathToChart) compressFactor:0.8

set pathToChart to (path to desktop as text) & "theChart 10.tif"
my fileFromClipToPath:(POSIX path of pathToChart)

#=====
# Handler built upon the one written by Shane STANLEY
on textFileFromClipToPath:thePath
	set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
	set theData to pb's dataForType:(current application's NSPasteboardTypeString)
	if theData = missing value then error "No Numbers cells data found on clipboard"
	set theResult to (theData's writeToFile:thePath atomically:true)
	return (theResult = 1)
end textFileFromClipToPath:

#=====
# Handler written by Shane STANLEY
on jpegFromClipToPath:thePath compressFactor:compFactor -- 0.0 = max compression, 1.0 = none
	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"
	# Convert it into jpeg will get rid of transparency
	set newRep to current application's NSBitmapImageRep's imageRepWithData:theData
	set theData to (newRep's representationUsingType:(current application's NSJPEGFileType) |properties|:{NSImageCompressionFactor:compFactor, NSImageProgressive:false})
	set theResult to (theData's writeToFile:thePath atomically:true)
	return (theResult = 1)
end jpegFromClipToPath:compressFactor:

#=====
# Handler built upon the one written by Shane STANLEY
on fileFromClipToPath:thePath
	set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
	set theType to pb's availableTypeFromArray:{current application's NSPasteboardTypeTIFF, current application's NSPasteboardTypePNG, current application's NSPasteboardTypePDF, "public.jpeg", "com.compuserve.gif", "com.microsoft.bmp"} -- returns first type found
	if the theType is missing value then error "No suitable image data found on the clipboard"
	-- log theType as text
	set theData to pb's dataForType:theType
	if (theType = current application's NSPasteboardTypeTIFF) then
		if (thePath ends with ".tiff") or thePath ends with ".tif" then
			-- no change required, save tiff data as is
		else if thePath ends with ".png" then # Convert the Tiff datas into Png ones
			set theData to my convertToPng(theData)
		else if (thePath ends with ".jpg") or thePath ends with ".jpeg" then # Convert the Tiff datas into Jpeg ones
			set theData to my convertToJpeg(theData)
		else # No extension given, save as Tiff
			set thePath to my ChangeExtension(thePath, "tiff") as text
		end if
	else if (theType = current application's NSPasteboardTypePNG) then
		if thePath ends with ".png" then
			-- no change required, save png data as is
		else if thePath ends with ".tiff" then # Convert the Png datas into Tiff ones
			set theData to my convertToTiff(theData)
		else if (thePath ends with ".jpg") or thePath ends with ".jpeg" then # Convert the Png datas into Jpeg ones
			set theData to my convertToJpeg(theData)
		else # No extension given, save as Png
			set thePath to my ChangeExtension(thePath, "png") as text
		end if
	else if (theType = current application's NSPasteboardTypePDF) then
		if thePath ends with ".pdf" then
			-- no change required, save pdf data as is
		else if (thePath ends with ".tiff") or (thePath ends with ".tif") or (thePath ends with ".png") or (thePath ends with ".jpg") or thePath ends with ".jpeg" then (*
		set newRep to current application's NSBitmapImageRep's imageRepWithData:theData
		log newRep --> missing value ????
		*)
			# As an awful workaround, save the data in a pdf file first
			set newExt to "pdf"
			set pathNSString to current application's NSString's stringWithString:thePath
			set pdfPath to pathNSString's stringByDeletingPathExtension()'s stringByAppendingPathExtension:newExt
			set theResult to (theData's writeToFile:pdfPath atomically:true)
			if (theResult = 1) then
				# Now the data is in a pdf file, extract the image
				set theImage to current application's NSImage's alloc()'s initWithContentsOfFile:pdfPath
				if theImage = missing value then return false
				-- get bitmap as data
				set theData to theImage's TIFFRepresentation()
				-- make imagerep from data
				set newRep to current application's NSBitmapImageRep's imageRepWithData:theData
				if (thePath ends with ".tiff") or thePath ends with ".tif" then
					set theData to (newRep's representationUsingType:(current application's NSTIFFFileType) |properties|:{NSTIFFCompressionNone:1})
				else if thePath ends with ".png" then # Try to convert the PDF datas into Png ones
					set theData to (newRep's representationUsingType:(current application's NSPNGFileType) |properties|:{NSTIFFCompressionNone:1})
				else if (thePath ends with ".jpg") or thePath ends with ".jpeg" then # Try to convert the PDF datas into Jpeg ones
					set compFactor to 1
					
				end if
			end if
		else # No usable extension given, save as Pdf
			set thePath to my ChangeExtension(thePath, "pdf") as text
		end if
	else if (theType = "public.jpeg") then
		if (thePath ends with ".jpg") or thePath ends with ".jpeg" then
			-- no change required, save jpeg data as is
		else # No usable extension given, save as jpg
			set thePath to my ChangeExtension(thePath, "jpg")
		end if
	else if theType = "com.compuserve.gif" then
		if thePath ends with ".gif" then
			-- no change required, save gif data as is
		else # No usable extension given, save as gif
			set thePath to my ChangeExtension(thePath, "gif")
		end if
	else if theType = "com.microsoft.bmp" then
		if thePath ends with ".bmp" then
			-- no change required, save bmp data as is
		else # No usable extension given, save as bmp
			set thePath to my ChangeExtension(thePath, "bmp")
		end if
	end if
	set theResult to (theData's writeToFile:thePath atomically:true)
	return (theResult = 1)
end fileFromClipToPath:

on convertToTiff(theData)
	set newRep to current application's NSBitmapImageRep's imageRepWithData:theData
	return (newRep's representationUsingType:(current application's NSTIFFFileType) |properties|:{NSTIFFCompressionNone:1})
end convertToTiff

on convertToPng(theData)
	set newRep to current application's NSBitmapImageRep's imageRepWithData:theData
	return (newRep's representationUsingType:(current application's NSPNGFileType) |properties|:{NSTIFFCompressionNone:1})
end convertToPng

on convertToJpeg(theData)
	set compFactor to 1
	set newRep to current application's NSBitmapImageRep's imageRepWithData:theData
	return (newRep's representationUsingType:(current application's NSJPEGFileType) |properties|:{NSImageCompressionFactor:compFactor, NSImageProgressive:false})
end convertToJpeg

on ChangeExtension(thePath, newExt)
	set pathNSString to current application's NSString's stringWithString:thePath
	return pathNSString's stringByDeletingPathExtension()'s stringByAppendingPathExtension:newExt
end ChangeExtension

#=====
# Test written by Shane STANLEY
on wait4chart()
	local pb, isOK, i
	set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
	-- log (pb's types as list)
	repeat with i from 1 to 10 -- some limit
		tell current application to delay 0.1
		if ((pb's types()'s containsObject:"public.tiff") as boolean) and not ((pb's types()'s containsObject:(current application's NSPasteboardTypeString)) as boolean) then exit repeat
		if i = 10 then
			error "No Numbers chart available in the clipboard !"
		end if
	end repeat
end wait4chart

#=====
# Test built upon the one written by Shane STANLEY
on wait4cells()
	local pb, isOK, i
	set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
	repeat with i from 1 to 20 -- some limit
		tell current application to delay 0.5
		if (pb's types()'s containsObject:"public.utf16-external-plain-text") as boolean then exit repeat
		if i = 20 then
			error "No text data available in the clipboard !"
		end if
	end repeat
end wait4cells

#=====

# (current application's NS???FileType)
# Tiff -> 0
# Bmp -> 1
# Gif -> 2
# Jpeg -> 3
# Png -> 4

# log (pb's types as list)
(*	
# clipboards filled with standard text or with Numbers cells share these components :
"public.rtf"
"NeXT Rich Text Format v1.0 pasteboard type"
"public.utf16-external-plain-text"
"CorePasteboardFlavorType 0x75743136"
"public.utf8-plain-text"
"NSStringPboardType"
"com.apple.traditional-mac-plain-text"
"CorePasteboardFlavorType 0x54455854"
"dyn.ah62d4rv4gk81g7d3ru"
"CorePasteboardFlavorType 0x7374796C"

# if the clipboard was filled from Script Editor or Numbers cells it contain also
"dyn.ah62d4rv4gk81n65yru"
"CorePasteboardFlavorType 0x7573746C"

 # a clipboard filled with Numbers cells contain these other components :
 
"com.apple.iWork.TSPNativeMetadata" <
"com.apple.iWork.TSPNativeData" <
"com.apple.iWork.TSPDescription" <
"com.apple.rtfd"
"public.html"
"Apple HTML pasteboard type"
"public.png" <
"Apple PNG pasteboard type" <
"com.adobe.pdf"
"Apple PDF pasteboard type"
"public.tiff" <
"NeXT TIFF v4.0 pasteboard type" <

# a clipboard filled with a Numbers chart contain these components :
"com.apple.iWork.TSPNativeMetadata"
"com.apple.iWork.TSPNativeData"
"com.apple.iWork.TSPDescription"
"public.png"
"Apple PNG pasteboard type"
"public.tiff"
"NeXT TIFF v4.0 pasteboard type"

# So to check that cells are available we must test for availability of :
"com.apple.rtfd"
"public.html"
"Apple HTML pasteboard type"
"com.adobe.pdf"
"Apple PDF pasteboard type"

# In practice, to check that the clipboard contains Numbers cells we would check that
it contains "public.rtf"

# To check that the clipboard contains a Numbers chart we would check that
it contain "public tiff" but doesn't contain (current application's NSPasteboardTypeString)
*)

As you will see, it was originally written to put cells selected in Numbers in a picture file.
But you may drop the instructions dedicated to Numbers.

Oops. I didn’t used the script since El Capitan delivery so I missed the fact that comparisons doesn’t behave now as they behaved under Yosemite. When a comparison matches, it returned 1 but now it returns true.
I edited the tests accordingly.
I took this occasion to allow us to use the extension “tif” as well as “tiff” after discovering that I have hundreds of files with the “tif” extension on my machine.

Yvan KOENIG running El Capitan 10.11.5 in French (VALLAURIS, France) dimanche 5 juin 2016 21:07:37