How to load GIF image in Swift?
Asked Answered
O

9

98

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.

Oldworld answered 13/1, 2015 at 10:11 Comment(5)
animatedImageNamed() doesn't do what you think it does. That method is a shortcut for loading a series of static images that are named like so image0, image 1, image2 and so on and sets them as the animationImages array. It does not load an animated image like a GIF. This question has been asked before and has a few answers: https://mcmap.net/q/218618/-display-animated-gif-in-ios -- given it's not Swift, but it shouldn't be difficult to apply the answers to Swift.Stakeout
If you don't want to use the open source ObjC code in answer linked above, then the basic gist is that you will need to decode the gif file to extract the individual frames, and then pass those frame images to the image view's animationImages property.Stakeout
I've also tried expertland.net/question/a6bc48r3n7t5251n4v1p7l4n5u50jp6s9/… But I get stuck on: var testImage = UIImage.animatedImageWithAnimatedGIFData(NSData.dataWithContentsOfURL(url)) 'dataWithContentsOfURL' is unavailable: use object construction 'NSData(contentsOfURL:)'Oldworld
you can use this one: github.com/kirualex/SwiftyGifArne
please refer to this https://mcmap.net/q/218619/-add-animated-gif-image-in-iphone-uiimageviewPregnancy
P
177

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

Preventer answered 13/1, 2015 at 12:45 Comment(14)
For future users of this, this will not work with JPG or PNG. If you are loading a list of URLs or if you don't know the extension, it will fail.Alrzc
your code is giving this Error "Type 'UIImage' has no member 'gifImageWithName'" can you please help meGet
this lib is using too much memory,Manualmanubrium
I tried this lib, it works perfectly, however some GIF image appears rotated 90 degree or looks somewhat wrong, is this a bug?Anticipative
@kirit, I want to show GIF only once. How should i do that by using your swift file ?Towage
@ammateja the you call the sequences of images in imageView only one time.Preventer
successGIF.image = UIImage.gifImageWithName("translation-successful") am using like this, just with name am trying to show GIF. Here how can we show only one timeTowage
@KiritModi this library is using too much memory and giving many memory leaksInnsbruck
You copied this form SwiftGif :DIron
how to adjust the animation speed?Anthracnose
I dragged iOSDevCenters+GIF.swift class inside app and displayed gif with image data it took more then 700 MB in XCode running with iPad any solution for this????Tani
This code uses lot of memory due to that my app freezes any help?? Kirit and @OldworldTani
this code using a lot of Memory and Animation is too much slowLorrimor
github.com/TaLinh/JellyGif is using low Memory and Easy to useLorrimor
U
45

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
Untold answered 8/2, 2019 at 18:38 Comment(5)
I used this approach to load a few gifs in a collectionView and my app was using over 2GB of memory. The use of gifs like this appears to be extremely memory intensive.Brillatsavarin
cause CGImageSourceCreateWithData needs to be balanced with a CFReleaseLenee
@Lenee How do I release the image? When I try to release it, xCode gives me warning saying CF objects are automatically memory managed.Untold
When you're done with your animation, do confettiImageView.animationImages = nil which will release the memory.Vardon
Down scale each frame of gif while extracting could be helpful in case of high memory usage, try specify option with kCGImageSourceThumbnailMaxPixelSize key in CGImageSourceCreateImageAtIndex() call, typically choose a size which equals to UI component's point size multiplied by device screen's scale factor.Geographical
R
18

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

Radio answered 27/3, 2018 at 7:4 Comment(8)
There is no explanation for how this library works - how is somebody supposed to continue displaying a GIF image if this library suddenly starts to fail, or becomes corrupt, or if they have to otherwise remove it? Please attempt to explain what the library does.Arvy
not working for me Error : SwiftGif: This image named "test" does not exist I added test.gif in assets I can see image but I get above errorBaumbaugh
@karan, use this: imageView.loadGif(asset: "test")Phenice
I used only one file SwiftGifCommon/UIImage+Gif.swift and loadGif method. no need to install complete podGragg
It takes lot of memory when i play gif imageview in arkit scene due to that app UI freezed any solution?Tani
It's never a solution to add a pod to your project!Nephology
I'm using this pod but the issue is gif image is display fine on Xcode debugging, but not displaying in TestFlight build.Landau
It's a lot more helpful to try to provide a solution without the use of unnecessary libraries which no one really knows how they work, since most people won't take the time to read it's code and understand how it works before using it.Vaucluse
T
12

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

Total answered 17/5, 2020 at 11:6 Comment(1)
this is working much better than other options on this pageMelchior
C
11
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

Caterwaul answered 7/8, 2017 at 19:58 Comment(8)
Memory usage with this one is abnormally high, with a single larger, 6mb gif the memory usage shot to 400MB. Actual device not simulator. Haven't tried many other gifs though.Daliadalila
@SamBing I am also facing the memory issue with this code, have you managed to find any update or other alternatives to this?Cacciatore
@Cacciatore I did turn to a library called Gifu, mostly because the way it buffers and handles memory it's way more efficient. Take a look at it, as i did go through a lot of libraries, you may just save some time.Daliadalila
@SamBing I did a pod install for 'Gifu' (latest v2.0.1). I am getting an error in one of its classes, named FrameStore (line 101, prepareFrames method). Also, I think the library loads only local gifs, i need to load them from network calls. The full documentation is not available. Any suggestion?Cacciatore
@Cacciatore it supports loading GIFS from Data, so you can fetch the Data first. As for the error i'm really not sure as i haven't encountered it.Daliadalila
@SamBing I did try using Gifu in a separate project and got it working. Thanks. The project i am working on is using the library 'SDWebImage' so I updated the pod for gif support and had the gifs displayed, the memory consumption is fine as well. You can have a look into it as well :)Cacciatore
Same issue it took more than 700 MB with this to play small gif any solution please without third party library??Tani
HI, My app UI freezed after using this in Arkit sceneview any solution please?Tani
T
10

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

Trefor answered 25/9, 2020 at 14:42 Comment(1)
Exactly! Was lost for over 30 minsRattlesnake
V
5

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:

Vaso answered 16/6, 2023 at 10:58 Comment(0)
H
0

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

Hypophosphate answered 3/8, 2019 at 11:52 Comment(2)
A lot of open issues, last code commit around a year ago... This seems to be more up to date: github.com/kaishin/GifuErek
There is already a user that has answered with using SwiftGiftOriginUntold
G
0

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.

Gaul answered 16/1, 2023 at 17:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.