Marius
Marius

Reputation: 1024

How to load GIF image in Swift?

I have a String with an URL of GIF banner which I need to put into app.

My code:

func showAdd(){
    Request.get("http://www.kyst.no/api/?apiMode=advertisement&lang=no", { (error: NSError?, data: NSData, text: NSString?) -> () in
        let jsonResult: Dictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as Dictionary<String, AnyObject>
        var banner : NSString = jsonResult["advertisement"]!["banner"] as NSString
        self.addViewImage.image = UIImage.animatedImageNamed(banner, duration: 1)
    })
}

But nothing happens. Please help.

Upvotes: 101

Views: 208601

Answers (9)

Kaushik Movaliya
Kaushik Movaliya

Reputation: 857

In SWIFT 5 you can load any .gif image without the use of any third pary. You have to just add this code

extension UIImage {
    class func gifImageWithData(_ data: Data) -> UIImage? {
        guard let source = CGImageSourceCreateWithData(data as CFData, nil) else {
            return nil
        }
        
        let frameCount = CGImageSourceGetCount(source)
        var images: [UIImage] = []
        
        for i in 0..<frameCount {
            if let cgImage = CGImageSourceCreateImageAtIndex(source, i, nil) {
                let image = UIImage(cgImage: cgImage)
                images.append(image)
            }
        }
        
        return UIImage.animatedImage(with: images, duration: 0.0)
    }
}



import UIKit

// Assuming you have a UIImageView outlet named `gifImageView` in your view controller

guard let gifPath = Bundle.main.path(forResource: "example", ofType: "gif") else {
    print("Failed to find the GIF image.")
    return
}

guard let gifData = try? Data(contentsOf: URL(fileURLWithPath: gifPath)) else {
    print("Failed to load the GIF image data.")
    return
}

guard let gifImage = UIImage.gifImageWithData(gifData) else {
    print("Failed to create the GIF image.")
    return
}

// Set the loaded GIF image to the UIImageView
gifImageView.image = gifImage

In the above example, replace "example" with the name of your GIF file (without the file extension) and make sure the GIF file is added to your Xcode project and included in the target.

Note that the code relies on a helper method gifImageWithData(_:) to create a UIImage from the GIF data. Here's an extension that provides that method:

Upvotes: 8

Zach Doster
Zach Doster

Reputation: 119

import UIKit
import ImageIO

extension UIImage {

public class func gifImageWithData(data: NSData) -> UIImage? {
    guard let source = CGImageSourceCreateWithData(data, nil) else {
        print("image doesn't exist")
        return nil
    }
    
    return UIImage.animatedImageWithSource(source: source)
}

public class func gifImageWithURL(gifUrl:String) -> UIImage? {
    guard let bundleURL = NSURL(string: gifUrl)
        else {
            print("image named \"\(gifUrl)\" doesn't exist")
            return nil
    }
    guard let imageData = NSData(contentsOf: bundleURL as URL) else {
        print("image named \"\(gifUrl)\" into NSData")
        return nil
    }
    
    return gifImageWithData(data: imageData)
}

public class func gifImageWithName(name: String) -> UIImage? {
    guard let bundleURL = Bundle.main
        .url(forResource: name, withExtension: "gif") else {
            print("SwiftGif: This image named \"\(name)\" does not exist")
            return nil
    }
    
    guard let imageData = NSData(contentsOf: bundleURL) else {
        print("SwiftGif: Cannot turn image named \"\(name)\" into NSData")
        return nil
    }
    
    return gifImageWithData(data: imageData)
}

class func delayForImageAtIndex(index: Int, source: CGImageSource!) -> Double {
    var delay = 0.1
    
    let cfProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil)
    let gifProperties: CFDictionary = unsafeBitCast(CFDictionaryGetValue(cfProperties, Unmanaged.passUnretained(kCGImagePropertyGIFDictionary).toOpaque()), to: CFDictionary.self)
    
    var delayObject: AnyObject = unsafeBitCast(CFDictionaryGetValue(gifProperties, Unmanaged.passUnretained(kCGImagePropertyGIFUnclampedDelayTime).toOpaque()), to: AnyObject.self)
    
    if delayObject.doubleValue == 0 {
        delayObject = unsafeBitCast(CFDictionaryGetValue(gifProperties, Unmanaged.passUnretained(kCGImagePropertyGIFDelayTime).toOpaque()), to: AnyObject.self)
    }
    
    delay = delayObject as! Double
    
    if delay < 0.1 {
        delay = 0.1
    }
    
    return delay
}

class func gcdForPair(a: Int?, _ b: Int?) -> Int {
    var a = a
    var b = b
    if b == nil || a == nil {
        if b != nil {
            return b!
        } else if a != nil {
            return a!
        } else {
            return 0
        }
    }
    
    if a! < b! {
        let c = a!
        a = b!
        b = c
    }
    
    var rest: Int
    while true {
        rest = a! % b!
        
        if rest == 0 {
            return b!
        } else {
            a = b!
            b = rest
        }
    }
}

class func gcdForArray(array: Array<Int>) -> Int {
    if array.isEmpty {
        return 1
    }
    
    var gcd = array[0]
    
    for val in array {
        gcd = UIImage.gcdForPair(a: val, gcd)
    }
    
    return gcd
}

class func animatedImageWithSource(source: CGImageSource) -> UIImage? {
    let count = CGImageSourceGetCount(source)
    var images = [CGImage]()
    var delays = [Int]()
    
    for i in 0..<count {
        if let image = CGImageSourceCreateImageAtIndex(source, i, nil) {
            images.append(image)
        }
        
        let delaySeconds = UIImage.delayForImageAtIndex(index: Int(i), source: source)
        delays.append(Int(delaySeconds * 1000.0)) // Seconds to ms
    }
    
    let duration: Int = {
        var sum = 0
        
        for val: Int in delays {
            sum += val
        }
        
        return sum
    }()
    
    let gcd = gcdForArray(array: delays)
    var frames = [UIImage]()
    
    var frame: UIImage
    var frameCount: Int
    for i in 0..<count {
        frame = UIImage(cgImage: images[Int(i)])
        frameCount = Int(delays[Int(i)] / gcd)
        
        for _ in 0..<frameCount {
            frames.append(frame)
        }
    }
    
    let animation = UIImage.animatedImage(with: frames, duration: Double(duration) / 1000.0)
    
    return animation
}
}

Here is the file updated for Swift 3

Upvotes: 11

FrugalResolution
FrugalResolution

Reputation: 655

If you are using Kingfisher you can use the AnimatedImageView.

Therefore, in the .xib in the Identity Inspector (right sidemenu) of the existing imageView, change the class to AnimatedImageView. Module is switching automatically to Kingfisher. Change the Class of the IBOutlet in the viewClass also to AnimatedImageView.

Upvotes: 0

smoothumut
smoothumut

Reputation: 3491

it would be great if somebody told to put gif into any folder instead of assets folder

Upvotes: 10

Linh Ta
Linh Ta

Reputation: 623

You can try this new library. JellyGif respects Gif frame duration while being highly CPU & Memory performant. It works great with UITableViewCell & UICollectionViewCell too. To get started you just need to

import JellyGif

let imageView = JellyGifImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))

//Animates Gif from the main bundle
imageView.startGif(with: .name("Gif name"))

//Animates Gif with a local path
let url = URL(string: "Gif path")!
imageView.startGif(with: .localPath(url))

//Animates Gif with data
imageView.startGif(with: .data(Data))

For more information you can look at its README

Upvotes: 12

Mocha
Mocha

Reputation: 2253

Simple extension for local gifs. Gets all the images from the gif and adds it to the imageView animationImages.

extension UIImageView {
    static func fromGif(frame: CGRect, resourceName: String) -> UIImageView? {
        guard let path = Bundle.main.path(forResource: resourceName, ofType: "gif") else {
            print("Gif does not exist at that path")
            return nil
        }
        let url = URL(fileURLWithPath: path)
        guard let gifData = try? Data(contentsOf: url),
            let source =  CGImageSourceCreateWithData(gifData as CFData, nil) else { return nil }
        var images = [UIImage]()
        let imageCount = CGImageSourceGetCount(source)
        for i in 0 ..< imageCount {
            if let image = CGImageSourceCreateImageAtIndex(source, i, nil) {
                images.append(UIImage(cgImage: image))
            }
        }
        let gifImageView = UIImageView(frame: frame)
        gifImageView.animationImages = images
        return gifImageView
    }
}

To Use:

 guard let confettiImageView = UIImageView.fromGif(frame: view.frame, resourceName: "confetti") else { return }
 view.addSubview(confettiImageView)
 confettiImageView.startAnimating()

Repeat and duration customizations using UIImageView APIs.

confettiImageView.animationDuration = 3
confettiImageView.animationRepeatCount = 1

When you are done animating the gif and want to release the memory.

confettiImageView.animationImages = nil

Upvotes: 48

Arjun
Arjun

Reputation: 1598

This is working for me

Podfile:

platform :ios, '9.0'
use_frameworks!

target '<Your Target Name>' do
pod 'SwiftGifOrigin', '~> 1.7.0'
end

Usage:

// An animated UIImage
let jeremyGif = UIImage.gif(name: "jeremy")

// A UIImageView with async loading
let imageView = UIImageView()
imageView.loadGif(name: "jeremy")

// A UIImageView with async loading from asset catalog(from iOS9)
let imageView = UIImageView()
imageView.loadGif(asset: "jeremy")

For more information follow this link: https://github.com/swiftgif/SwiftGif

Upvotes: 0

Kirit Modi
Kirit Modi

Reputation: 23407

Load GIF image Swift :

## Reference.

#1 : Copy the swift file from This Link :

#2 : Load GIF image Using Name

    let jeremyGif = UIImage.gifImageWithName("funny")
    let imageView = UIImageView(image: jeremyGif)
    imageView.frame = CGRect(x: 20.0, y: 50.0, width: self.view.frame.size.width - 40, height: 150.0)
    view.addSubview(imageView)

#3 : Load GIF image Using Data

    let imageData = try? Data(contentsOf: Bundle.main.url(forResource: "play", withExtension: "gif")!)
    let advTimeGif = UIImage.gifImageWithData(imageData!)
    let imageView2 = UIImageView(image: advTimeGif)
    imageView2.frame = CGRect(x: 20.0, y: 220.0, width: 
    self.view.frame.size.width - 40, height: 150.0)
    view.addSubview(imageView2)

#4 : Load GIF image Using URL

    let gifURL : String = "http://www.gifbin.com/bin/4802swswsw04.gif"
    let imageURL = UIImage.gifImageWithURL(gifURL)
    let imageView3 = UIImageView(image: imageURL)
    imageView3.frame = CGRect(x: 20.0, y: 390.0, width: self.view.frame.size.width - 40, height: 150.0)
    view.addSubview(imageView3)

Download Demo Code

OUTPUT :

iPhone 8 / iOS 11 / xCode 9

enter image description here

Upvotes: 178

Sagar Sangani
Sagar Sangani

Reputation: 287

First install a pod :-

pod 'SwiftGifOrigin'

and import in your class

import SwiftGifOrigin

then write this code in viewDidiload method

yourImageView.image = UIImage.gif(name: "imageName")

Note:- plz do not include the file extension in the gif file name. Ex:-

//Don't Do this
yourImageView.image = UIImage.gif(name: "imageName.gif")

See source: https://github.com/swiftgif/SwiftGif

Upvotes: 18

Related Questions