SDWebImage源码阅读(十三)UIImage+MultiFormat
这个 UIImage 的一个叫 MultiFormat 的分类,看名字可能已经猜到,UIImage 的多版本,主要功能是用来做 NSData 和 UIImage 的相互转化的。
.h
1 + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data; 2 - (nullable NSData *)sd_imageData; 3 - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat;
定义了 3 个方法,基本只是看方法名和返回值,已经基本猜到各个方法要实现的功能。
1.这是一个类方法,一个NSData 对象做参数,转化为一个 UIImage 对象返回。
2.这是一个实例方法,把调取该方法的 UIImage 对象的 NSData 数据返回。
3.获取 UIImage 的指定图片类型的 NSData 数据。
.m
1 + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data { 2 if (!data) { 3 return nil; 4 } 5 6 UIImage *image; 7 SDImageFormat imageFormat = [NSData sd_imageFormatForImageData:data]; 8 if (imageFormat == SDImageFormatGIF) { 9 image = [UIImage sd_animatedGIFWithData:data]; 10 } 11 #ifdef SD_WEBP 12 else if (imageFormat == SDImageFormatWebP) 13 { 14 image = [UIImage sd_imageWithWebPData:data]; 15 } 16 #endif 17 else { 18 image = [[UIImage alloc] initWithData:data]; 19 #if SD_UIKIT || SD_WATCH 20 UIImageOrientation orientation = [self sd_imageOrientationFromImageData:data]; 21 if (orientation != UIImageOrientationUp) { 22 image = [UIImage imageWithCGImage:image.CGImage 23 scale:image.scale 24 orientation:orientation]; 25 } 26 #endif 27 } 28 29 30 return image; 31 }
把 NSData 转化为 UIImage。
如果 data 不存在,则直接返回 nil。
根据 data 判断 UIImage 的后缀类型并赋值给 imageFormat。
如果 imageFormat 是 SDImageFormatGIF,调用 sd_animatedGIFWithData: 把 data 转化为图片。
如果 imageFormat 是 SDImageFormatWebP 则做相应的处理,这里并没有给出。
其他的情况:
直接调用 initWithData: 把 data 转化为 UIImage。
如果是 iOS 平台开发或者 TV 平台开发或者 WATCH 平台开发,使用 data 调用 sd_imageOrientationFromImageData: 获取图片的方向并赋值给 orientation。
如果 orientation 不等于 UIImageOrientationUP (默认方向),则调用:
1 + (UIImage *)imageWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(UIImageOrientation)orientation NS_AVAILABLE_IOS(4_0);
重新调整图片方向。
最后返回 iamge。
1 +(UIImageOrientation)sd_imageOrientationFromImageData:(nonnull NSData *)imageData { 2 UIImageOrientation result = UIImageOrientationUp; 3 CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL); 4 if (imageSource) { 5 CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL); 6 if (properties) { 7 CFTypeRef val; 8 int exifOrientation; 9 val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation); 10 if (val) { 11 CFNumberGetValue(val, kCFNumberIntType, &exifOrientation); 12 result = [self sd_exifOrientationToiOSOrientation:exifOrientation]; 13 } // else - if it's not set it remains at up 14 CFRelease((CFTypeRef) properties); 15 } else { 16 //NSLog(@"NO PROPERTIES, FAIL"); 17 } 18 CFRelease(imageSource); 19 } 20 return result; 21 }
根据 imageData 获取图片的方向。
1 #pragma mark EXIF orientation tag converter 2 // Convert an EXIF image orientation to an iOS one. 3 // reference see here: http://sylvana.net/jpegcrop/exif_orientation.html 4 + (UIImageOrientation) sd_exifOrientationToiOSOrientation:(int)exifOrientation { 5 UIImageOrientation orientation = UIImageOrientationUp; 6 switch (exifOrientation) { 7 case 1: 8 orientation = UIImageOrientationUp; 9 break; 10 11 case 3: 12 orientation = UIImageOrientationDown; 13 break; 14 15 case 8: 16 orientation = UIImageOrientationLeft; 17 break; 18 19 case 6: 20 orientation = UIImageOrientationRight; 21 break; 22 23 case 2: 24 orientation = UIImageOrientationUpMirrored; 25 break; 26 27 case 4: 28 orientation = UIImageOrientationDownMirrored; 29 break; 30 31 case 5: 32 orientation = UIImageOrientationLeftMirrored; 33 break; 34 35 case 7: 36 orientation = UIImageOrientationRightMirrored; 37 break; 38 default: 39 break; 40 } 41 return orientation; 42 } 43 #endif
根据 exifOrientation 获得对应的 UIImageOrientation。
1 - (nullable NSData *)sd_imageData { 2 return [self sd_imageDataAsFormat:SDImageFormatUndefined]; 3 } 4 5 - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat { 6 NSData *imageData = nil; 7 if (self) { 8 #if SD_UIKIT || SD_WATCH 9 int alphaInfo = CGImageGetAlphaInfo(self.CGImage); 10 BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone || 11 alphaInfo == kCGImageAlphaNoneSkipFirst || 12 alphaInfo == kCGImageAlphaNoneSkipLast); 13 14 BOOL usePNG = hasAlpha; 15 16 // the imageFormat param has priority here. But if the format is undefined, we relly on the alpha channel 17 if (imageFormat != SDImageFormatUndefined) { 18 usePNG = (imageFormat == SDImageFormatPNG); 19 } 20 21 if (usePNG) { 22 imageData = UIImagePNGRepresentation(self); 23 } else { 24 imageData = UIImageJPEGRepresentation(self, (CGFloat)1.0); 25 } 26 #else 27 NSBitmapImageFileType imageFileType = NSJPEGFileType; 28 if (imageFormat == SDImageFormatGIF) { 29 imageFileType = NSGIFFileType; 30 } else if (imageFormat == SDImageFormatPNG) { 31 imageFileType = NSPNGFileType; 32 } 33 34 imageData = [NSBitmapImageRep representationOfImageRepsInArray:self.representations 35 usingType:imageFileType 36 properties:@{}]; 37 #endif 38 } 39 return imageData; 40 }
获取 UIImage 对象的 NSData 数据。
当不指定 imageFormat 的时候,使用 SDImageFormatUndefined。
当 imageFormat 是 SDImageFormatUndefined 的时候根据 alphaInfo 判断,hasAlpha 是假的时候(没有 alpha 信息的时候)使用
UIImageJPEGRepresentation 转化,把 UIImage 对象转化为 JPEG 类型的 NSData 数据,相反的有 alpha 的时候转化为 PNG 类型的 NSData 数据。
如果 imageFormat 是 SDImageFormatPNG 的时候,则直接转化为 PNG 类型NSData 数据。
下面有一篇:
1 UIKIT_EXTERN NSData * __nullable UIImagePNGRepresentation(UIImage * __nonnull image); // return image as PNG. May return nil if image has no CGImageRef or invalid bitmap format 2 UIKIT_EXTERN NSData * __nullable UIImageJPEGRepresentation(UIImage * __nonnull image, CGFloat compressionQuality); // return image as JPEG. May return nil if image has no CGImageRef or invalid bitmap format. compression is 0(most)..1(least)
两者的比较。
参考链接:http://blog.csdn.net/mideveloper/article/details/11473627
http://www.jianshu.com/p/b9d415188c42
END