How Do I Copy Image File to Clipboard and Retain Format?

foundation
finder
asobjc

(koenigyvan) #21

I will be more precise.
The original file was "test-1200.png"
I ran the script

[code]# borrowed from : How Do I Copy Image File to Clipboard and Retain Format?

use AppleScript version “2.4” – Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

(*
set posixPath to "/Users/shane/desktop/test-1200.png"
set posixPath to POSIX path of “Macintosh HD:Users:Important:pour ebay:_X28737ƒYK:##28755.png”
*)
set posixPath to POSIX path of ((path to desktop as text) & “test-1200.png”)

set {theData, theError} to current application’s NSData’s dataWithContentsOfFile:posixPath options:0 |error|:(reference)
set theClip to current application’s NSPasteboard’s generalPasteboard()
theClip’s clearContents()
theClip’s setData:theData forType:"public.jpeg"
set theType to theClip’s (pasteboardItems()'s objectAtIndex:0)'s types() as list
set theTypes to theClip’s types() as list[/code]
I created a new mail and pasted in it.
I sent the message to myself (the joy of having several mail addresses)
I opened the received message.
I entered the small local menu listing the attachments and was proposed to save the file as “PastedGraphic-1.tiff” with its 3.8 Mbytes.

It seems that if the clipboard contain “public.png” and “public.tiff” data, Mail grabs the “public.png” component
but if the clipboard contain “public.jpeg” and “public.tiff” data, Mail grabs the “public.tiff” component.

When I pasted the same clipboard into a Pages document, as the file was a flat one I can’t see the picture file itself but looking in the file with Hexedit I found the string “PastedGraphic-1.jpeg” which is what I wished to get.

Of course, I was able to save the content of the clipboard in a jpeg file but I don’t guess what would help in doing that.

What would be fine would be the ability to remove the “public.tiff” and “NeXT TIFF v4.0 pasteboard type” components from the clipboard exactly as we may drop the style components when we copy a styled piece of text.
I will try to retrieve the script doing that to see if it may be adapted to drop the tiff components.


(Shane Stanley) #22

Then you shouldn’t use public.jpeg as the type – you have to use public.png. When you call setData:forType:, the data and the type must match.

And then you would not be able to copy-and-paste the image into an application that only accepts tiffs. The whole point of the clipboard is to offer a wide range of formats, and let the client application choose which suits it best.


(koenigyvan) #23

I don’t want to keep always jpeg only but I feel that it may be interesting to paste jpeg in some cases where I know that it would be smaller than png.

With the proposed file I ran :slight_smile:[code]# borrowed from : How Do I Copy Image File to Clipboard and Retain Format?

use AppleScript version “2.4” – Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

(*
set posixPath to "/Users/shane/desktop/test-1200.png"
set posixPath to POSIX path of “Macintosh HD:Users:Important:pour ebay:_X28737ƒYK:##28755.png”
*)
set posixPath to POSIX path of ((path to desktop as text) & “test-1200.png”)

set {theData, theError} to current application’s NSData’s dataWithContentsOfFile:posixPath options:0 |error|:(reference)
set theClip to current application’s NSPasteboard’s generalPasteboard()
theClip’s clearContents()
theClip’s setData:theData forType:"public.png"
set theType to theClip’s (pasteboardItems()'s objectAtIndex:0)'s types() as list
log theType (public.png)
set theTypes to theClip’s types() as list
log theTypes (public.png, Apple PNG pasteboard type, public.tiff, NeXT TIFF v4.0 pasteboard type)
clipboard info

The default compfactor applied to jpeg is ≃ 0.75

–> {{«class PNGf», 1 070 884}, {«class 8BPS», 11 066 614}, {GIF picture, 626 510}, {«class jp2 », 4 139 634}, {JPEG picture, 6 359 827}, {TIFF picture, 6.3105946E+8}, {«class BMP », 6.31061382E+8}, {«class TPIC», 7 359 854}}

set theData to theClip’s dataForType:“public.tiff” – get tiff data off pasteboard
if theData = missing value then error "No tiff data found on clipboard"
set newRep to current application’s NSBitmapImageRep’s imageRepWithData:theData
set compfactor to 1.0
set theData to (newRep’s representationUsingType:(current application’s NSJPEGFileType) |properties|:{NSImageCompressionFactor:compfactor, NSImageProgressive:false})
theClip’s setData:theData forType:"public.jpeg"
set theType to theClip’s (pasteboardItems()'s objectAtIndex:0)'s types() as list
log theType (public.png, public.jpeg)
set theTypes to theClip’s types() as list
log theTypes (public.png, Apple PNG pasteboard type, public.jpeg, CorePasteboardFlavorType 0x4A504547, public.tiff, NeXT TIFF v4.0 pasteboard type)
clipboard info

with compfactor = 1.0

–> {{«class PNGf», 1 070 884}, {JPEG picture, 11 564 428}, {«class 8BPS», 11 066 614}, {GIF picture, 626 510}, {«class jp2 », 4 139 634}, {TIFF picture, 6.3105946E+8}, {«class BMP », 6.31061382E+8}, {«class TPIC», 7 359 854}}

[/code]

This thought me that :
(1) the jpeg stored by default is not the best quality one, it’s compressed with a factor ≃ 0.75
(2) how to store a jpeg with no compression
(3) the png object is smaller than the jpeg one so it’s useless to try to play with the jpeg one.


#24

This is because I produced the PNG file from vector graphics, without any antialiasing. JPEG doesn’t “understand” this type of non-continuous-tone images and will introduce its typical artifacts. Thus the JPEG file size of those images will always be larger than the PNG which uses some kind of deflate compression (very effective for this kind of images, and lossless, i.e. no artifacts added).

And, this is true over the whole JPEG quality range, including 100:

JPEG, quality: 5 → file size: 1.2MB

JPEG, quality: 100 → file size: 3.6MB

Original PNG, file size: 325KB; losslessly optimized: 125KB

(File sizes and screenshots for the 600ppi version of the test file.)

But this doesn’t mean JPEG is useless. It works fine for continuous-tone images, typically photos. (Good ratio of perceived quality / file size.)

Not sure what you mean.

Even if you set the JPEG quality to 100 it will still alter the image (see above).

It exists a “JPEG Lossless” but it seems to be a different format than JPEG and not many programs have implemented it. Off hand, GraphicConverter is the only app I know that offers “JPEG Lossless”. But with the example image from above it produces a file size of 20.2MB.

JPEG2000 has a Lossless option. It produces a file size of 1.2MB.


#25

Yep, this works fine! Thank you.


(koenigyvan) #26

Hello Tom

I reproduce my message with a different layout :slight_smile:
This thought me that : (1) the jpeg stored by default is not the best quality one, it’s compressed with a factor ≃ 0.75
This thought me that : (2) how to store a jpeg with no compression (better said with a factor = 1.0)
This thought me that : (3) the png object is smaller than the jpeg one so it’s useless to try to play with the jpeg one. (in a case like yours)

I guess that it’s more clear this time.
Of course, I knew that getting a jpeg larger than the png is not the general case.
Thank you for giving the explanation of this “surprising” behavior.


(Jim Underwood) #27
theClip's setData:theData forType:"public.png"

Many thanks, Shane. That was the key to getting the data on the clipboard in the same format as the file.

So, here is my script, hopefully solving the problem, which takes into account all of the great stuff posted by @ShaneStanley, @Tom, @ccstone, and others.

If anyone sees any errors/issues, or can offer improvements, please advise.

###Script to Put Image File on Clipboard & Retain Format

(*
===============================================================================
  Put Image File on Clipboard
===============================================================================

VER:   1.0    LAST UPDATE:   2017-05-01

PURPOSE:
  • Select Image File, and Put on Clipboard Retaining Same Format

AUTHOR:    JMichaelTX (with heavy lifting from others)
              • I cobbled this together, and accept responsibility for all errors
              • The meat of this script provided by @ShaneStanley, @ccstone, and @Tom

REQUIRED:
  1.  macOS El Capitan 10.11.6+
  2. use statements for ASObjC shown below
  
METHOD:
  • Get the file format using Spotlight Metadata for kMDItemContentTypeTree
  • Read the file using ASObjC
  • Write the Clipboard (Pasteboard) specifying the above file format

INSTALLATION:   See http://tinyurl.com/install-as

REF:  The following were used in some way in the writing of this script.
  1.  How Do I Copy Image File to Clipboard and Retain Format?
      http://forum.latenightsw.com/t/how-do-i-copy-image-file-to-clipboard-and-retain-format/590
===============================================================================
   
*)

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

--- Primary Type (UTI) is Listed First ---
(*    NOTE:  If you wanted an alternate format, you could search list *)
set kMDKeyStr to "kMDItemContentTypeTree"

set filePath to POSIX path of (choose file with prompt ¬
  "Choose IMAGE file" of type ["public.image"])

set metaDataStr to getMetaData(filePath, kMDKeyStr)
set primaryType to item 1 of metaDataStr

--- READ FILE ---
set {nsFileContents, theError} to current application's NSData's dataWithContentsOfFile:filePath options:0 |error|:(reference)

--- GET REFERENCE TO CLIPBOARD ---
set theClip to current application's NSPasteboard's generalPasteboard()
theClip's clearContents()

--- PUT IMAGE DATA ON CLIPBOARD ---
theClip's setData:nsFileContents forType:primaryType

--- CHECK CLIPBOARD FOR ITEM TYPES ---
set clipList to theClip's (pasteboardItems()'s objectAtIndex:0)'s |types|() as list
set clipRec to the clipboard as record

set msgStr to "Type: " & primaryType
set msgTitleStr to "Image File Put on Clipboard"
display notification msgStr with title msgTitleStr sound name "Hero.aiff"

--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
on getMetaData(pPOSIXPath, pkMDKey)
  (*  VER: 1.0    2017-05-01
  --–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
  PURPOSE:  Get Value(s) of Spotlight Metadata for Given Key
  PARAMETERS:
    • pPOSIXPath    : POSIX path of file
    • pkMDKey        : Spotlight kMD Key Name
  RETURNS:  List of key values (even if only one value)
  
  AUTHOR:  JMichaelTX (heavy lifting by @ccstone)
  REQUIRES:  use framework "Foundation"

  REF:  Script by @ccstone with @ShaneStanley
          Jun 10, 2016
          Getting Individual Metadata Items with ASObjC
          https://lists.apple.com/archives/applescript-users/2016/Jun/msg00068.html
    --–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
    *)
  
  local curApp, nsPath, myNSURL, nsMetaItem, nsMDValue
  
  set curApp to current application
  
  set nsPath to curApp's NSString's stringWithString:pPOSIXPath
  
  --- EXPAND TILDE & SYMLINK (if any exist) ---
  set nsPath to nsPath's stringByResolvingSymlinksInPath()
  
  --- GET THE NSURL, WHETHER OR NOT THE FILE/FOLDER EXISTS ---
  set myNSURL to curApp's |NSURL|'s fileURLWithPath:nsPath
  
  --- GET THE SPOTLIGHT METADATA VALUE ---
  set nsMetaItem to current application's NSMetadataItem's alloc()'s initWithURL:myNSURL
  set nsMDValue to nsMetaItem's valueForAttribute:pkMDKey
  
  return (nsMDValue as list)
  
end getMetaData
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~