ブラーでぼかすけど膨らませない方法(SwiftUI)

## はじめに

本記事は [SwiftWednesday Advent Calendar 2023](https://qiita.com/advent-calendar/2023/swift-wednesday) の8日目の記事です。
昨日は @startaiyo さんでした。

SwiftUIのブラーでぼかすけど膨らませない方法を紹介します。

## 環境

- OS：macOS Sonoma 14.0（23A344）
- Swift：5.9

## 問題

64×64の正方形を横に3つ並べます。

```swift:ContentView.swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack(spacing: 4) {
            Rectangle()
                .fill(.red)
                .frame(width: 64, height: 64)
            
            Rectangle()
                .fill(.green)
                .frame(width: 64, height: 64)
            
            Rectangle()
                .fill(.blue)
                .frame(width: 64, height: 64)
        }
    }
}
```

![スクリーンショット 2023-12-06 22.32.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138245/e0c464cf-fefd-7da6-fe9d-60ec63df32d8.png)

これらの正方形に半径16のブラー（ [`blur(radius:opaque:)`](https://developer.apple.com/documentation/swiftui/view/blur(radius:opaque:)) ）をかけます。

```diff_swift:ContentView.swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack(spacing: 4) {
            Rectangle()
                .fill(.red)
                .frame(width: 64, height: 64)
+               .blur(radius: 16)
            
            Rectangle()
                .fill(.green)
                .frame(width: 64, height: 64)
+               .blur(radius: 16)
            
            Rectangle()
                .fill(.blue)
                .frame(width: 64, height: 64)
+               .blur(radius: 16)
        }
    }
}
```

![スクリーンショット 2023-12-06 22.37.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138245/913f7a9b-6403-00ec-485f-a69285c6bdeb.png)

正方形全体がぼけましたが、64×64の領域を越えて描画されています。
領域内に収めてぼかす方法はないでしょうか？

## 解決策

当たり前かもしれませんが、 [`clipShape(_:style:)`](https://developer.apple.com/documentation/swiftui/view/clipshape(_:style:)) を使って元の図形と同じ形に切り抜きます。

```diff_swift:ContentView.swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack(spacing: 4) {
            Rectangle()
                .fill(.red)
                .frame(width: 64, height: 64)
                .blur(radius: 16)
+               .clipShape(Rectangle())
            
            Rectangle()
                .fill(.green)
                .frame(width: 64, height: 64)
                .blur(radius: 16)
+              .clipShape(Rectangle())
            
            Rectangle()
                .fill(.blue)
                .frame(width: 64, height: 64)
                .blur(radius: 16)
+               .clipShape(Rectangle())
        }
    }
}
```

![スクリーンショット 2023-12-06 22.47.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138245/9120a9c0-1b1f-9310-2baf-55b53d8493d7.png)

これで元の図形のままブラーをかけることができました。

## おまけ: ブラーで縁を薄くしない方法

今回紹介した方法だと、正方形の縁が円状に薄くなってしまいます。
縁を薄くせずにぼかす方法はないでしょうか？

SwiftUI単体ではできなさそうですが、 [Core Image](https://developer.apple.com/documentation/coreimage) を使うと縁を薄くせずにぼかすことができるようです。

https://iosexample.com/hundreds-of-core-image-filters-wrapped-as-ciimage-modifiers-for-easy-integration-with-swiftui/

## おわりに

今回はただの正方形で試しましたが、画像をぼかす際に有用となるテクニックだと思います :relaxed:

以上 [SwiftWednesday Advent Calendar 2023](https://qiita.com/advent-calendar/2023/swift-wednesday) の8日目の記事でした。
明日も @uhooi です。