エンジニアだとMarkdownを使ったりとかSlackでコミュニケーションしたりとか頻繁にしますよね。そこで手軽にアニメーションを共有する手段としてGIFアニメが大変便利なため重宝しますよね!私もGIFアニメよく使うのですが、QuickTime Playerで画面録画をしたmovファイルをGIFに変換するのってみなさんどんな手段でやってますか?
macでGIFアニメを手軽に作るアプリとしては、PicGIFが有名ですが、画像の縦横サイズの編集が手軽にしづらかったり、繰り返し再生回数を指定できなかったり(とりわけ無限ループにできない)、各コマのalignmentが調整できなかったり、GIFのトリミングができなかったり、痒いところに手が届かないと感じていました。また、Effectや文字列追加機能は不要だと思っていたため、必要十分な機能のアプリを作ることにしました。
GIFlash
特徴
- 複数のコマ画像をインポートしてパラパラ漫画を作れる
- 動画からコマ画像を切り出してインポートできる
- 繰り返し再生(ループ)の回数を指定できる
- GIFアニメのサイズの変更が容易
(アスペクト比をロックして拡大縮小できる) - サイズの異なるリソースを用いる場合、中央揃えや右寄せ、上寄せなど配置の指定ができる
- 背景色の指定ができる(透明も可)
- 既存のGIFアニメのトリミングができる
- 編集中の各コマをPNGとして出力できる
技術的な話
NSImageの配列からGIFを作って保存する方法
-
CGImageDestinationなんたら
をつかっていく。 - 繰り返し回数は0を指定すると無限ループになる
-
kCGImagePropertyGIFDelayTime
という属性とkCGImagePropertyGIFUnclampedDelayTime
という属性があるが、前者だとフレーム間隔の最小が100msまでしか指定できない。後者を選ぶともっと間隔を短くできる。
import Cocoa
import ImageIO
var frames = [CGImage]() // フレームを追加しておく
func generateGif(_ saveURL: URL, // NSSavePanelとかでユーザに保存場所を指定させる
_ loopCount: Int, // 繰り返し再生回数
_ interval: Float, // フレーム間隔
successHandler: () -> Void,
failureHandler: () -> Void) {
guard 0 < frames.count,
let gif = CGImageDestinationCreateWithURL(saveURL as CFURL, kUTTypeGIF, frames.count, nil)
else { return failureHandler() }
// 繰り返し再生回数の指定
let props = [
(kCGImagePropertyGIFDictionary as String) : [(kCGImagePropertyGIFLoopCount as String) : loopCount]
]
CGImageDestinationSetProperties(gif, props as CFDictionary)
// フレーム間隔の指定
let frameProps = [
(kCGImagePropertyGIFDictionary as String) : [(kCGImagePropertyGIFUnclampedDelayTime as String) : interval]
]
// フレームを追加していく
frames.forEach { (frame) in
CGImageDestinationAddImage(gif, frame, frameProps as CFDictionary)
}
// 出力する
if CGImageDestinationFinalize(gif) {
successHandler()
} else {
failureHandler()
}
}
そのほかハマったところ
- Swift:CGImage ←→ NSImage ←→ CIImage【変換Extension】
- Swift: 画像をプログラムで描画するときのTips
- Swift: macOSでの座標系のややこしい話
- Swift:実践的なUndoManagerの使い方
- Swift:AVPlayerでシンプルな動画プレイヤーをつくる
リンク
-
GIFLash
使ってみてのコメント待ってます🙏