今回のゴール
今回のキーワード
- UIImage
- gif
- Extension
やったこと
素材画像を見直すよ
- 前回で使ったgif画像は実は素材画像を自分で切り貼りして無理やり作ったものだよ
- だからかなり荒いものになっていたよ
- 大量にある素材画像からgif化できないか探してたらこんなものがあったよ
- どうやら左上から右方向に3枚ごとにまとめればgifになりそうなので、この画像の左上から3枚目まで1枚ずつ切り抜いてgif化できないかなと考えたよ
画像の一部の切り抜き方をググるよ
- 検索ワード「UIImage 切り抜き」
- ドンピシャな記事(Swift3.0で画像の切り抜き)が見つかったのでそのまま拝借するよ
まず1枚切り抜いて表示してみるよ
- sozai.pngという名前でプロジェクトに素材画像を追加するよ
- UIImage+Cropping.swiftというExtension用のファイルを追加して先ほどのコードを追記するよ
UIImage+Cropping.swift
import Foundation
import UIKit
extension UIImage {
func cropping(to: CGRect) -> UIImage? {
var opaque = false
if let cgImage = cgImage {
switch cgImage.alphaInfo {
case .noneSkipLast, .noneSkipFirst:
opaque = true
default:
break
}
}
UIGraphicsBeginImageContextWithOptions(to.size, opaque, scale)
draw(at: CGPoint(x: -to.origin.x, y: -to.origin.y))
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result
}
}
- 左上の座標(x: 0.0, y: 0.0)から(width: 64.0, height: 64.0)分のCGRectを作って関数に代入するよ (色々調べた結果、1枚1枚は64 * 64のサイズでできているよ)
ViewController.swift
~~~省略~~~
override func viewDidLoad() {
super.viewDidLoad()
// 一旦コメントアウト
// imageView.image = UIImage.gif(name: "character")
// まずは素材画像からUIImageを宣言する
let image = UIImage(named: "sozai.png")
// 切り取る範囲を指定するCGRectを宣言する
let croppingRect = CGRect(x: 0.0, y: 0.0, width: 64.0, height: 64.0)
// imageをcroppingRectで切り抜いて、返り値をimageView.imageに代入する
imageView.image = image?.cropping(to: croppingRect)
}
~~~省略~~~
UIImageをgifにする方法が分からなかったのでググるよ
- 検索ワード「UIImage gif化」
- 色々参考になる記事はあったけど、分かりやすいこの記事([iOS][swift] アニメーションGIFを作る)を参考にするよ
- 前回ダウンロードしてきたUIImage+Gif.swiftに追記していくよ
- (人のライブラリいじっていいものなんだろうか・・ )
- 必要な処理が2つあるので分かりやすいように関数を2つに分けるよ
- UIImageからgif用の3枚を切り抜く処理(createCharacterImagesForGif)
- これはExtensionの中でしか使わないようにprivateにしたよ
- UIImageの配列からgifファイルのURLを生成する処理(createGifURL)
- これはほぼコピペだけど、動けばいいか!の精神で乗り切るよ
- UIImageからgif用の3枚を切り抜く処理(createCharacterImagesForGif)
UIImage+Gif.swift
import UIKit
import ImageIO
import MobileCoreServices
~~~省略~~~
extension UIImage {
~~~省略~~~
// MARK: 自身のimageからgif用の配列を生成するメソッド
private func createCharacterImagesForGif() -> [UIImage]? {
let cropX = 64 // 切り抜くwidth
let cropY = 64 // 切り抜くheight
// 切り抜いた画像を保存しておく配列
var images: [UIImage] = []
// 3枚分for文を回す
for i in 0..<3 {
guard let image = self.cropping(to: CGRect(x: i * cropX, y: 0, width: cropX, height: cropY)) else {
// クロッピングに失敗したらnilをreturnする
return nil
}
// 切り抜けたUIImageを配列に追加
images.append(image)
}
// うまいこといけば3枚分のUIImageが入った配列がreturnされる
return images
}
// MARK: UIImageの配列からgifを生成し、保存したURLを返すメソッド
func createGifURL() -> URL? {
guard let images = self.createCharacterImagesForGif() else {
return nil
}
let charaImages: [CGImage] = images.map{$0.cgImage!}
guard let url = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(NSUUID().uuidString).gif") else {
print("url化失敗")
return nil
}
guard let destination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypeGIF, charaImages.count, nil) else {
print("CGImageDestinationの作成に失敗")
return nil
}
let properties = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFLoopCount as String: 0]]
CGImageDestinationSetProperties(destination, properties as CFDictionary)
let frameProperties = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFDelayTime as String: 0.25]]
for image in charaImages {
CGImageDestinationAddImage(destination, image, frameProperties as CFDictionary)
}
if CGImageDestinationFinalize(destination) {
print("GIF生成が成功")
return url
} else {
print("GIF生成に失敗")
return nil
}
}
}
ViewController.swift
~~~省略~~~
override func viewDidLoad() {
super.viewDidLoad()
// 一旦コメントアウト
// imageView.image = UIImage.gif(name: "character")
// まずは素材画像からUIImageを宣言する
let image = UIImage(named: "sozai.png")
// 素材のimageからgifのURLが生成できたかをnilチェックする
if let url = image?.createGifURL() {
// urlが生成されていたらimageViewのimageに代入
imageView.image = UIImage.gif(url: url.absoluteString)
}
}
~~~省略~~~
できた!前回のと比較すると一目瞭然
結果
- 素材が神
- 先人が神
- ドンピシャな記事があるとマジで捗る
- UIImage.gifの引数がurlってラベルなのにString型で分かりにくい
- 今回の作業ブランチはこちら!
余談
- 他のgif画像も表示してみた
- どうやら全てがgifになるわけじゃなかった様子だよ
- どう使ったらいいか分からないgifもあるよ・・
次回 2017/6/25追記
キャラクターをクラス化してViewControllerから分離するよ
http://qiita.com/nasteng/items/ed2a3974b4bafdb5f653
最後に
ご指摘・リファクタ大歓迎です