SwiftUI・UIKit・AppKitでの画像処理の煩わしさを解消するためのヒント

図を作ってみました。

Appleの異なる画像処理フレームワーク(SwiftUI、UIKit、AppKit)間で画像データをやり取りする際のフロー図を示しています。

この図が示しているように、iOS や macOS で画像を扱う場合、複数の異なるフレームワーク(SwiftUI、UIKit、AppKit)間での画像データのやり取りが必要となることがよくあります。

しかし、それぞれのフレームワークは異なる画像型(UIKit では UIImage、AppKit では NSImage など)を使っているため、これらを統一して操作するのは煩雑です。

処理の煩わしさは以下の点にあります:

 

🧑🏻‍💻 異なる画像型の存在

UIKit、AppKit、Core Graphics などの各フレームワークはそれぞれ独自の画像データ型(UIImageNSImageCGImage など)を使います。

異なる画像型を相互に変換する必要があり、そのための変換処理が増えてしまいます。

 

🧑🏻‍💻 変換処理の多さ

SwiftUI の Image コンポーネントに画像を渡すには、UIKit の UIImage や AppKit の NSImage などの形式に適切に変換する必要があります。

例えば、UIImage を SwiftUI に渡すために Image(uiImage:) を使う必要があり、AppKit の NSImage なら Image(nsImage:) を使います。このように、変換手順が異なり、統一感に欠けます。

 

🧑🏻‍💻 データ型の制約と互換性

画像データをファイル形式(例えば、PNG や JPEG)に変換したり、ネットワークで送信する場合、Data 型を使う必要があります。

そのため、 UIImage.pngData()NSBitmapImageRep.representation(using:properties:) のような変換処理を追加で行わなければなりません。

こうした一連の変換処理は単純な画像表示のために多くの余分なコードを必要とし、開発者にとって煩わしいと感じる要因です。

 

🧑🏻‍💻 フレームワーク間の相違点

UIKit は iOS 向け、AppKitは macOS 向けのフレームワークなので、同じアプリをクロスプラットフォームで開発する際に、これらのフレームワーク間の違いに対応しなければならず、異なる API や処理方法に習熟する必要があります。

総じて、このような画像の処理は、単純に画像を表示・変換・送信したいだけであっても多くの手順が必要となるため、効率的でないことが多いです。

これが処理の煩わしさにつながっています。

 

🧑🏻‍💻 SwiftUI

Image(uiImage:) または Image(nsImage:) を使って、それぞれ UIKit の UIImage または AppKit の NSImage を表示できます。

ImageRenderer(content:) を使って、 UIImage または NSImage を作成することが可能です。

 

🧑🏻‍💻 UIKit の UIImage

SwiftUI の Image や AppKit の NSImage との間で画像の相互変換が可能です。

UIImagepngData() でPNGフォーマットのデータに変換できますし、 UIImage(data:) でデータから画像を生成できます。

 

🧑🏻‍💻 AppKit の NSImage

AppKit では NSImage.cgImage() で Core Graphics の CGImage を取得でき、NSBitmapImageRep クラスを使って画像表現の変換が行われます。

NSBitmapImageRep を通じて、NSImage は、PNGなどの形式でエクスポート可能です。

 

🧑🏻‍💻 Core GraphicsのCGImage

UIKit の UIImage や AppKitの NSImage と互換性があり、それらを通じて画像を描画・変換する基盤を提供します。

 

🧑🏻‍💻 Foundation の Data

UIImageNSImage から変換したデータ(例:PNG)を保持するデータ型。

これにより、画像データをファイルとして保存したり、ネットワークを通じて送信したりできます。

 

🧑🏻‍💻 したかったこと

AsyncImage 内での画像データの比較です。



302 リダイレクト後の画像を確認しています。

 

🧑🏻‍💻 まとめ

SwiftUI、UIKit、AppKit での画像処理は、それぞれのフレームワークが異なる画像形式を扱っているため、煩雑に感じることが多いです。

しかし、正しい変換手法を使い、CGImage などを活用すれば互換性を確保できます。

さらに、最新の API を使いこなすことで、画像処理を効率的に行い、開発の手間を減らすことが可能です。

この記事で紹介したヒントを参考に、より快適な画像処理の開発を目指しましょう。


【SwiftUI】UIImage / NSImage の Image への抽象化

どちらが好きですか、以下2つのコード。

 

■ 1つ目


import SwiftUI

public extension Image {
    #if canImport(AppKit)
    init(image: NSImage) {
        self = Image(nsImage: image)
    }
    #endif

    #if canImport(UIKit)
    init(image: UIImage) {
        self = Image(uiImage: image)
    }
    #endif
}

特徴:
- 拡張機能 (extension) を使って、Imageに新しいinitイニシャライザを追加しています。
- プラットフォームごとに異なる型 (NSImageやUIImage) を直接引数に取ります。
- プラットフォーム依存の条件付きで、NSImage(macOS)またはUIImage(iOS)を使用してImageを初期化しています。

メリット:
- 各プラットフォームに対応したイニシャライザが個別に用意されており、Imageの初期化が直感的です。

デメリット
- プラットフォームごとにinitメソッドが別々に定義されているため、共通の型を扱うのが難しい。

 

■ 2つ目


#if canImport(AppKit)
import AppKit
public typealias PlatformImage = NSImage
#elseif canImport(UIKit)
import UIKit
public typealias PlatformImage = UIImage
#endif

import SwiftUI

extension Image {
    init(platformImage: PlatformImage) {
        #if canImport(UIKit)
        self = Image(uiImage: platformImage)
        #elseif canImport(AppKit)
        self = Image(nsImage: platformImage)
        #endif
    }
}

特徴:
- PlatformImageという型エイリアスを使って、macOSのNSImageとiOSのUIImageを抽象化しています。
- platformImageという共通の引数型を持つイニシャライザを追加しています。これにより、プラットフォームごとにImageを初期化しますが、型エイリアスによって共通化されています。

メリット:
- 抽象化されているため、呼び出し側のコードがプラットフォームに依存しません。つまり、共通のコードでPlatformImage型を使えば、iOSでもmacOSでも同じコードで動作します。
- 可読性が高く、メンテナンスが容易です。プラットフォームごとにメソッドを分ける必要がなく、1つのメソッドで対応しています。

デメリット:
- プラットフォームごとに異なる処理を追加する際に、多少複雑になる可能性があります。

 

■ まとめ

AIによると、

結論:どちらが良いか?

2つ目のコードの方が一般的に推奨されます。理由は、コードの抽象化によって、呼び出し側がプラットフォームに依存しない形でImageを扱うことができるためです。メンテナンス性が高く、同じコードベースで複数のプラットフォームをサポートしやすくなります。

ただし、プラットフォームごとに異なる処理が必要なケースでは、1つ目のコードの方が直感的に分かりやすい場合もあるので、状況に応じて選択が変わることがあります。

ということです。

私的には、どっちも勉強になります、としか。



【ffmpeg】VP9 コーデックから H.264 コーデックへの動画変換

YouTubeやGoogleフォトからダウンロードした動画は、他のサービスやツールでの利用が難しいことが多く、特に動画コーデックの互換性が問題となることがあります。特にVP9コーデックで圧縮された動画は、特定のプラットフォームやアプリでの再生がサポートされていない場合があります。したがって、VP9コーデックで圧縮された動画をH.264コーデックに変換することは、さまざまなデバイスやサービスでの利用を可能にするための重要なステップです。

👉 ffprobe vs mediainfo

 

🎬 VP9コーデックとは

VP9はGoogleが開発したオープンでロイヤリティフリーな動画圧縮コーデックであり、VP8の後継にあたります。このコーデックは、特に高解像度の動画配信に適しており、H.264に比べて同等の品質でファイルサイズを小さくすることが可能です。VP9はYouTubeやGoogleのストリーミングサービスで広く利用されており、その高い圧縮効率と画質が評価されています。しかし、一部のプラットフォームやデバイスでは、VP9を直接再生できないことがあり、この点がユーザーにとっての障壁となることがあります。

👉 VP9 - Wikipedia

 

🎬 H.264コーデックの利点

H.264は、現在最も広く使用されている動画圧縮コーデックの一つであり、様々なデバイスやプラットフォームでサポートされています。これにより、H.264でエンコードされた動画は、ほぼすべてのメディアプレーヤーやデバイスで再生可能であり、特にSNSやオンラインサービスにおいては、非常に高い互換性を誇ります。したがって、VP9からH.264への変換は、動画を広範に利用するために必要な手段と言えます。

 

🎬 変換方法

VP9コーデックからH.264コーデックへの変換は、FFmpegという強力なオープンソースの動画処理ツールを使用することで簡単に行えます。以下のコマンドをターミナルで実行することで、VP9で圧縮された動画をH.264形式に変換できます。


ffmpeg -i before.mov -y -vcodec libx264 -qp 0 -pix_fmt yuv420p -acodec copy after.mov


-i before.mov : 変換元の動画ファイルを指定します。
-y : 既存の出力ファイルを上書きすることを指示します。
-vcodec libx264 : 出力動画のコーデックをH.264(libx264)に指定します。
-qp 0 : 品質を最優先にする設定です。数字が小さいほど高品質になりますが、ファイルサイズも大きくなります。
-pix_fmt yuv420p : 出力動画のピクセルフォーマットを設定します。多くのデバイスでの再生互換性を確保するために、yuv420pが推奨されます。
-acodec copy : オーディオコーデックを変更せずに、元のオーディオをそのままコピーすることを意味します。

 

🎬 実際の利用例

この方法を使用することで、Instagramなどのプラットフォームに動画をアップロードできるようになります。動画の圧縮と変換を行うことで、質の高い動画を手軽に他のサービスで利用することが可能になります。また、これにより視聴者にとっても快適な再生体験を提供することができるでしょう。

 

🎬 まとめ

VP9からH.264への動画変換は、動画の互換性を向上させ、様々なプラットフォームでの利用を可能にするための有効な手段です。FFmpegを使用することで、手軽に高品質な動画を変換し、SNSやオンラインサービスでのシェアを促進できます。このように、動画の圧縮形式を変更することは、デジタルコンテンツの普及において非常に重要なプロセスです。


ffmpeg -i before.mov -c:a copy -c:v libx264 after.mov

これで Instagram にもアップできました!