CIFilterをかけた画像を保存するアプリ。
ファイル保存のウィンドウNSSavePanelを表示したいが、ネットで調べたコードじゃエラーが出て表示されない。
わかったのは、最近Sandboxという仕組みになり、そのせいでファイルの扱いがReadOnlyになっていたのだ。
TARGETSのCapabilities / App Sandbox / File Access / User Selected File のPermission & Accessを、Read Only → Read/Write に変更してやったら(App SandboxのボタンがOFFになる)NSSavePanelが表示され、画像の保存もできた。
めんどっちーね。
なお、User Selected FileがRead/Writeになっていれば、App SandboxのボタンをONにしても保存できるようだ。やっていいのかどうかしらんけど。
Sandboxとはなんぞや?
どうやら砂場を意味していて、子供をその中で遊ばせときゃ安全…という概念で、プログラムを保護された環境下で動作させるものだという。(マイナビニュースより)
公式には以下のように書かれている。
macOSのApp Sandboxは、アプリケーションが意図された動作だけを行うようにする機能です。アプリケーションのサンドボックス化は、アプリケーションをあなたのMacの重要なシステムコンポーネント、あなたのデータ、そしてほかのアプリケーションから分離させます。もしアプリケーションに悪意のあるソフトウェアが含まれていたとしても、サンドボックス化が自動的にそれをブロックするので、あなたのコンピュータと情報は守られます。macOSでは、内蔵されたPDFビューアや、Adobe Flash Player、Silverlight、QuickTime、Oracle Javaなどのプラグインをサンドボックス化することで、Safariにサンドボックス保護機能を持たせています。さらにmacOSは、メール、メッセージ、FaceTime、カレンダー、連絡先、写真、メモ、リマインダー、Photo Booth、クイックルックプレビュー、Game Center、辞書、Font Book、Mac App Storeなどのアプリケーションもサンドボックス化します。
コード(クロージャ内で保存する場合)
勉強のためにいろいろ余計なプロパティも設定してみたが、こんな感じ。
savePanelの表示と一緒に、保存処理するクロージャを設定する場合。
//画像保存
@IBAction func saveImage(_ sender: Any) {
let saveImage = myImageView.image
let savePanel = NSSavePanel()
savePanel.title = "画像保存だってよ" //表示されない?
savePanel.prompt = "保存" //デフォルトボタンのテキスト
savePanel.nameFieldLabel = "名前:" //ファイル名入力欄の左に表示されるテキスト
savePanel.nameFieldStringValue = "名称未設定" //デフォルトファイル名
savePanel.message = "画像を保存します" //ウィンドウ上部に表示される
savePanel.message = "画像を保存します" //ウィンドウ上部に表示される
savePanel.canCreateDirectories = true //フォルダ新規作成ボタン表示
savePanel.showsHiddenFiles = false //隠しファイルの表示
savePanel.showsTagField = true //タグ付のフィールド表示有無
savePanel.tagNames = ["画像","旅行"] //デフォルト表示するタグ
savePanel.isExtensionHidden = true //「拡張子を隠す」ボタン。Finder設定で表示になってると機能しない
let downloadPath = NSHomeDirectory() + "/Downloads" //Download[s]なので注意
savePanel.directoryURL = URL(fileURLWithPath: downloadPath) //デフォルト表示のフォルダ
savePanel.canSelectHiddenExtension = false //falseだとウィンドウ中のファイルが薄く表示される。選択はできる
savePanel.allowedFileTypes = ["jpg","gif","png"] //許可するファイルタイプ(先頭の拡張子がデフォルトファイル名に付く)
savePanel.allowsOtherFileTypes = false //許可されたファイルタイプ以外の許可(デフォルト不許可)
savePanel.treatsFilePackagesAsDirectories = false //アプリみたいなファイルパッケージの中までディレクトリとして表示するか否か
savePanel.begin { (result) in
if result == NSApplication.ModalResponse.OK {
guard let tiffData = saveImage?.tiffRepresentation, //画像をTIFFのDataにする
let imageRep = NSBitmapImageRep(data: tiffData), //bitmapデータを描画?
let imageData = imageRep.representation(using: .jpeg, properties: [.compressionFactor : NSNumber(floatLiteral: 0.7)]) //JPEGに変換
else {
print("画像変換エラー")
return
}
//画像保存処理
do {
try imageData.write(to: savePanel.url!)
} catch {
print("保存エラー \(error)")
}
}
}
}
コード(delegateメソッド内で保存処理する場合)
savePanelは表示だけさせて、「保存」ボタンが押されたらdelegateメソッドで処理する場合。
//画像保存
@IBAction func saveImage(_ sender: Any) {
let saveImage = myImageView.image
let savePanel = NSSavePanel()
savePanel.title = "画像保存だってよ" //表示されない?
savePanel.prompt = "保存" //デフォルトボタンのテキスト
savePanel.nameFieldLabel = "名前:" //ファイル名入力欄の左に表示されるテキスト
savePanel.nameFieldStringValue = "名称未設定" //デフォルトファイル名
savePanel.message = "画像を保存します" //ウィンドウ上部に表示される
savePanel.canCreateDirectories = true //フォルダ新規作成ボタン表示
savePanel.showsHiddenFiles = false //隠しファイルの表示
savePanel.delegate = self
savePanel.showsTagField = true //タグ付のフィールド表示有無
savePanel.tagNames = ["画像","旅行"] //デフォルト表示するタグ
savePanel.isExtensionHidden = true //「拡張子を隠す」ボタン。Finder設定で表示になってると機能しない
let downloadPath = NSHomeDirectory() + "/Downloads" //Download[s]なので注意
savePanel.directoryURL = URL(fileURLWithPath: downloadPath) //デフォルト表示のフォルダ
savePanel.canSelectHiddenExtension = false //falseだとウィンドウ中のファイルが薄く表示される。選択はできる
savePanel.allowedFileTypes = ["jpg","gif","png"] //許可するファイルタイプ(先頭の拡張子がデフォルトファイル名に付く)
savePanel.allowsOtherFileTypes = false //許可されたファイルタイプ以外の許可(デフォルト不許可)
savePanel.treatsFilePackagesAsDirectories = false //アプリみたいなファイルパッケージの中までディレクトリとして表示するか否か
savePanel.runModal() //savePanelの表示
}
//savePanelで保存ボタンを押した際に呼ばれるDelegateメソッド
func panel(_ sender: Any, validate url: URL) throws {
let saveImage = myImageView.image
guard let data = saveImage?.tiffRepresentation,
let imageRep = NSBitmapImageRep(data: data),
let imageData = imageRep.representation(using: .jpeg, properties: [.compressionFactor : NSNumber(floatLiteral: 0.7)])
else {
print("なんかエラーっす")
return
}
do {
try imageData.write(to: url)
} catch {
print("保存エラー \(error)")
}
}
プロパティはだいたいこんな感じ |
問題点
savePanelのローカライズが不完全。プロパティで設定したところしか日本語化されない。
savePanelの下の方に保存するファイル形式(jpeg, gif, pngとか)を選ぶポップアップメニューを表示したいけど、やり方がわからん。
0 件のコメント:
コメントを投稿