DEMO地址: https://github.com/lisiyuan1993/ImageCreatIncremental
Image I/O
Image I/O 基础
Image I/O framework提供不透明数据类型(opaque data types),从CGImageSourceRef获取图片数据,将图片数据写入到CGImageDestinationRef。它提供一个范围很广的图片格式,包含web格式,动态图,原始相机数据。
Image I/O framework 提供了两个类型来对图片进行操作:
CGImageSourceRef 负责对图片的读操作
CGImageDestinationRef 负责对图片的写操作
Image Source
如果图片太大或者图片需要下载, 可以使用 incremental image source(渐进式图片加载), 这样就可以边加载边显示图片
//SDWebImage下载图片二进制数据后的解码过程
- (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished {
//创建一个渐进式图片资源
if (!_imageSource) {
_imageSource = CGImageSourceCreateIncremental(NULL);
}
UIImage *image;
// 传递CFData和一个bool值,去描述这个数据是否包含全部图片数据或者只是部分数据。无论什么情况,这个data包含已经积累的全部图片文件。
// (__bridge CFDataRef)data 获取图片数据到CFData中
// Get the finish status -> BOOL finished = (totalSize(已下载数据) >= self.expectedSize(总数据));
//“final”参数在提供最终数据集时为真;否则错误
CGImageSourceUpdateData(_imageSource, (__bridge CFDataRef)data, finished);
if (_width + _height == 0) {
//通过CGImageSourceCopyPropertiesAtIndex 来获得图片资源里的图片所包含的所有属性的字典
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(_imageSource, 0, NULL);
if (properties) {
NSInteger orientationValue = 1;
CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight);
if (val) CFNumberGetValue(val, kCFNumberLongType, &_height);
val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth);
if (val) CFNumberGetValue(val, kCFNumberLongType, &_width);
val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation);
if (val) CFNumberGetValue(val, kCFNumberNSIntegerType, &orientationValue);
CFRelease(properties);
#if SD_UIKIT || SD_WATCH
_orientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:orientationValue];
#endif
}
}
if (_width + _height > 0) {
//如果已经累积了足够的数据, 通过CGImageSourceCreateImageAtIndex 创建图片, 并开始绘制这部分图片, 然后释放掉内存.
CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL);
#if SD_UIKIT || SD_WATCH
if (partialImageRef) {
const size_t partialHeight = CGImageGetHeight(partialImageRef);
CGColorSpaceRef colorSpace = SDCGColorSpaceGetDeviceRGB();
CGContextRef bmContext = CGBitmapContextCreate(NULL, _width, _height, 8, 0, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
if (bmContext) {
CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = _width, .size.height = partialHeight}, partialImageRef);
CGImageRelease(partialImageRef);
partialImageRef = CGBitmapContextCreateImage(bmContext);
CGContextRelease(bmContext);
}
else {
CGImageRelease(partialImageRef);
partialImageRef = nil;
}
}
#endif
if (partialImageRef) {
#if SD_UIKIT || SD_WATCH
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:1 orientation:_orientation];
#elif SD_MAC
image = [[UIImage alloc] initWithCGImage:partialImageRef size:NSZeroSize];
#endif
CGImageRelease(partialImageRef);
}
}
//释放 incremental image source
if (finished) {
if (_imageSource) {
CFRelease(_imageSource);
_imageSource = NULL;
}
}
return image;
}
Image Destinations
图形目标(Image Destinations)抽象出来了数据写入,并且消除了用户通过原始数据流来处理数据的需求。一个 image destination相当于一张图片或者一组图片,对于每张图片它可以包含缩略图和属性,在通过(URL, CFData,Quartz data consumer)创建CGImageDestination对象之后.可以向里面添加图片数据和设置图片属性。当设置完成之后,调用CGImageDestinationFinalize函数来结束。
//编码 (图片->二进制数据):
- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format {
if (!image) {
return nil;
}
if (format == SDImageFormatUndefined) {
BOOL hasAlpha = SDCGImageRefContainsAlpha(image.CGImage);
if (hasAlpha) {
format = SDImageFormatPNG;
} else {
format = SDImageFormatJPEG;
}
}
NSMutableData *imageData = [NSMutableData data];
CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:format];
// Create an image destination创建图形目标.
CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, 1, NULL);
if (!imageDestination) {
// Handle failure.
return nil;
}
NSMutableDictionary *properties = [NSMutableDictionary dictionary];
#if SD_UIKIT || SD_WATCH
NSInteger exifOrientation = [SDWebImageCoderHelper exifOrientationFromImageOrientation:image.imageOrientation];
[properties setValue:@(exifOrientation) forKey:(__bridge_transfer NSString *)kCGImagePropertyOrientation];
#endif
// Add your image to the destination.添加数据和图片
CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties);
// CGImageDestinationFinalize()完成数据写入
if (CGImageDestinationFinalize(imageDestination) == NO) {
// Handle failure.
imageData = nil;
}
CFRelease(imageDestination);
return [imageData copy];
}
从缓存中取出图片二进制数据后解码:
- (UIImage *)decodedImageWithData:(NSData *)data {
if (!data) {
return nil;
}
UIImage *image = [[UIImage alloc] initWithData:data];
#if SD_MAC
return image;
#else
if (!image) {
return nil;
}
UIImageOrientation orientation = [[self class] sd_imageOrientationFromImageData:data];
if (orientation != UIImageOrientationUp) {
image = [[UIImage alloc] initWithCGImage:image.CGImage scale:image.scale orientation:orientation];
}
return image;
#endif
}
参考:
图片处理:Image I/O 学习笔记https://www.jianshu.com/p/4dcd6e4bdbf0
网友评论