美文网首页
SDWebImage图片处理:Image I/O 学习

SDWebImage图片处理:Image I/O 学习

作者: nucky_lee | 来源:发表于2019-03-01 12:02 被阅读0次

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

相关文章

网友评论

      本文标题:SDWebImage图片处理:Image I/O 学习

      本文链接:https://www.haomeiwen.com/subject/zsfduqtx.html