[SwiftUI][Image] イメージ処理アプリを作る(4)

SwiftUI

SwiftUI を使った イメージ処理アプリを作ってみます

環境&対象

以下の環境で動作確認を行なっています。

  • macOS Big Sur 11.1
  • Xcode 12.3

本シリーズ内容

SwiftUI を使って、イメージ処理するアプリを作ります。

以下の理解が進むことがゴールです。

  • SwiftUI を使ったアプリ開発
  • NSImage を使った画像処理全般
  • Photos 拡張編集機能 と SwiftUI app の組み合わせ方
  • イメージ処理アプリも TDD で進めることが可能かどうか
  • その他 macOS app 開発 Tips

この記事で作る範囲

最初に、画像の上にメガネを重ねて表示することができました。

その後、メガネをドラッグすることで 位置変更できるようにし、追加で、サイズ変更もできるようにしてきました。

今回は、別の画像の上にメガネを重ねることができるようにします。

一言で言うと、別画像のファイルをドロップすることで、画像を入れ替える機能をつけます。

  • 画像ファイルをドロップされたら、その写真を表示する

写真をドロップできるようにする

やること

写真ファイルをドロップすると、その画像を表示できるようにします。

ドロップされる要素への対応は、SwiftUI では onDrop で行うことができます。

テスト

テストが難しいです。

実装機能はシンプルなのですが、外部からファイルをドロップする方法がわかりません・・・・・

Finder で新規ウィンドウを開くことまではできるようになったのですが、特定のフォルダまで移動できないので、ドロップできるファイルまで辿り着けません。

# 方法がわかったら この記事をアップデートします。

なので、今回はテストコードは無しです。
手動でテストすることとします。

テスト項目は、以下を想定します。
「画像ファイル(JPG)をドロップしたら、置き換わる」
「画像ファイル(PNG)をドロップしたら、置き換わる」
「画像でないファイルをドロップしたら、無視される」

アプリ実装

以前の記事でも説明しています。

[SwiftUI] SwiftUIのビュー上へのドロップの実装

UITest を作るのは難しいですが、アプリの実装自体は簡単です。

ContentView

//
//  ContentView.swift
//
//  Created by : Tomoaki Yagishita on 2021/01/19
//  © 2021  SmallDeskSoftware
//

import SwiftUI
import UniformTypeIdentifiers

struct MainView: View {
    @State private var image:NSImage = NSImage(named: "initialPhoto")!
    @State private var isTargeted = false

    var body: some View {
        ZStack {
            Image(nsImage: image).resizable().scaledToFit().frame(width: 500, height: 500)
                .accessibility(identifier: "mainImage")
                // (1)
                .onDrop(of: [UTType.fileURL], isTargeted: $isTargeted) { (providers) -> Bool in
                    guard let provider = providers.first else { return false } // handle first item only
                    // (2)
                    provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil) { (url, error) in
                        // (3)
                        DispatchQueue.main.async {
                            if let url = url as? Data {
                                // (4)
                                let imageURL = NSURL(absoluteURLWithDataRepresentation: url, relativeTo: nil) as URL
                                if let localImage = NSImage(contentsOf: imageURL) {
                                    // (5)
                                    image = localImage
                                }
                            } else if let error = error {
                                print(error)
                            }
                        }
                    }
                    return true
                }
            GlassImage()
        }
        .padding()
    }
}
コード解説
  1. .onDrop modifier でドロップを受け取ります
  2. NSItemProvider の loadItem を使って、ドロップされた情報を受け取ります
  3. UI 更新が必要となるため、main キューで操作します
  4. ファイルの URL が渡されるので、そこから NSImage を作ります
  5. NSImage を作ることができたら、表示イメージにセットします

この記事でできたこと

  • イメージのファイルをドロップすることで、画像を置き換える

現在のアプリ

以下のような動作です。

次回

次回以降は 現在の機能を Photos の拡張機能としても使えるようにアプリを変更していきます。

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です