iOSでAPNGを作成したいので調べてみた。
適当なライブラリを調べたらAPNGKitが出てきたが表示機能に限定していた。
C++から作れないのかなとlibpingを調べたらパッチを当てるのに票が集まらないわ、ライブラリがメンテナンスしてないわと混迷を極めていた。
APNG support on main libpng library? #267
調べていくと、こちらのページ下部にlibpngにapngパッチ当てたリンクやサンプルコードへのリンクがある。
http://littlesvr.ca/apng/
Apple Document Archive
ニッチ過ぎて情報を見つけるのに手間取ったが、AppleのDocumentにAPNGの作成方法があった。
適当に修正したらうまく動いた。
Animation.swift
import UniformTypeIdentifiers
enum AnimationError: Error {
case create
case finalize
}
func Animation(_ images: [UIImage], toUrl: URL, loopCount: Int = 0) throws {
let frameCount = images.count
let fileProperties = NSMutableDictionary()
fileProperties.setObject(kCGImagePropertyPNGDictionary, forKey: NSDictionary(dictionary: [kCGImagePropertyAPNGLoopCount: loopCount]))
let frameProperties = NSMutableDictionary()
frameProperties.setObject(kCGImagePropertyPNGDictionary, forKey: NSDictionary(dictionary: [kCGImagePropertyAPNGDelayTime: 1.0 / Double(frameCount)]))
guard let destination = CGImageDestinationCreateWithURL(toUrl as CFURL, UTType.png.identifier as CFString , frameCount, nil) else {
throw AnimationError.create
}
CGImageDestinationSetProperties(destination, fileProperties.copy() as? NSDictionary)
for image in images {
autoreleasepool {
CGImageDestinationAddImage(destination, image.cgImage!, frameProperties)
}
}
if !CGImageDestinationFinalize(destination) {
throw AnimationError.finalize
}
}
評価用にプロジェクト内のPNGを探してテンポラリのAPNGにまとめる処理を書いてみた。
なお、画像は同じ幅のPNGのみ配置。
Example.swift
func test(){
let path = Bundle.main.bundlePath
let items = try? FileManager.default.contentsOfDirectory(atPath: path)
do {
let fileUrl: URL = FileManager.default.temporaryDirectory.appendingPathComponent("test.png")
if FileManager.default.fileExists(atPath: fileUrl.path) {
try FileManager.default.removeItem(at: fileUrl)
}
var images = [UIImage]()
if let items = items {
try items.sorted().forEach { f in
if f.hasSuffix(".png") {
let fileUrl = URL(fileURLWithPath: path).appendingPathComponent(f)
if FileManager.default.fileExists(atPath: fileUrl.path) {
let data = try Data(contentsOf: fileUrl)
if let uiImage = UIImage(data: data) {
images.append(uiImage)
}
}
}
}
}
try Animation(images, toUrl: fileUrl)
print(fileUrl)
} catch {
print(error.localizedDescription)
}
}