Small make up said. GIF image format is a common dynamic image format, both on the Web end and mobile end are often encountered, but considering the current iOS is not able to show GIF images, and GIF native support is not as comprehensive as JPG, PNG and other image formats support, Therefore, this article from the perspective of image synthesis and decomposition to explain GIF knowledge, combined with ImageIO framework can be more convenient to achieve the synthesis and decomposition of GIF images. This article is from “iOS animation — Core Technology and Case Study”.

GIF usage scenarios in iOS

There are three ways to use GIF in iOS.

(1) GIF images are decomposed into single frames.

(2) a series of single frame image synthesis GIF images.

(3) Display GIF animation effect on iOS system.

In GIF synthesis and decomposition will contact iOS image processing core framework ImageIO, as the iOS system image processing core framework, it provides us with a variety of rich API, this article will achieve GIF decomposition and synthesis function, through ImageIO can be very convenient to achieve. GIF animation display effects will be combined with UIImageView and timer, using frame by frame display for you to present GIF animation effects.

GIF decomposes a single frame of an image

GIF image decomposition process

The process of splitting a GIF into a single frame is as follows.

The whole process is divided into 5 modules and 4 processes, as follows.

(1) Read the GIF image locally and convert it to NSdata data type.

(2) Take NSData as the input of ImageIO module.

(3) Get the output data of ImageIO: UIImage.

(4) Store the obtained UIImage data in JPG or PNG format and save it locally.

In the whole process of GIF image decomposition, ImageIO is the core part of the process. It is responsible for parsing the GIF file format and converting the parsed data into a sequence of frames of picture output. Fortunately, we didn’t create the wheel, we just used it. So in this book we will not study the specific implementation of GIF decomposition synthesis algorithm, but will focus on how to use the ImageIO framework to achieve the required functionality.

2 GIF image decomposition code implementation

Before formally analyzing the code, let’s take a look at the file structure of the entire project, as shown in figure 1.

The source file is plane.gif. The viewDidLoad() method in the viewController.swift file contains all the code for splitting a GIF into a single frame and saving it locally. Here’s how to do this with “GIF decomposing into single frames”.

Function module 1: read GIF files and convert them to NSdata type.

let gifPath:NSString = Bundle.main.path(forResource: "plane", ofType: "gif")! as NSString
let gifData:Data = try! Data(contentsOf: URL(fileURLWithPath: gifPath as String))
Copy the code

The first line of code uses the path method to get the address of a file named plane in GIF format. Line 2 gets the file information and loads it into the gifData (NSData type) variable. The first part of the process has been completed.

Function module two: use ImageIO framework, traverse all GIF sub frames. It is important to note that when using ImageIO, you must convert the NSdata read to the data type that ImageIO can process. Here, CGImageSourceRef is used. The processing flow of corresponding functional modules is shown as follows.

1 let gifDataSource:CGImageSource = CGImageSourceCreateWithData(gifData as CFData, nil)! 2 let gifImageCount:Int = CGImageSourceGetCount(gifDataSource) 3 for i in 0... gifImageCount-1{ let imageref:CGImage? = CGImageSourceCreateImageAtIndex(gifDataSource, i, nil) let image:UIImage = UIImage(cgImage: imageref! , scale:UIScreen.main.scale, orientation:UIImageOrientation.up ) }Copy the code

Below is the GIF data processing process in ImageIO part of the function description. Line 1 converts the GIF raw data type NSdata to a data type CGImageSourceRef that ImageIO can handle directly. Line 2 gets the number of frames for the current GIF image. We know that GIFs are made up of frames, so this line is to get the number of frames that make up the GIF. Line 3 iterates the CGImageSource data by image sequence number and converts the iterated result to UIImage using the UIImage system method.

Here are two methods to focus on.

CGImageSourceCreateImageAtIndex method is used to return one frame image in GIF CGImage type data. This method takes three parameters, parameter 1 is the raw GIF data, parameter 2 is the ordinal number in the GIF subframe (the ordinal number starts at 0), and parameter 3 is some selection parameters for GIF data extraction, which is set to nil because it is not very common here.

public func CGImageSourceCreateImageAtIndex(_ isrc: CGImageSource, _ index: Int, _ options: CFDictionary?) -> CGImage?
Copy the code

The following is a method of the UIImage class that instantiates the UIImage instance object. This method has three parameters: parameter 1 is the content required to build UIImage. Note that the content here is of CGImage type; parameter 2 is the conversion coefficient between the physical pixel of the mobile phone and the display resolution of the mobile phone; parameter 3 indicates the image direction of the constructed UIImage. Using this method, you can build an image with a given orientation at a certain phone resolution, of course the image type is UIImage.

public init(CGImage cgImage: CGImage, scale: CGFloat, orientation: UIImageOrientation)
Copy the code

UIImage has been obtained through the above two steps. However, UIImage is not the usual image format we see. The biggest feature of this image format is that it cannot be stored as a locally viewable image format, so if you need to save the image locally, You need to convert the OBTAINED UIImage data type to PNG or JPG image data before you can store the image locally.

Here is the complete GIF image decomposition save code:

override func viewDidLoad() { super.viewDidLoad() let gifPath:NSString = Bundle.main.path(forResource: "plane", ofType: "gif")! as NSString let gifData:Data = try! Data(contentsOf: URL(fileURLWithPath: gifPath as String)) let gifDataSource:CGImageSource = CGImageSourceCreateWithData(gifData as CFData, nil)! let gifImageCount:Int = CGImageSourceGetCount(gifDataSource) for i in 0... gifImageCount-1{ let imageref:CGImage? = CGImageSourceCreateImageAtIndex( gifDataSource, i, nil) let image:UIImage = UIImage(cgImage: imageref! , scale:UIScreen.main.scale, orientation:UIImageOrientation.up ) let imageData:Data = UIImagePNGRepresentation(image)! var docs=NSSearchPathForDirectoriesInDomains( .documentDirectory, .userDomainMask, true) let documentsDirectory = docs[0] as String let imagePath = documentsDirectory+"/\(i)"+".png" try? imageData .write(to: URL(fileURLWithPath: imagePath), options: [.atomic]) print("\(imagePath)") } }Copy the code

The first line of the code uses the UIImagePNGRepresentation method to store the UIImage data type as a PNG data type, the second and third lines get the Document directory of the application, and the fourth line calls the write method to write the image to a local file. If you want to see the effect of the final write, you can add print information in the last line, the file write path to print out, observe whether the image write successfully.

3 GIF image decomposition to achieve the final effect

Print (” (imagePath) “), the last line in the above code, gets the final path of the image. Enter this path and you can see the final decomposition result of the picture as shown below.



According to the figure above, in the Mac system, use the system image view tool to view the GIF image segmentation results, compared with the content in the figure, it can be seen that the GIF image decomposition results are correct.

Sequence images into GIF images

GIF picture synthesis ideas

Multi-frame image synthesis GIF process and GIF decomposition multi-frame image process of mutual inverse, GIF image decomposition process inverted push, is the process of GIF image synthesis. The 67 sequential single-frame images decomposed above are described here as the input source to be processed.

In terms of function, GIF image synthesis is divided into the following three main parts.

(1) Load 67 original data sources to be processed.

(2) Build GIF files in the Document directory.

(3) set GIF file properties, using ImageIO encoding GIF file.

2 GIF image synthesis code implementation

The following code is written according to the three main steps of GIF building. The first part of the code reads 67 PNG images into the NSMutableArray array. The first line of the code initializes the mutable array, the second line iterates through 67 local images, the third line constructs 67 image names according to the naming rules of images, and the fourth line loads local images. The last line loads the read images in turn into the images mutable array.

Let images:NSMutableArray = NSMutableArray() for I in 0... Let imagePath = "\(I).png" // Build imagename :UIImage = UIImage(named: imagePath)! // images.addobject (image)// Add the image to the array}Copy the code

The function of the second part of the code is to build the GIF file path in the Document directory. The specific implementation is shown as follows.

/ / range: in the Document directory to create GIF file var docs = NSSearchPathForDirectoriesInDomains (. DocumentDirectory,. UserDomainMask, true) let documentsDirectory = docs[0] as String let gifPath = documentsDirectory+"/plane.gif" print("\(gifPath)") let url = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, gifPath as CFString! , CFURLPathStyle.cfurlposixPathStyle, false) let destion = CGImageDestinationCreateWithURL(url! , kUTTypeGIF, images.count, nil)Copy the code

Code 1 line and the second line to obtain the Document path address, the third line of code through string splicing to form a complete Document path under the plane.gif file path. To make it easy to see where the GIF file is, line 4 prints out the GIF file path. Line 5 converts the plane. GIF file path from string to URL. The last line of code is a very important way to build GIF images in ImageIO, we focus on analyzing the role and function of this method.

public func CGImageDestinationCreateWithURL(_ url: CFURL, _ type: CFString, _ count: Int, _ options: CFDictionary?) -> CGImageDestination?
Copy the code

CGImageDestinationCreateWithURL method is used to create an image of the target object, in order to facilitate everybody understanding, here the image target compared to a collection.

CGImageDestination structure

The set describes a series of parameters that constitute the current image target object, such as the URL address of the image, the image type, the image frame number, configuration parameters and so on. This code passes the plane.gif local file path to the image object as parameter 1, parameter 2 describes the type of the image as a GIF image, parameter 3 indicates the number of frames currently constituted by the GIF image, and parameter 4 temporarily gives it a null value.

So far, the image source to be processed has been loaded into the code, and the GIF image Destination has been built. Now we need to use the ImageIO framework to encode multiple PNG images into GIF images. The processing process is as follows.

The specific implementation code is as follows:

// Part3: Set GIF properties, Using 67 PNG image build GIF let cgimagePropertiesDic = 0.1] [kCGImagePropertyGIFDelayTime as String: / / set the playback time between each frame cgimagePropertiesDestDic =Copy the code

[kCGImagePropertyGIFDictionary as String:cgimagePropertiesDic]; for cgimage in images{ CGImageDestinationAddImage(destion! , (cgimage as AnyObject).cgImage!! , cgimagePropertiesDestDic as CFDictionary?) ; }// Add each frame element in turn to the GIF image object

let gifPropertiesDic:NSMutableDictionary = NSMutableDictionary() gifPropertiesDic.setValue(kCGImagePropertyColorModelRGB, forKey: kCGImagePropertyColorModel as String) gifPropertiesDic.setValue(16, forKey: KCGImagePropertyDepth as String). / / set the color of the image depth gifPropertiesDic setValue (1, forKey: KCGImagePropertyGIFLoopCount as String) / / set the Gif execution times let gifDictionaryDestDic = [kCGImagePropertyGIFDictionary as String:gifPropertiesDic] CGImageDestinationSetProperties(destion! , gifDictionaryDestDic as CFDictionary?) ; / / set properties for GIF image CGImageDestinationFinalize (destion!) ;Copy the code

The first line of the code to set the GIF image properties, set the time interval of each frame in the current GIF image display to 0.1s. Line 2 builds a GIF image property dictionary that is initialized with the time interval between each GIF frame. Line 4 quickly appends the prepared image to the Destination of the GIF image using a traversal method. Line 5 initializes a mutable dictionary object that is used to set the properties of each frame in the GIF image. Line 6 sets the color space format of the picture to RGB (Red Green Blue) type. Line 7 sets the image color depth. Generally speaking, black and white images are also known as binary images, and the color depth is 1, representing 2 to the power of 1, namely two colors: black and white. The general color depth of grayscale image is 8, which means 2 to the power of 8. There are 256 colors in total, that is, there are 256 kinds of gradual change from black to white. For color pictures generally have 16 bit depth and 32 bit depth, here set to 16 bit depth color picture. Line 8 sets the number of times the GIF image is executed, in this case once. Lines 9 and 10 of the code take care of adding the various properties of the image set above to the Destination Destination of the GIF. The last line completes the build of the Destination target file for the GIF.

You can print out the path of the current GIF image. You can view the final GIF image in this path.

Gif image display

IOS native does not support the direct display of GIF images, which is composed of a single frame from the previous analysis, so as long as the decomposition of GIF images, the next is the problem of multiple groups of images display. This article introduces another image presentation form, that is, displaying GIF multi-frame images based on UIImageView.

After the analysis of GIF image display ideas, it can be known that there are two steps to display GIF images in iOS: the first step is to decompose GIF images into single frame images, and the second step is to display multi-frame images in iOS. UIImageView is a UI component that displays images, but it also has some animation properties that you can animate frame by frame.

Considering that the GIF image was decomposed in the first step, the decomposed 67 images are loaded in first.

UIImageView multi-frame image display concrete implementation code is as follows. Var images:[UIImage] = [] for I in 0… 66{// Let imagePath = “(I).png” // Build image name let image:UIImage = UIImage(named: imagePath)! Image.append (image)// Add the image to the array} let imageView = UIImageView() imageView.frame = self.view.bounds imageView.contentMode = UIViewContentMode.Center self.view.addSubview(imageView) imageView.animationImages = images imageView.animationDuration = 5 imageView.animationRepeatCount = 1 imageView.startAnimating()

Line 1 of this code initializes an array object whose child elements are of type UIImage. Lines 2 through 5 load the 67 images in sequence into the current array through a for loop. Line 6 instantiates a UIImageView instance object. Lines 7 and 8 set the frame position property of the UIImageView instance object and how the image is stretched, which is centered. Line 9 adds UIImageView to the self.view layer. Line 10 adds the initially-loaded 67 images to the animationImages of the UIImageView instance, setting the contents of the UIImageView. Line 11 sets the playback period of the UIImageView image animation. Line 12 sets the number of animation repeats. The last line launches the UIImageView multi-frame image display animation.