-1

A gif image is loaded into a UIImageView (by using this extension) and another UIImageView is overlaid on it. Everything works fine but the problem is when I going for combine both via below code, it shows a still image (.jpg). I wanna combine both and after combine it should be a animated image (.gif) too.

let bottomImage = gifPlayer.image
let topImage = UIImage

let size = CGSize(width: (bottomImage?.size.width)!, height: (bottomImage?.size.height)!)
        
UIGraphicsBeginImageContext(size)
        
let areaSize = CGRect(x: 0, y: 0, width: size.width, height: size.height)
bottomImage!.draw(in: areaSize)

topImage!.draw(in: areaSize, blendMode: .normal, alpha: 0.8)
let newImage = UIGraphicsGetImageFromCurrentImageContext()

UIGraphicsEndImageContext()

Click here to know more about this problem please.

  • Do you mean how to create a gif data representation with multiple images? – Leo Dabus Dec 15 '22 at 12:01
  • Actually no. I want to add 'Frame' on Gif image that is already created. Note: A gif image is loaded into a UIImageView and another UIImageView overlayed on it. So I need to combine these together and download. – Md. Faysal Ahmed Dec 15 '22 at 13:49
  • @Md.FaysalAhmed - how are you displaying your animated gif to begin with? – DonMag Dec 15 '22 at 20:23
  • By using this [**UIImage Extension**](https://github.com/kiritmodi2702/GIF-Swift/blob/master/GIF-Swift/iOSDevCenters%2BGIF.swift) – Md. Faysal Ahmed Dec 16 '22 at 06:39

1 Answers1

0

When using an animated GIF in a UIImageView, it becomes an array of UIImage.

We can set that array with (for example):

imageView.animationImages = arrayOfImages
imageView.animationDuration = 1.0

or, we can set the .image property to an animatedImage -- that's how the GIF-Swift code you are using works:

if let img = UIImage.gifImageWithName("funny") {
    bottomImageView.image = img
}

in that case, the image also contains the duration:

img.images?.duration

So, to generate a new animated GIF with the border/overlay image, you need to get that array of images and generate each "frame" with the border added to it.

Here's a quick example...

This assumes:

  • you are using GIF-Swift
  • you have added bottomImageView and topImageView in Storyboard
  • you have a GIF in the bundle named "funny.gif" (edit the code if yours is different)
  • you have a "border.png" in assets (again, edit the code as needed)

and you have a button to connect to the @IBAction:

import UIKit
import ImageIO
import UniformTypeIdentifiers

class animImageViewController: UIViewController {

    @IBOutlet var bottomImageView: UIImageView!
    @IBOutlet var topImageView: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        if let img = UIImage.gifImageWithName("funny") {
            bottomImageView.image = img
        }
        
        if let img = UIImage(named: "border") {
            topImageView.image = img
        }
        
    }
    
    @IBAction func saveButtonTapped(_ sender: Any) {
        generateNewGif(from: bottomImageView, with: topImageView)
    }

    func generateNewGif(from animatedImageView: UIImageView, with overlayImageView: UIImageView) {
        
        var images: [UIImage]!
        var delayTime: Double!
        
        guard let overlayImage = overlayImageView.image else {
            print("Could not get top / overlay image!")
            return
        }
        
        if let imgs = animatedImageView.image?.images {
            // the image view is using .image = animatedImage
            // unwrap the duration
            if let dur = animatedImageView.image?.duration {
                images = imgs
                delayTime = dur / Double(images.count)
            } else {
                print("Image view is using an animatedImage, but could not get the duration!" )
                return
            }
        } else if let imgs = animatedImageView.animationImages {
            // the image view is using .animationImages
            images = imgs
            delayTime = animatedImageView.animationDuration / Double(images.count)
        } else {
            print("Could not get images array!")
            return
        }
        
        // we now have a valid [UIImage] array, and
        //  a valid inter-frame duration, and
        //  a valid "overlay" UIImage
    
        // generate unique file name
        let destinationFilename = String(NSUUID().uuidString + ".gif")
        
        // create empty file in temp folder to hold gif
        let destinationURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(destinationFilename)
        
        // metadata for gif file to describe it as an animated gif
        let fileDictionary = [kCGImagePropertyGIFDictionary : [kCGImagePropertyGIFLoopCount : 0]]
        
        // create the file and set the file properties
        guard let animatedGifFile = CGImageDestinationCreateWithURL(destinationURL as CFURL, UTType.gif.identifier as CFString, images.count, nil) else {
            print("error creating file")
            return
        }
        
        CGImageDestinationSetProperties(animatedGifFile, fileDictionary as CFDictionary)
        
        let frameDictionary = [kCGImagePropertyGIFDictionary : [kCGImagePropertyGIFDelayTime: delayTime]]
        
        // use original size of gif
        let sz: CGSize = images[0].size
        
        let renderer: UIGraphicsImageRenderer = UIGraphicsImageRenderer(size: sz)
        
        // loop through the images
        //  drawing the top/border image on top of each "frame" image with 80% alpha
        //  then writing the combined image to the gif file
        images.forEach { img in
            
            let combinedImage = renderer.image { ctx in
                img.draw(at: .zero)
                overlayImage.draw(in: CGRect(origin: .zero, size: sz), blendMode: .normal, alpha: 0.8)
            }
            
            guard let cgFrame = combinedImage.cgImage else {
                print("error creating cgImage")
                return
            }
            
            // add the combined image to the new animated gif
            CGImageDestinationAddImage(animatedGifFile, cgFrame, frameDictionary as CFDictionary)
            
        }
        
        // done writing
        CGImageDestinationFinalize(animatedGifFile)
        
        print("New GIF created at:")
        print(destinationURL)
        print()
        
        // do something with the newly created file...
        //  maybe move it to documents folder, or
        //  upload it somewhere, or
        //  save to photos library, etc
    }
    
}

Notes:

DonMag
  • 69,424
  • 5
  • 50
  • 86