How to paste an NSImage correctly from NSPasteboard?
Asked Answered
T

2

5

Ok, Here's the code I'm using :

if let image = NSImage(pasteboard: pasteboard){
    //..
}

And I have 3 ways where images come into the app:

  1. If the image is dragged to the window, and using the dragging pasteboard, the image is correct.
  2. If the image is copied in browser, "Copy Image".. and using NSPasteboard.general().. The image is pasted correctly.
  3. If the image is copied in Finder, right click -> Copy "image-name.jpg". then the pasted image is NOT correct. Instead I get the icon for JPEG file type.

I tried other methods, including apple's snippet (same result, I get icon instead of the image itself) :

NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
NSArray *classArray = [NSArray arrayWithObject:[NSImage class]];
NSDictionary *options = [NSDictionary dictionary];

BOOL ok = [pasteboard canReadObjectForClasses:classArray options:options];
if (ok) {
    NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options];
    NSImage *image = [objectsToPaste objectAtIndex:0];
    [imageView setImage:image];
}
Trumpery answered 19/2, 2017 at 0:10 Comment(0)
C
9

The pasteboard does contain a path to the file, which you can use it to load the image from disk:

func paste(_ sender: AnyObject) {
    let pasteboard = NSPasteboard.general()

    if let data = pasteboard.data(forType: kUTTypeFileURL),
        let str =  String(data: data, encoding: .utf8),
        let url = URL(string: str),
        let image = NSImage(contentsOf: url)
    {
        imageView.image = image
    }
}
Chopfallen answered 19/2, 2017 at 1:0 Comment(3)
Yes this works perfectly. Any ideas if there's an official definition for "public.file-url" somewhere? It seems the documentations are lacking such detail of how pasteboard actually works.Trumpery
There's actually a constant for that: kUTTypeFileURL (documentation) I got that value by examining the pasteboard items in the debuggerChopfallen
Your implementation is a bit roundabout: let filenameURL = NSURL(from: pasteboard) as URL? saves on the intermediate steps. (Alas, there is no way to get a URL directly from a pasteboard.)Rokach
P
3

That's because the Finder isn't copying an image, it's copying a file item. The primary representation of this is a URL, but another representation is the file icon. None of the representations are the content of the file (i.e. the JPEG image).

You could first check if the pasteboard can provide a URL and create the image from the URL. Only if that fails try creating an image directly from the pasteboard.

Alternatively, you could enumerate the pasteboardItems, which would give you them in the order that the source app thinks is most relevant. Stop at the first which is either a URL to an image file or image data.

Pled answered 19/2, 2017 at 0:51 Comment(1)
Thanks for the explanation. This was very helpfulTrumpery

© 2022 - 2024 — McMap. All rights reserved.