ページ

2008年1月14日月曜日

FireFoxから画像をドラッグ&ドロップして保存する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前回 NSDraggingInfo の namesOfPromisedFilesDroppedAtDestination:dropLocation を使いSafariで画像を保存することができたが、FireFoxではできなかった。いろいろ調べた結果、Pasteboard Managerを使えばできることがわかった。

サンプル
sp1.zip

方法は Pasteboard.h に記述されていた。


/* From: Pasteboard.h - "Pasteboard File Promising"
*
* Order of operations on copy or drag
*
* 1) The sender promises kPasteboardTypeFileURLPromise for a file yet to be created.
* 2) The sender adds kPasteboardTypeFilePromiseContent containing the UTI describing
* the file's content.
*
* Order of operations on paste or drop
*
* 3) The receiver asks for kPasteboardTypeFilePromiseContent to decide if it wants the file.
* 4) The receiver sets the paste location with PasteboardSetPasteLocation.
* 5) The receiver asks for kPasteboardTypeFileURLPromise.
* 6) The sender's promise callback for kPasteboardTypeFileURLPromise is called.
* 7) The sender uses PasteboardCopyPasteLocation to retrieve the paste location, creates the file
* and keeps its kPasteboardTypeFileURLPromise promise.
*/


受取側で 3), 4) 5) を行えば Firefoxからドラッグした画像ファイルを任意のフォルダに作成することができる。
コードはこんな感じ(ポイントのみ抜粋)。


// 3) The receiver asks for kPasteboardTypeFilePromiseContent to decide if it wants the file.
PasteboardCopyItemFlavorData(pboard, item_id, kPasteboardTypeFilePromiseContent, &flavor_data);

// 4) The receiver sets the paste location with PasteboardSetPasteLocation.
err = PasteboardSetPasteLocation(pboard, url);

// 5) The receiver asks for kPasteboardTypeFileURLPromise.
PasteboardCopyItemFlavorData(pboard, item_id, kPasteboardTypeFileURLPromise, &flavor_data);


最初に kPasteboardTypeFilePromiseContent を要求して(3)、次にファイルの保存場所を PasteboardSetPasteLocationで指定する。そして最後に kPasteboardTypeFileURLPromiseを要求するとファイルが作成される。


FireFoxの場合、5)の結果は badPasteboardFlavorErr(-25133:item flavor does not exist)が返る。一方 Safariでは保存ファイルのURLが flavor_dataに返る。


(FireFoxの場合の実行ログ)
2008-01-14 18:14:00.578 sp1[29834:10b] PasteboardCopyItemFlavorData: err=0
2008-01-14 18:14:00.578 sp1[29834:10b] flavor_data=<64796e2e>
2008-01-14 18:14:00.579 sp1[29834:10b] PasteboardSetPasteLocation: err=0
2008-01-14 18:14:00.623 sp1[29834:10b] PasteboardCopyItemFlavorData: err=-25133

(Safariの場合の実行ログ)
2008-01-14 18:00:56.273 sp1[29795:10b] PasteboardCopyItemFlavorData: err=0
2008-01-14 18:00:56.274 sp1[29795:10b] flavor_data=<7075626c>
2008-01-14 18:00:56.274 sp1[29795:10b] PasteboardSetPasteLocation: err=0
2008-01-14 18:00:56.277 sp1[29795:10b] PasteboardCopyItemFlavorData: err=0
2008-01-14 18:00:56.279 sp1[29795:10b] flavor_data=<66696c65>......



3)で得られる flavor_dataも上記のように FireFoxと Safariで異なる。FireFoxは "dyn.ah62d4rv4gk8u" という文字列でこれは動的UTIを表す。一方 Safariは "public.jpeg"(これも UTI)を返す。

FireFoxの場合、ファイル名を取得するには別途 URLタイプのデータを Pasteboardから取り出す必要がある(サンプルは取り出している)。

- - - -
Finder が実現できているので何か方法はあるかと思ったが調べてもなかなか情報が集まらない。
その上、Cocoaの情報は見つからず Carbonや Drag Manager、Scrap Manager などがでてきて、一時は無理かと思った。
さんざん時間がかかったあげく最終的にはヒントが身近なところ(Pasteboard.h)にあって方法もあっけなかった。やれやれ。
まあとりあえず良かった。


(付録)16進数文字列を文字に変換する
ruby のpackを使うと簡単にできる。

例:
p ["7075626c69632e6a706567"].pack("H*")
=> "public.jpeg"