High performance and delightful way to play with APNG format in iOS.

Last update: Aug 1, 2022

APNGKit

APNGKit is a high performance framework for loading and displaying APNG images in iOS and macOS. It's built with high-level abstractions and brings a delightful API. Since be that, you will feel at home and joy when using APNGKit to play with images in APNG format.

APNG, what and why?

The Animated Portable Network Graphics (APNG) is a file format extending the well-known PNG format. It allows for animated PNG files that work similarly to animated GIF files, while supporting 24-bit images and 8-bit transparency not available for GIFs. This means much better quality of animation. At the same time, the file size is comparable to or even less than, if created carefully, GIFs.

Talk is cheap; show me the image. You can click on the image to see how it looks like when animating.

APNGKit Demo

That's cool. APNG is much better! But wait...why haven't I heard about APNG before? It is not a popular format, so why should I use it in my next great iOS/macOS app?

Good question! APNG is an excellent extension for regular PNG, and it is also very simple to use and not conflicting with current PNG standard (It consists a standard PNG header, so if your platform does not support APNG, it will be recognized as a normal PNG with its first frame being displayed as a static image). But unfortunately, it is a rebel format so that it is not accepted by the PNG group. However, it is accepted by many vendors and is even mentioned in W3C Standards. There is another format called MNG (Multiple-image Network Graphics), which is created by the same team as PNG. It is a comprehensive format, but very very very (重要的事要说三遍) complex. It is so complex that despite being a "standard", it was almost universally rejected. There is only one "popular" browser called Konqueror(at least I have used it before when I was in high school) that supports MNG, which is really a sad but reasonable story.

Even though APNG is not accepted currently, we continue to see the widespread implementation of it. Apple recently supported APNG in both desktop and mobile Safari. Microsoft Edge and Chrome are also considering adding APNG support since it is already officially added in WebKit core.

APNG is such a nice format to bring users much better experience of animating images. The more APNG is used, the more recognition and support it will get. Not only in the browsers world, but also in the apps we always love. That's why I created this framework.

Installation

Requirement

iOS 9.0+ / macOS 10.11+ / tvOS 9.0+

Swift Package Manager

The recommended way to install APNGKit is to use Swift Package Manager. Adding it to your project with Xcode:

CocoaPods

CocoaPods is a dependency manager for Cocoa projects.

$ gem install cocoapods

To integrate APNGKit into your Xcode project using CocoaPods, specify it in your Podfile:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'
use_frameworks!

target 'your_app' do
  pod 'APNGKit', '~> 2.0'
end

Then, run the following command:

$ pod install

You should open the {Project}.xcworkspace instead of the {Project}.xcodeproj after you installed anything from CocoaPods.

For more information about how to use CocoaPods, I suggest this tutorial.

Usage

Basic

Import APNGKit into your source files in which you want to use the framework.

import APNGKit

Load an APNG Image

// Load an APNG image from file in main bundle
var image = try APNGImage(named: "your_image")

// Or
// Load an APNG image from file at specified path
if let url = Bundle.main.url(forResource: "your_image", withExtension: "apng") {
    image = try APNGImage(fileURL: path)
}

// Or
// Load an APNG image from data
let data: Data = ... // From disk or network or anywhere else.
image = try APNGImage(data: data)

You may notice that all initializers are throwable. If anything is wrong during creating the image, it let you know the error explicitly and you have a chance to handle it. We will cover the error handling soon later.

Display an APNG Image

When you have an APNGImage object, you can use it to initialize an image view and display it on screen with an APNGImageView, which is a subclass of UIView or NSView:

let image: APNGImage = ... // You already have an APNG image object.

let imageView = APNGImageView(image: image)
view.addSubview(imageView)

Start animation

The animation will be played automatically as soon as the image view is created with a valid APNG image. If you do not want the animation to be played automatically, set the autoStartAnimationWhenSetImage property to false before you assign an image:

let imageView = APNGImageView(frame: .zero)
imageView.autoStartAnimationWhenSetImage = false
imageView.image = image

// Start the animation manually:
imageView.startAnimating()

Image owner

DO NOT set the same image to multiple image views, which is not allowed in APNGKit. Every created APNGImage has an owner, you cannot set multiple owners to it, otherwise it confuses how to sync with the screen. To display the same image, create a new one:

let image = try APNGImage(named: "image")
imageView.image = image

// You cannot set the same image to another image view.
// This causes an error.
anotherImageView.image = image

// You can create another one and set it.
// This works.
let anotherImage = try APNGImage(named: "image")
anotherImageView.image = anotherImage

// Or first remove the original owner.
// This works
imageView.image = nil
anotherImageView.image = image

XIB or Storyboard

If you are an Interface Builder lover, drag a UIView (or NSView) (Please note, not a UIImageView or NSImageView) to the canvas, and modify its class to APNGImageView. Then, you can drag an IBOutlet and play with it as usual, such as setting its image property.

Delegates

APNG defines the play loop count as numberOfPlays in APNGImage, and APNGKit respects it by default. To inspect the end of each loop, register yourself as a delegate of APNGImageView.onOnePlayDone:

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let imageView = APNGImageView(image: image)
        imageView.onOnePlayDone.delegate(on: self) { (self, count) in
            print("Played: \(count)")
        }
    }
}

When numberOfPlays is nil, the animation will be played forever. If it is a limited non-zero value, the animation will be stopped at the final frame when the loop count reaches the limit. To inspect the whole animation is done, use onAllPlaysDone:

imageView.onAllPlaysDone.delegate(on: self) { (self, _) in
    print("All done.")
}

APNGKit loads the data in a streaming way by default, it reads the frame information while playing the animation. Since APNG encodes the duration in each frame, it is not possible to get the whole animation duration before loading all frames information. Before the first reading pass finishes, you can only get a partial duration for loaded frames. To get the full duration, use APNGImage.onFramesInformationPrepared:

let image = try APNGImage(named: "image")
image.onFramesInformationPrepared.delegate(on: self) { (self, _) in
    switch image.duration {
        case .full(let duration):
            print("Full duration: \(duration)")
        case .partial:
            print("This should not happen.")
    }
}

imageView.image = image

Or, you can specify the .fullFirstPass option while creating the APNGImage. It reads all frames before starting rendering and animating the image:

let image = try APNGImage(named: "image", options: [.fullFirstPass])
print(image.duration) // .full(duration)

APNGKit provides a few other reading options. Please let me skip it for now and you can check them in documentation.

Error handling

While creating image

Creating an APNGImage can throw an error if anything goes wrong. All possible errors while decoding are defined as an APNGKitError.decoderError. When an error happens while creating the image, you are expected to check if it should be treated as a normal static image. If so, try to set it as the static image:

do {
    let image = try APNGImage(named: data.imageName)
    imageView.image = image
} catch {
    if let normalImage = error.apngError?.normalImage {
        imageView.staticImage = normalImage
    } else {
        print("Error: \(error)")
    }
}

While playing animation

If some frames are broken, the default image defined in APNG should be displayed as a fallback. You can get this in APNGKit for free. To get notified when this happens, listen to APNGImageView.onFallBackToDefaultImage:

imageView.onDecodingFrameError.delegate(on: self) { (self, error) in
    print("A frame cannot be decoded. After this, either onFallBackToDefaultImage or onFallBackToDefaultImageFailed happens.")
}

imageView.onFallBackToDefaultImage.delegate(on: self) { (self, _) in
    print("Fall back to default image.")
}
imageView.onFallBackToDefaultImageFailed.delegate(on: self) { (self, error) in
    print("Tried to fall back to default image, but it fails: \(error)")
}

PNG compression

Xcode will compress all PNG files in your app bundle when you build the project. Since APNG is an extension format of PNG, Xcode will think there are redundancy data in that file and compress it into a single static image. When this happens, you may inspect a log message from APNGKit:

CgBI chunk found. It seems that the input image is compressed by Xcode and not supported by APNGKit. Consider to rename it to apng to prevent compressing.

Usually this is not what you want when working with APNG. You can disable the PNG compression by setting "COMPRESS_PNG_FILES" to NO in the build settings of your app target. However, it will also prevent Xcode to optimize your other regular PNGs.

A better approach would be renaming your APNG files with an extension besides of "png". If you do so, Xcode will stop recognizing your APNG files as PNG format, and will not apply compression on them. A suggested extension is "apng", which will be detected and handled by APNGKit seamlessly.

Acknowledgement

The demo elephant image in README file is stolen from ICS Lab, you can find the original post here.

Reference

If you are interested in APNG, you can know more about it from the links below (some of them are written in Chinese).

APNGKit can only load and display APNG image now. The creating feature will be developed later. If you need to create APNG file now, I suggest using iSparta or apngasm instead for now.

License

APNGKit is released under the MIT license. See LICENSE for details.

GitHub

https://github.com/onevcat/APNGKit
Comments
  • 1. APNGImageView is not recognized by Xcode 7 in storyboard

    Autocomplete does not work and Xcode doesn't allow me to use it at all because of that.

    2015-10-21 11 26 18

    Although I can use APNGKit's functions in code.

    Am I doing something wrong? Or is there a bug in your code?

    Reviewed by yurijmi at 2015-10-21 08:28
  • 2. Project Bitcode issue

    In out project, we setting the OTHER_CFLAGS to -fembed-bitcode but it show error:

    Showing All Errors Only
    ld: bitcode bundle could not be generated because '.../Build/Products/Debug-iphoneos/APNGKit/APNGKit.framework/APNGKit' was built without full bitcode. All frameworks and dylibs for bitcode must be generated from Xcode Archive or Install build for architecture arm64
    

    Is any setting missing or APNGKit didn't support bitcode?

    Reviewed by marcuswu0814 at 2017-03-24 03:50
  • 3. Issue in compiling with xcode 8 - for legacy support - swift 2.3

    Hi!

    I am trying to use the library. I get error for below: /APNGKit/Frame.swift:75:73: Nil is not compatible with expected argument type 'CGDataProviderReleaseDataCallback' (aka '@convention(c) (UnsafeMutablePointer<()>, UnsafePointer<()>, Int) -> ()')

    Tried this for most versions of library - 0.1.0 to 0.1.4.

    Please suggest way to deal with this. My project is in Swift 2.3, so need library compiled with 2.3 to be used.

    Thanks!

    Reviewed by harit at 2016-09-28 14:02
  • 4. mouse ear gets stuck

    Hi team. I have an issue could you help?

    I used APNGKit v2.0.2, it works for me with almost apng images, but I encountered an issue with mouse

    https://user-images.githubusercontent.com/2205362/144172712-94f36430-1c48-42b1-9953-37d784123544.mov

    I tried view this image on the Safari browser (Mac OS) with url: file:///Users/../Downloads/mouse.png - no stuck ear.

    Reviewed by duyenlv at 2021-12-01 04:57
  • 5. Prevent crash in libapng

    This is a discussion about an issue I had in APNGKit. I think it would be easier to have a discussion based on the PR.

    setjmp, longjmp

    It seems this code is trying to save the program from a longjmp inside libapng: https://github.com/onevcat/APNGKit/blob/704d1b58cf9ccc284d0c150e76bbcf2b5745c575/APNGKit/Disassembler.swift#L247

    However, I don't think it works because png_jmpbuf(pngPointer) just returns the jmpbuf. A setjmp function call should be used, but it is no longer available in Swift for safety.

    The Actual Issue

    I'm having a crash in my app. I created a demo: https://github.com/axl411/APNGKitCrash

    The crash happens at this line: https://github.com/onevcat/APNGKit/blob/704d1b58cf9ccc284d0c150e76bbcf2b5745c575/APNGKit/Disassembler.swift#L168

    Inside libapng, the error happens at: https://github.com/onevcat/APNGKit/blob/704d1b58cf9ccc284d0c150e76bbcf2b5745c575/APNGKit/libpng-apng/pngread.c#L333

    A longjmp is called at last in libapng, but since no setjmp is called earlier, the program crashes.

    Fix

    To fix this we need to call setjmp earlier on the stack to escape from the error. I tried but it seems in Swift this is not possible. So the fix is to move the processing code that could call longjmp inside libapng to the ObjC env, and let ObjC handles the call to setjmp and the code for exiting.

    In my PR I just move the call to png_read_frame_head to ObjC, and handle the setjmp call there.

    However, png_read_frame_head is not the only function that could call longjmp, we should guard all calls to libapng with setjmp, in every method. So eventually, it seems the whole parsing code should be written in ObjC, guarded by setjmp, and only the interface code can be in Swift. Here's an example: https://github.com/line/apng-drawable/blob/7097a85fe94c18623fd7df6d833719289e4a105b/apng-drawable/src/main/cpp/apng-drawbale/ApngDecoder.cpp (pls search "setjmp")

    Reviewed by axl411 at 2020-10-20 09:41
  • 6. optimize cpu load to build next frame by first progressive decoding

    There is problem on APNGImage.next(currentIndex:) that consume cpu load almost 70% of total 24%.

    Test environment: iPhone 6s, iOS 10.1.1 Demo app: APNGDemo-iOS APNG file: spinfox.apng

    I've fixed it to build next frame by first progressive decoding.

    Let me know if it has any problems. Thank you.

    Before

    cpu profile

    After

    final
    Reviewed by netmaid at 2018-03-26 11:02
  • 7. support macOS

    changes

    • [x] add a target named APNGKit OSX to support macOS 10.10 or later.
    • [x] the framework name is APNGKit, same as iOS.
    • [x] add macOS test target APNGKitTests OSX, using existing iOS test cases.
    • [x] when write a demo to test, it works well.

    to do

    • [ ] for macOS, if set repeatCount, mouse over event to support replay.
    • [ ] for macOS, auto startAnimating when APNGImageView becomes visible, auto stopAnimating when it becomes invisible.

    note

    • could you change the iOS target name to APNGKit iOS, and keep the framework name as APNGKit
    • could you change the directory structure in order to add a Mac App demo.
    Reviewed by tyljohnny at 2017-04-01 16:44
  • 8. Carthage in Objective-C context

    Hey,

    I'm trying to use APNGKit with Carthage in Objective-C context. I can't use Swift because its an Unity project. Is this combination possible? I imported <APNGKit/APNGKit-Swift.h> but the header file does only expose the default init and initWithDecoder methods. I tried [[APNGImage alloc] contentsOfFile:@""] wich throws No visible @interface for 'APNGImage' declares the selector 'contentsOfFile:'

    Reviewed by dionysiusmarquis at 2017-11-09 11:04
  • 9. Repeatedly push an view controller whose view owned a apng animation view and pop it, app will crash.

    This is the occasional problem. And we detected it by our apm system. And finally positioned to the APNGKit. I test the APNGKit's demo, it also has the same problem.

    This is the error symbol stack log of APNGKitDemo proj.

    Hardware Model:      iPhone7,2
    Process:             APNGDemo-iOS [3710]
    Path:                /private/var/containers/Bundle/Application/42CDB407-533D-4EA7-8F5D-77F199CBAC8B/APNGDemo-iOS.app/APNGDemo-iOS
    Identifier:          com.onevcat.APNGDemo-iOS
    Version:             1 (1.0)
    Code Type:           ARM-64 (Native)
    Role:                Foreground
    Parent Process:      launchd [1]
    Coalition:           com.onevcat.APNGDemo-iOS [3835]
    
    
    Date/Time:           2017-11-07 10:28:59.6368 +0800
    Launch Time:         2017-11-07 10:27:52.6125 +0800
    OS Version:          iPhone OS 10.3.2 (14F89)
    Report Version:      104
    
    Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
    Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000109e38000
    Termination Signal: Segmentation fault: 11
    Termination Reason: Namespace SIGNAL, Code 0xb
    Terminating Process: exc handler [0]
    Triggered by Thread:  0
    
    Filtered syslog:
    None found
    
    Thread 0 name:  Dispatch queue: com.apple.main-thread
    Thread 0 Crashed:
    0   libsystem_platform.dylib      	0x000000018bd20e10 _platform_memmove + 176
    1   CoreGraphics                  	0x000000018e0702c0 decode_data + 13144
    2   CoreGraphics                  	0x000000018e239720 img_decode_read + 2024
    3   CoreGraphics                  	0x000000018e23d490 img_alphamerge_read + 548
    4   CoreGraphics                  	0x000000018e2408fc img_data_lock + 6124
    5   CoreGraphics                  	0x000000018e23f0b8 CGSImageDataLock + 176
    6   CoreGraphics                  	0x000000018e05f1c0 ripc_AcquireImage + 756
    7   CoreGraphics                  	0x000000018e2539a4 ripc_DrawImage + 656
    8   CoreGraphics                  	0x000000018e243b50 CGContextDrawImageWithOptions + 632
    9   QuartzCore                    	0x000000018fe87a8c CA::Render::(anonymous namespace)::create_image_by_rendering+ 105100 (CGImage*, CGColorSpace*, unsigned int, double) + 1068
    10  QuartzCore                    	0x000000018fe88960 CA::Render::(anonymous namespace)::create_image_from_rgb_image+ 108896 (CGImage*, CGColorSpace*, unsigned int, double) + 660
    11  QuartzCore                    	0x000000018fe874b0 CA::Render::create_image+ 103600 (CGImage*, CGColorSpace*, unsigned int, double) + 876
    12  QuartzCore                    	0x000000018fe89238 CA::Render::copy_image+ 111160 (CGImage*, CGColorSpace*, unsigned int, double, double) + 472
    13  QuartzCore                    	0x000000018ff87434 -[CALayer+ 1152052 (CALayerPrivate) _copyRenderLayer:layerFlags:commitFlags:] + 480
    14  QuartzCore                    	0x000000018fef4a74 CA::Context::commit_layer+ 551540 (CA::Layer*, unsigned int, unsigned int, void*) + 108
    15  QuartzCore                    	0x000000018ff7a3a8 CA::Layer::commit_if_needed(CA::Transaction*, void (*)+ 1098664 (CA::Layer*, unsigned int, unsigned int, void*), void*) + 388
    16  QuartzCore                    	0x000000018feb39ac x_hash_table_foreach + 72
    17  QuartzCore                    	0x000000018ff1d4c0 CA::Transaction::foreach_root(void (*)+ 718016 (CA::Layer*, void*), void*) + 40
    18  QuartzCore                    	0x000000018fef5778 CA::Context::commit_transaction+ 554872 (CA::Transaction*) + 1320
    19  QuartzCore                    	0x000000018ff1c3ac CA::Transaction::commit+ 713644 () + 504
    20  QuartzCore                    	0x000000018ff1ce78 CA::Transaction::observer_callback+ 716408 (__CFRunLoopObserver*, unsigned long, void*) + 120
    21  CoreFoundation                	0x000000018cc149a8 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
    22  CoreFoundation                	0x000000018cc12630 __CFRunLoopDoObservers + 372
    23  CoreFoundation                	0x000000018cc12a7c __CFRunLoopRun + 956
    24  CoreFoundation                	0x000000018cb42da4 CFRunLoopRunSpecific + 424
    25  GraphicsServices              	0x000000018e5ac074 GSEventRunModal + 100
    26  UIKit                         	0x0000000192dfd058 UIApplicationMain + 208
    27  APNGDemo-iOS                  	0x0000000100097cfc 0x100090000 + 31996
    28  libdyld.dylib                 	0x000000018bb5159c start + 4
    
    Reviewed by Desgard at 2017-11-07 02:51
  • 10. [bug] The repeat count info is not working.

    The repeat count info is not working.

    The repleatCount in png metadata means that repeat animation after end of the last play. So #0 means that 1 time animation from first frame. #1 means that 2 times repeat. #2 means that 3 time repeat.

    REF. https://wiki.mozilla.org/APNG_Specification num_plays indicates the number of times that this animation should play; if it is 0, the animation should play indefinitely. If nonzero, the animation should come to rest on the final frame at the end of the last play.

    Reviewed by cabbage98 at 2018-03-28 07:46
  • 11. Missing PLTE before IDAT

    I have converted some gifs to apng files. But I am getting this error when I'm trying to use them:

    imagePNG_error_break:445: *** ERROR: imagePNG_error_break handle_error:269: IDAT: Missing PLTE before IDAT

    What does it mean? How can I get these files to work?

    Reviewed by alexionut at 2021-11-18 14:47
  • 12. How to tint a APNG Image?

    I would like to tint a Image like

    let imageView = UIImageView()
    imageView.image = UIImage(named: "custom-icon")?.withRenderingMode(.alwaysTemplate)
    imageView.tintColor = .red
    

    How can I do that with APNG?

    let imageView = APNGImageView()
    imageView.image = APNGImage(named: "custom-apng-icon", progressive: true)
    imageView.tintColor = .red
    

    ..but it does not work

    Reviewed by StefaniOSApps at 2021-04-07 23:46
Related tags
Image framework for iOS to display/encode/decode animated WebP, APNG, GIF, and more.
Image framework for iOS to display/encode/decode animated WebP, APNG, GIF, and more.

YYImage Image framework for iOS to display/encode/decode animated WebP, APNG, GIF, and more. (It's a component of YYKit) Features Display/encode/decod

Jul 18, 2022
High-performance animated GIF support for iOS in Swift
High-performance animated GIF support for iOS in Swift

Gifu adds protocol-based, performance-aware animated GIF support to UIKit. (It's also a prefecture in Japan). Install Swift Package Manager Add the fo

Aug 4, 2022
SwiftyGif - High performance & easy to use Gif engine
 SwiftyGif - High performance & easy to use Gif engine

SwiftyGif High performance & easy to use Gif engine Features UIImage and UIImageView extension based Remote GIFs with customizable loader Great CPU/Me

Jul 31, 2022
Async GIF image decoder and Image viewer supporting play GIF images. It just use very less memory.
Async GIF image decoder and Image viewer supporting play GIF images. It just use very less memory.

YLGIFImage Asynchronized GIF image class and Image viewer supporting play/stop GIF images. It just use very less memory. Following GIF usually will co

Jul 27, 2022
Complete Animated GIF Support for iOS, with Functions, NSJSONSerialization-style Class, and (Optional) UIImage Swizzling
Complete Animated GIF Support for iOS, with Functions, NSJSONSerialization-style Class, and (Optional) UIImage Swizzling

AnimatedGIFImageSerialization This library is no longer maintained. In iOS 13+ and macOS 10.15+, use CGAnimateImageAtURLWithBlock instead. AnimatedGIF

Jun 29, 2022
Convert live photos and videos into animated GIFs in iOS, or extract frames from them.
Convert live photos and videos into animated GIFs in iOS, or extract frames from them.

Create a GIF from the provided video file url, Or extract images from videos. This repository has been separated from original repo along with some no

May 18, 2022
Performant animated GIF engine for iOS
Performant animated GIF engine for iOS

FLAnimatedImage is a performant animated GIF engine for iOS: Plays multiple GIFs simultaneously with a playback speed comparable to desktop browsers H

Aug 11, 2022
XAnimatedImage is a performant animated GIF engine for iOS written in Swift based on FLAnimatedImage
XAnimatedImage is a performant animated GIF engine for iOS written in Swift based on FLAnimatedImage

XAnimatedImage is a performant animated GIF engine for iOS written in Swift based on FLAnimatedImage. An illustration is shown below: Features Plays m

Jun 29, 2022
Test2 - A curated list of Open Source example iOS apps developed in Swift
Test2 - A curated list of Open Source example iOS apps developed in Swift

Example iOS Apps A curated list of Open Source example iOS apps developed in Swi

Jan 4, 2022
Captcha implementation in ios App

CaptchaDemo_ios A Swift project to showcase implementation of Google ReCaptcha in iOS Application. Features A light weight basic wrapper to handle com

Feb 7, 2022
iOS implementation of the Catrobat language

Catty Catty, also known as Pocket Code for iOS, is an on-device visual programming system for iPhones. Catrobat is a visual programming language and s

Aug 5, 2022
APNGKit is a high performance framework for loading and displaying APNG images in iOS and macOS.
APNGKit is a high performance framework for loading and displaying APNG images in iOS and macOS.

APNGKit is a high performance framework for loading and displaying APNG images in iOS and macOS. It's built on top of a modified version of libpng wit

Aug 1, 2022
An animated gif & apng engine for iOS in Swift. Have a great performance on memory and cpu usage.

Features Small but complete, only200lines of code. Allow to control display quality, memory usage, loop time and display progress. Have a great perfor

Jun 29, 2022
Awesome Cache Delightful on-disk cache (written in Swift). Backed by NSCache for maximum performance

Awesome Cache Delightful on-disk cache (written in Swift). Backed by NSCache for maximum performance and support for expiry of single objects. Usage d

Jul 21, 2022
Image framework for iOS to display/encode/decode animated WebP, APNG, GIF, and more.
Image framework for iOS to display/encode/decode animated WebP, APNG, GIF, and more.

YYImage Image framework for iOS to display/encode/decode animated WebP, APNG, GIF, and more. (It's a component of YYKit) Features Display/encode/decod

Jul 18, 2022
An extremely high-performance, lightweight, and energy-efficient pure Swift async web image loader with memory and disk caching for iOS and  Watch.

KFSwiftImageLoader KFSwiftImageLoader is an extremely high-performance, lightweight, and energy-efficient pure Swift async web image loader with memor

Jun 29, 2022
High-performance and flexible video editing and effects framework, based on AVFoundation and Metal.
High-performance and flexible video editing and effects framework, based on AVFoundation and Metal.

High-performance and flexible video editing and effects framework, based on AVFoundation and Metal.

Aug 4, 2022
High performance and lightweight UIView, UIImage, UIImageView, UIlabel, UIButton, Promise and more.

SwiftyUI High performance and lightweight UIView, UIImage, UIImageView, UIlabel, UIButton and more. Features SwiftyView GPU rendering Image and Color

Jul 26, 2022
High performance Swift treemap layout engine for iOS and macOS.
High performance Swift treemap layout engine for iOS and macOS.

Synopsis YMTreeMap is a high performance treemap layout engine for iOS and macOS, written in Swift. The input to YMTreeMap is a list of arbitrary numb

Jul 18, 2022