環境
Swift5
SwiftUI
Xcode11.5
実現すること
SwiftUIフレームワークを使って、任意の画像に図形を合成する。本記事では、このかわいい犬を円の図形で囲むようにします。
実装
ComposedImageModel.swift
が以下になります。
ComposedImageModel.swift
import Foundation
import UIKit
struct ComposedImageModel {
// 犬の画像格納用
var image: UIImage
// CAShapeLayer画像格納用
var layerImage: UIImage
// 合成した画像格納用
var composedImage: UIImage
init() {
self.image = UIImage()
self.layerImage = UIImage()
self.composedImage = UIImage()
}
}
次に以下ComposedImageViewModel.swift
でUIImageを合成する処理を記載していきます。
[主な処理]
- 犬の画像を格納
- CAShapeLayerを使って円形の図形を作成 > UIImageにレンダリング
- 上記2つの画像を1つの画像に合成
ComposedImageViewModel.swift
import Foundation
import UIKit
class ComposedImageViewModel {
var composedImageModel: ComposedImageModel
init() {
self.composedImageModel = ComposedImageModel()
composedImages()
}
// 2つのUIImageを1つのUIImageに合成
private func composedImages() {
// いっぬの画像を取得
self.composedImageModel.image = UIImage(named: "dog")!
// CAShapeLayerと使って円形を描画
let calayer = CAShapeLayer()
let size = self.composedImageModel.image.size
calayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
calayer.path = UIBezierPath(ovalIn: CGRect.init(x: size.width/2 - size.height/2, y: 0, width: size.height, height: size.height)).cgPath
calayer.fillColor = UIColor.clear.cgColor
calayer.strokeColor = UIColor.black.cgColor
// 円形のCAShapeをUIImageにレンダリング
UIGraphicsBeginImageContextWithOptions(calayer.frame.size, false, 1)
let context = UIGraphicsGetCurrentContext()!
calayer.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.composedImageModel.layerImage = image!
// いっぬのUIImageとレンダリングされた円形のUIImageを合成
UIGraphicsBeginImageContext(CGSize(width: size.width, height: size.height))
self.composedImageModel.image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
self.composedImageModel.layerImage.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
self.composedImageModel.composedImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
}
}
次に以下ComposedImageView.swift
で比較できるように
- 犬のUIImage
- CAShapeLayerから作成した円形のUIImage
- 上記2つを合成したUIImage
を表示します。CAShapeLayerのUIImageに関しては、サイズの大きさがわかりやすいように意図的に背景を赤くして表示しています。
ComposedImageView.swift
import SwiftUI
struct ComposedImageView: View {
private var imageVM = ComposedImageViewModel()
var body: some View {
VStack {
// いっぬのImageを表示
Image(uiImage: self.imageVM.composedImageModel.image)
// CAShapeからレンタリングしたImageを表示
Image(uiImage: self.imageVM.composedImageModel.layerImage)
.background(Color.red)
// 上記二つのImageを合成したImageを表示
Image(uiImage: self.imageVM.composedImageModel.composedImage)
}
}
}
struct ComposedImageView_Previews: PreviewProvider {
static var previews: some View {
ComposedImageView()
}
}
ContentView.swift
にComposedImageView
を記載して、表示させる。
ContentView.swift
import SwiftUI
struct ContentView: View {
var body: some View {
ComposedImageView()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
シミュレーター又は実機で実行
これまで作成した画像が、以下のように表示されます。

所感
自作アプリを作成している段階で、撮影した写真のUIImageと合成した図形の位置関係でごちゃごちゃしたので、本記事でまとめさせてもらいました。
(*短足でかわいいよね)
参考文献
SwiftUIでMVVM
http://sinnderu.hatenablog.com/entry/2019/12/22/133157
【Swift4】UIViewをUIImageに変換し、画像としてカメラロールに保存する方法
https://program-life.com/410