7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

macでGIFアニメをサクッと作る最高のツール

Posted at

エンジニアだとMarkdownを使ったりとかSlackでコミュニケーションしたりとか頻繁にしますよね。そこで手軽にアニメーションを共有する手段としてGIFアニメが大変便利なため重宝しますよね!私もGIFアニメよく使うのですが、QuickTime Playerで画面録画をしたmovファイルをGIFに変換するのってみなさんどんな手段でやってますか?

macでGIFアニメを手軽に作るアプリとしては、PicGIFが有名ですが、画像の縦横サイズの編集が手軽にしづらかったり、繰り返し再生回数を指定できなかったり(とりわけ無限ループにできない)、各コマのalignmentが調整できなかったり、GIFのトリミングができなかったり、痒いところに手が届かないと感じていました。また、Effectや文字列追加機能は不要だと思っていたため、必要十分な機能のアプリを作ることにしました。

GIFlash

Screen Shot 2021-02-22 at 15.30.16.png
Screen Shot 2021-02-22 at 15.37.43.png

特徴

  1. 複数のコマ画像をインポートしてパラパラ漫画を作れる
  2. 動画からコマ画像を切り出してインポートできる
  3. 繰り返し再生(ループ)の回数を指定できる
  4. GIFアニメのサイズの変更が容易
    (アスペクト比をロックして拡大縮小できる)
  5. サイズの異なるリソースを用いる場合、中央揃えや右寄せ、上寄せなど配置の指定ができる
  6. 背景色の指定ができる(透明も可)
  7. 既存のGIFアニメのトリミングができる
  8. 編集中の各コマをPNGとして出力できる

Screen Shot 2021-02-22 at 15.39.51.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()
    }
}

そのほかハマったところ

リンク

  • GIFLash
    使ってみてのコメント待ってます🙏
7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?