1
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

クリップボードから画像を取得する

Last updated at Posted at 2020-06-23

NSPasteboardの基本

  • 【Apple】URL Reading Options
    • NSPasteboardに関する全体の話。ベースとしてここを参照しています。
    • ※ただしサンプルコードはObjective-Cです。

クリップボードからファイルのURLを取得

// ファイルパスがコピーされている場合を考える
let pasteboard = NSPasteboard.general

// NSImageの扱うUTIを指すfileURLのみ抽出する設定
// 具体的にはprint(NSImage.imageTypes)で確認できる
let classes = [NSURL.self]
let options: [NSPasteboard.ReadingOptionKey : Any] = [.urlReadingFileURLsOnly : true,
                                                      .urlReadingContentsConformToTypes : NSImage.imageTypes]

let canRead = pasteboard.canReadObject(forClasses: classes, options: options)
if canRead {
    let objectsToPaste = pasteboard.readObjects(forClasses: classes,
                                                options: options) ?? []
    
    if objectsToPaste.count > 0 {
        let fileURL = objectsToPaste[0] as! URL
        if let uti = uti(url: fileURL) {
            // 画像フォーマットを取得できる
            print(uti)  // e.g. UTI: Optional("public.png")
        }
        imageView.image = NSImage(contentsOf: fileURL)  // 出力して確認
    }
} else {
    print("クリップボードにファイルパスはありませんでした")
}

func uti(url: URL) -> String? {
    guard let r = try? url.resourceValues(forKeys: [.typeIdentifierKey]) else {
        return nil
    }
    return r.typeIdentifier
}

クリップボードから画像を取得

NSImageとして取得

  • NSImageのコンストラクタにNSPasteboardのインスタンスを渡すことができます。
// 画像がクリップボードにコピーされている場合
let pasteboard = NSPasteboard.general

if let image = NSImage(pasteboard: pasteboard) {
  imageView.image = image  // 出力して確認
} else {
  print("クリップボードに画像はありませんでした")
}
  • もし複数のクリップボードのアイテムを取得したい場合は、下記の通りobjectsToPasteを経由します。
    • 前述のreadObjectsforClassesNSImageと変えています。
// 画像がクリップボードにコピーされている場合
let pasteboard = NSPasteboard.general

let classes = [NSImage.self]
let options = [NSPasteboard.ReadingOptionKey : Any]()

let canRead = pasteboard.canReadObject(forClasses: classes, options: options)
if canRead {
    let objectsToPaste = pasteboard.readObjects(forClasses: classes,
                                                options: options) ?? []

    if objectsToPaste.count > 0 {
        let image = objectsToPaste[0] as! NSImage
        imageView.image = image  // 出力して確認
    }
} else {
    print("クリップボードに画像はありませんでした")
}

Dataを経由して取得(画像のフォーマット情報も取得できる)

  • NSPasteboardの機能をうまく利用すると、画像のフォーマット情報を取得することができます。
  • toolinbox/iPicUploader
    • ここのコードを参考にしました。サンプルプロジェクトからJump to Definitionを繰り返せば色々見れるはずです。
    • 今回私のコードはなるべく短くしています。きちんと書く場合は、クラスや関数の分け方を上記ソースから参考にすると良いと思います。
// クリップボードの内容を一旦全て取得する
guard let pasteboardItems = NSPasteboard.general.pasteboardItems else {
    return
}

var myImages = [MyImageInfo]()

for pasteboardItem in pasteboardItems {
    for type in pasteboardItem.types {
        if let data = pasteboardItem.data(forType: type) {
            if let image = NSImage(data: data) {
                myImages.append(MyImageInfo(image: image, uti: type))
            }
        }
    }
}

struct MyImageInfo {
    let image: NSImage
    let uti: NSPasteboard.PasteboardType
}
  • NSPasteboard.PasteboardType
    • しかし足りないものもあって、例えばjpg(public.jpeg)は定数で用意されていないから自分で用意しないといけないかもです。
print(NSPasteboard.PasteboardType.png.rawValue)  // public.png
  • StackOverflow等を検索すると、画像のバイナリの先頭数バイトを見て判断、というアイディアしか見つかりませんでした。
  • (ゴリゴリ系はあまり実装したくないですね)
  • 実際にHex Fiendでバイナリを確認してみると以下の通り。
image image image

デバッグ時の小ネタ

スクリーンショットの拡張子を変更する

  • デフォルトはpngですが下記の通り変更可能です。
defaults write com.apple.screencapture type jpeg

現在のクリップボードを確認する

  • Finderのメニューからクリップボードを表示から確認できます。
  • 拡張子も確認できるので、デバッグ時のお供に。
image

NSImageのUTIを確認する

let utis = NSImage.imageTypes
for uti in utis {
    print(uti)
}
com.adobe.pdf
com.apple.pict
com.adobe.encapsulated-postscript
public.jpeg
public.png
com.compuserve.gif
com.canon.tif-raw-image
com.adobe.raw-image
com.dxo.raw-image
com.canon.cr2-raw-image
com.canon.cr3-raw-image
com.leafamerica.raw-image
com.hasselblad.fff-raw-image
com.hasselblad.3fr-raw-image
com.nikon.raw-image
com.nikon.nrw-raw-image
com.pentax.raw-image
com.samsung.raw-image
com.sony.raw-image
com.sony.sr2-raw-image
com.sony.arw-raw-image
com.epson.raw-image
com.kodak.raw-image
public.tiff
public.jpeg-2000
com.apple.atx
org.khronos.astc
org.khronos.ktx
public.avci
public.heic
public.heics
public.heif
com.canon.crw-raw-image
com.fuji.raw-image
com.panasonic.raw-image
com.panasonic.rw2-raw-image
com.leica.raw-image
com.leica.rwl-raw-image
com.konicaminolta.raw-image
com.olympus.sr-raw-image
com.olympus.or-raw-image
com.olympus.raw-image
com.phaseone.raw-image
com.microsoft.ico
com.microsoft.bmp
com.apple.icns
com.adobe.photoshop-image
com.microsoft.cur
com.truevision.tga-image
com.ilm.openexr-image
com.sgi.sgi-image
public.radiance
public.pbm
public.mpo-image
public.pvr
com.microsoft.dds
1
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?