SwiftUI

SwiftUI 사진 가져오기(3)

Daesiker 2021. 3. 20. 15:12
반응형

swiftUI 사진 가져오기(1)

swiftUI 사진 가져오기(2)

 


macOS

macOS에서 프로젝트를 실행할 때 사용하는 소스코드이다. 앞서 말했듯이 Target을 OS에 맞게 설정하고 소스파일 제목 제일 끝에 "_(원하는 OS)"를 적으면 자동으로 인식한다.

NSUIImage_macOS

import AppKit
import SwiftUI

public typealias NSUIImage = NSImage

extension NSUIImage {
  var data: Data? {
    //비트맵 이미지 데이터
    return self.tiffRepresentation
  }

  static func image(fromData data: Data) -> Image {
    return Image(nsImage: NSImage(data: data) ?? NSImage())
  }
}

AppKit과 swiftUI를 import한다. AppKit은 UIKit이랑 비슷하다고 생각하면된다. AppKit에서 iOS에서도 사용가능한 소스와 iOS에서만 사용가능한 소스를 합친 프레임워크가 UIKit이다. macOS에서 프로젝트를 작성할 때는 UIKit대신에 AppKit 프레임워크를 사용하면 된다.

 

iOS와 마찬가지로 typealias 키워드를 사용하여 NSUIImage를 macOS에서 이미지 데이터를 사용할 때 사용하는 NSImage로 바꾸어 주고 extension을 통해 새로운 변수와 함수를 추가한다.

 

앞서 받은 data를 NSImage로 인식하기 위해 tiffRepresentation을 통해 비트맵 이미지 데이터로 변환을 한다. 그리고 image 함수를 사용하여 NSImage로 바꾼 뒤에 NSImage를 SwiftUI에 Image 컴포넌트에 넣는다.

 

NSOpenPanelExtension

NSOpenPanel은 macOS 파일시스템에 접근하여 파일을 가져올 때 사용한다. iOS에서 ImagePicker을 통해 사진 App에 접근하여 사진을 가져오는 것처럼 여기서도 NSOpenPanel을 통해 파일을 가져온다.

import SwiftUI

extension NSOpenPanel {
    // Image 가져오기 실패 시 사용
  enum ImageError: Error {
    case selectionFailed
  }

  static func openImage(completion: @escaping (_ result: Result<NSImage, Error>) -> Void) {
    let panel = NSOpenPanel()
    //다중 선택가능?
    panel.allowsMultipleSelection = false
    //파일 선택가능?
    panel.canChooseFiles = true
    //폴더 선택가능?
    panel.canChooseDirectories = false
    //가져올 수 있는 파일형식
    panel.allowedFileTypes = ["jpg", "jpeg", "png", "heic"]
    //열기 눌렀을 때
    panel.begin { result in
      guard
        result == .OK,
        let url = panel.urls.first,
        let image = NSImage(contentsOf: url)
      else {
        completion(.failure(ImageError.selectionFailed))
        return
      }
      completion(.success(image))
    }
  }
}

먼저 이미지 선택에 실패할 경우를 대비해서 ImageError라는 enum값을 생성한 후 케이스를 하나 추가한다.

그 다음에 openImage라는 함수를 만들어서 NSOpenPanel을 어떻게 사용할건지 구성한다. 우선 NSOpenPanel을 panel 상수에 받은 뒤에 속성을 지정한다.

 

  • allowsMultipleSelection(Boolean) : 파일을 여러개 선택이 가능한지 설정한다.
  • canChooseFiles(Boolean) : 파일을 열 수 있는지 설정한다.
  • canChooseDirectories(Boolean) : 폴더를 열 수 있는지 설정한다.
  • allowedFileTypes[String] : 열 수 있는 파일 형식이 어떤것이 있는지 정의한다.
  • begin(Void → completion) : 열기를 눌렀을 때의 결과에 대해 어떤 함수를 실행할 껀지 정의한다.

 

여기서는 파일을 선택하고 열기 버튼을 누르면 결과 값을 확인하고 OK이면 해당 파일 경로 URL을 NSImage로 바꾸어서 반환해주고 실패하면 ImageError.selectionFailed를 반환한다.

 

MemeEditor_macOS.swift

이제 앞서 만든 기능들을 추가해서 UI작성을 하면된다.

import SwiftUI

struct MemeEditor: View {
  @Binding var meme: Meme

  func selectImage() {
    NSOpenPanel.openImage { result in
      guard case let .success(image) = result else { return }
      meme.imageData = image.data
    }
  }

  var body: some View {
    VStack {
      if meme.imageData != nil {
        TextLayer(meme: $meme) {
          ImageLayer(imageData: $meme.imageData)
        }
      }

      Button(action: selectImage) {
        Text("Add Image")
      }
      .padding()
    }
    .frame(minWidth: 500, minHeight: 500)
  }
}

meme의 imageData가 nil일 때 버튼이 생성되고 그 버튼을 클릭하면 selectImage()가 실행된다. selectImage에는 아까 만든 NSOpenPanel의 openImage가 실행되고 성공적으로 파일이 열리면 meme.imageData에 새로운 이미지 데이터를 넣어준다.

 


ContentView

import SwiftUI

struct ContentView: View {
  @Binding var document: MemeMakerDocument

  var body: some View {
    MemeEditor(meme: $document.meme)
  }
}

앞서만든 MemeMakerDocument를 바인딩하고 MemeEditor을 View로 가져와서 파라미터로 document.meme를 받고있다.

MemeMakerApp.swift

마지막으로 App의 시작점인 MemeMakerApp만 남았다.

import SwiftUI

@main
struct MemeMakerApp: App {
  var body: some Scene {
    DocumentGroup(newDocument: MemeMakerDocument()) { file in
      ContentView(document: file.$document)
    }
  }
}

문서 열기, 만들기 및 저장을 지원하는 DocumentGroup안에 앞서 만든 ContentView를 넣으면서 App이 마무리된다.

 

반응형

'SwiftUI' 카테고리의 다른 글

SwiftUI Binding, Environment  (0) 2021.03.31
SwiftUI Profile View  (0) 2021.03.30
SwiftUI 사진 가져오기(2)  (0) 2021.03.19
SwiftUI 사진 가져오기(1)  (2) 2021.03.17
SwiftUI TabView  (1) 2021.03.02