WebP and ioswebp for iOS Performance
Today, most of the Internet, regardless of web pages or apps, consumes the most traffic because of images. The better the user experience, the higher the dependence on images. However, images are a double-edged sword that brings the user experience and attracts the user's attention, but affects the performance, because the network request time is relatively long.
There are many types of images, including Bitmap (BMP), jpg (JPEG, lossy compression format), and png (lossless compression format, the image size and definition are as follows: BMP> png> jpg. Jpg is a lossy compression format, so jpg images are relatively minimal. For iOS, png is the most preferred image (which is officially recommended by Apple ).
However, there is an image format that is smaller in size than png, and the image quality is similar to png, that is, WebP.
What is WebP?
In a brief description, WebP is an image format created by google. Image Compression and decoding are completed by the APIS provided by google (available in various languages, however, it seems that js can decode WebP). In the case of lossless compression, it is about 28% smaller than png.
It is now compatible with major browser vendors (such as Chrome and Firefox), but Apple's Safri is not compatible with this format. Therefore, if UIWebView contains WebP images, it will not be displayed (but we can use NSUrlProtocol for processing ). If you want to use it in an APP, we need to introduce the SDWebImage third-party library.
Use WebP for SDWebImage
This third-party library is well encapsulated and used in the same way as we used it to load network images, as shown below:
[imageView sd_setImageWithURL: [NSURL URLWithString: image path] placeholderImage: [UIImage imageNamed: @ "default image"] completed: ^ (UIImage * image, NSError * error, SDImageCacheType cacheType, NSURL * imageURL) {}];
However, we have to take a closer look at how he did it.
We open:
SDWebImageDownloaderOperation
This class inherits NSOperation and mainly uses NSUrlSession to download network pictures. Let's take a look at the delegate method that he has downloaded:
-(void) URLSession: (NSURLSession *) session task: (NSURLSessionTask *) task didCompleteWithError: (NSError *) error
We intercept part of the code block to focus on analysis:
UIImage * image = [UIImage sd_imageWithData: self.imageData];
Debug in:
UIImage * image;
NSString * imageContentType = [NSData sd_contentTypeForImageData: data]; // judge the picture type according to the first 8 bits of the data stream
if ([imageContentType isEqualToString: @ "image / gif"]) {
image = [UIImage sd_animatedGIFWithData: data];
}
#ifdef SD_WEBP
else if ([imageContentType isEqualToString: @ "image / webp"])
{
image = [UIImage sd_imageWithWebPData: data]; // Decode WebP into the corresponding format (may be jpg, png, etc.)
}
#endif
else {
image = [[UIImage alloc] initWithData: data];
UIImageOrientation orientation = [self sd_imageOrientationFromImageData: data];
if (orientation! = UIImageOrientationUp) {
image = [UIImage imageWithCGImage: image.CGImage
scale: image.scale
orientation: orientation];
}
}
Let's talk about the sd_contentTypeForImageData method as follows:
+ (NSString *) sd_contentTypeForImageData: (NSData *) data {
uint8_t c;
[data getBytes: & c length: 1];
switch (c) {
case 0xFF:
return @ "image / jpeg";
case 0x89:
return @ "image / png";
case 0x47:
return @ "image / gif";
case 0x49:
case 0x4D:
return @ "image / tiff";
case 0x52:
// R as RIFF for WEBP
if ([data length] <12) {
return nil;
}
NSString * testString = [[NSString alloc] initWithData: [data subdataWithRange: NSMakeRange (0, 12)] encoding: NSASCIIStringEncoding];
if ([testString hasPrefix: @ "RIFF"] && [testString hasSuffix: @ "WEBP"]) {
return @ "image / webp";
}
return nil;
}
return nil;
}
The uint8_t inside is the first 8 bits of NSData, because after the picture is converted to NSData, it is expressed in ASCII code, and each picture contains a fixed header information block.
png is: 89 50 4E 47 0D 0A 1A 0A
bmp is: 42 4D
jpg is: FF D8 FF
webp is: 52 49 46 46 The middle 4 characters are indefinite 57 45 42 50 (translated as: RIFF other 4 characters WEBP)
In this way, the meaning of the above code is relatively clear.
If you want to learn more about a format and its composition, here is a good article:
http://blog.csdn.net/hherima/article/details/45846901
Let's take a look at the sd_imageWithWebPData method
It encapsulates the process of decoding WebP into pictures in other formats. WebP uses the VP8 encoding format. If you are interested, you can study the specific algorithm implementation process. Here are a few articles introducing WebP compression algorithms.
https://developers.google.com/speed/webp/docs/compression
http://blog.csdn.net/leixiaohua1020/article/details/12760173
remind
When SDWebImage stores WebP, it stores undecoded NSData instead of decoded NSData. The following code:
SDWebImageManager
if (options & SDWebImageRefreshCached && image &&! downloadedImage) {
// Image refresh hit the NSURLCache cache, do not call the completion block
}
else if (downloadedImage && (! downloadedImage.images || (options & SDWebImageTransformAnimatedImage)))) {
dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
UIImage * transformedImage = [self transformDownloadedImage: downloadedImage imageData: data withURL: url]; // Do you want to convert nsdata to other format image object before storing
if (transformedImage && finished) {
BOOL imageWasTransformed =! [TransformedImage isEqual: downloadedImage];
[self.imageCache storeImage: transformedImage recalculateFromImage: imageWasTransformed imageData: (imageWasTransformed? nil: data) forKey: key toDisk: cacheOnDisk];
}
dispatch_main_sync_safe (^ {
if (strongOperation &&! strongOperation.isCancelled) {
completedBlock (transformedImage, nil, SDImageCacheTypeNone, finished, url);
}
});
});
}
else {
if (downloadedImage && finished) {
[self.imageCache storeImage: downloadedImage recalculateFromImage: NO imageData: data forKey: key toDisk: cacheOnDisk]; // WebP storage is taking this step
}
dispatch_main_sync_safe (^ {
if (strongOperation &&! strongOperation.isCancelled) {
completedBlock (downloadedImage, nil, SDImageCacheTypeNone, finished, url);
}
});
}
It provides a delegate:
UIImage * transformedImage = [self transformDownloadedImage: downloadedImage imageData: data withURL: url];
It can be considered hard work, because it may take into account that WebP decoding will take some time (tested and found that WebP around 120k, decoding will take about 30ms), so provide a commission, you can choose to convert WebP NSData to png jpAfter g, store it in memory and then store it in disk.
However, time and space are like fish and bear's paws, and they can't have both. If you choose to save time, you will inevitably take up more space. In the end choose time or space, benevolence sees benevolence see wisdom.
Disadvantages of WebP
WebP is said to be so small, but WebP also has its own disadvantages:
At last
Regarding the picture size comparison between WebP and jpg, because WebP supports lossless and lossy compression, and jpg is a lossy compression format, so if the same pictures are lossy compressed, WebP is smaller than jpg.
Here is a good article about WebP:
https://isux.tencent.com/introduction-of-webp.html