Large Image Downsizing

官方文档Large Image Downsizing
https://developer.apple.com/library/content/samplecode/LargeImageDownsizing/Introduction/Intro.html

#define bytesPerMB 1048576.0f   //1MB=1024KB=1024*1024字节
#define bytesPerPixel 4.0f              //1像素4字节
#define pixelsPerMB ( bytesPerMB / bytesPerPixel )  //1MB中有多少像素

//use the width and height to calculate the total number of pixels in the input image.
sourceTotalPixels = sourceResolution.width * sourceResolution.height;

//calculate the number of MB that would be required to store this image uncompressed in memory.
sourceTotalMB = sourceTotalPixels / pixelsPerMB;

//根据机型设置 期望的未压缩的图片大小 kDestImageSizeMB, 并 * pixelsPerMB = destTotalPixels (期望的像素大小) 
//计算出压缩倍数
 imageScale = destTotalPixels / sourceTotalPixels;  

//得出期望的宽高
destResolution.width = (int)( sourceResolution.width * imageScale );
destResolution.height = (int)( sourceResolution.height * imageScale );

// create an offscreen bitmap context that will hold the output image pixel data, 
// as it becomes available by the downscaling routine.
// use the RGB colorspace as this is the colorspace iOS GPU is optimized for.
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

//bitmap的每一行在内存所占的比特数
int bytesPerRow = bytesPerPixel * destResolution.width;
// allocate enough pixel data to hold the output image.
void* destBitmapData = malloc( bytesPerRow * destResolution.height );
 // create the output bitmap context
destContext = CGBitmapContextCreate( destBitmapData, destResolution.width, destResolution.height, 8, 
              bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast );

//通过调用CGContextTranslateCTM函数来修改每个点的x, y坐标值
CGContextTranslateCTM( destContext, 0.0f, destResolution.height );
//缩放操作根据指定的x, y因子来改变坐标空间的大小,从而放大或缩小图像。
//x, y因子的大小决定了新的坐标空间是否比原始坐标空间大或者小。
//另外,通过指定x因子为负数,可以倒转x轴,同样可以指定y因子为负数来倒转y轴。
CGContextScaleCTM( destContext, 1.0f, -1.0f );

// sub rect of the input image bounds that represents the 
// maximum amount of pixel data to load into mem at one time.
CGRect sourceTile;
sourceTile.size.width = sourceResolution.width;
kSourceImageTileSizeMB  
//设置压缩时对于源图像使用到的*块*的最大字节数。  
//The tile size will be (x)MB of uncompressed image data.
#define tileTotalPixels kSourceImageTileSizeMB * pixelsPerMB
sourceTile.size.height = (int)( tileTotalPixels / sourceTile.size.width );  


函数原型:
CGContextRef CGBitmapContextCreate (
   void *data,
   size_t width,
   size_t height,
   size_t bitsPerComponent,
   size_t bytesPerRow,
   CGColorSpaceRef colorspace,
   CGBitmapInfo bitmapInfo
);

参数:
data         指向要渲染的绘制内存的地址。这个内存块的大小至少是(bytesPerRow*height)个字节
width       bitmap的宽度,单位为像素
height       bitmap的高度,单位为像素
bitsPerComponent        内存中像素的每个组件的位数.例如,对于32位像素格式和RGB 颜色空间,你应该将这个值设为8.
bytesPerRow   bitmap的每一行在内存所占的比特数
colorspace       bitmap上下文使用的颜色空间。
bitmapInfo      指定bitmap是否包含alpha通道,像素中alpha通道的相对位置,像素组件是整形还是浮点型等信息的字符串。

描述:
当你调用这个函数的时候,Quartz创建一个位图绘制环境,也就是位图上下文。当你向上下文中绘制信息时,
Quartz把你要绘制的信息作为位图数据绘制到指定的内存块。
一个新的位图上下文的像素格式由三个参数决定:
每个组件的位数,颜色空间,alpha选项。alpha值决定了绘制像素的透明性。
iOS kCGImageAlphaPremultipliedLast与kCGImageAlphaLast区别和联系
原文 http://blog.csdn.net/jeffasd/article/details/78142067
typedef CF_ENUM(uint32_t, CGImageAlphaInfo) {

    kCGImageAlphaNone,               /* For example, RGB. */

    kCGImageAlphaPremultipliedLast,  /* For example, premultiplied RGBA */

    kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */

    kCGImageAlphaLast,               /* For example, non-premultiplied RGBA */

    kCGImageAlphaFirst,              /* For example, non-premultiplied ARGB */

    kCGImageAlphaNoneSkipLast,       /* For example, RBGX. */

    kCGImageAlphaNoneSkipFirst,      /* For example, XRGB. */

    kCGImageAlphaOnly                /* No color data, alpha data only */

};

CGImageAlphaInfo包含以下信息:

*   是否包含 alpha ;
*   如果包含 alpha ,那么 alpha 信息所处的位置,在像素的[最低有效位](https://zh.wikipedia.org/wiki/%E6%9C%80%E4%BD%8E%E6%9C%89%E6%95%88%E4%BD%8D),比如 RGBA ,还是[最高有效位](https://zh.wikipedia.org/wiki/%E6%9C%80%E9%AB%98%E6%9C%89%E6%95%88%E4%BD%8D),比如 ARGB ;
*   如果包含 alpha ,那么每个颜色分量是否已经乘以 alpha 的值,这种做法可以加速图片的渲染时间,因为它避免了渲染时的额外乘法运算。比如,对于 RGB 颜色空间,用已经乘以 alpha 的数据来渲染图片,每个像素都可以避免 3 次乘法运算,红色乘以 alpha ,绿色乘以 alpha 和蓝色乘以 alpha 。

那么我们在解压缩图片的时候应该使用哪个值呢?根据 [Which CGImageAlphaInfo should we use](http://stackoverflow.com/questions/23723564/which-cgimagealphainfo-should-we-use)和官方文档中对 UIGraphicsBeginImageContextWithOptions 函数的讨论:

You use this function to configure the drawing environment for rendering into a bitmap. The format for the bitmap is a ARGB 32-bit integer pixel format using host-byte order. If the opaque parameter is YES, the alpha channel is ignored and the bitmap is treated as fully opaque (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host). Otherwise, each pixel uses a premultipled ARGB format (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host).

我们可以知道,当图片不包含 alpha 的时候使用 kCGImageAlphaNoneSkipFirst ,否则使用 kCGImageAlphaPremultipliedFirst 。

alpha 通道布局信息,实际上也有一个枚举值:

typedef CF_ENUM(uint32_t, CGImageAlphaInfo) {

    kCGImageAlphaNone,               /* For example, RGB. */

    kCGImageAlphaPremultipliedLast,  /* For example, premultiplied RGBA */

    kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */

    kCGImageAlphaLast,               /* For example, non-premultiplied RGBA */

    kCGImageAlphaFirst,              /* For example, non-premultiplied ARGB */

    kCGImageAlphaNoneSkipLast,       /* For example, RBGX. */

    kCGImageAlphaNoneSkipFirst,      /* For example, XRGB. */

    kCGImageAlphaOnly                /* No color data, alpha data only */

};

上面的注释其实写很清楚,如果没有 alhpa 分量,那就是 kCGImageAlphaNone。带有 skip 的两个 kCGImageAlphaNoneSkipLast和kCGImageAlphaNoneSkipFirst即有 alpha 分量,但是忽略该值,相当于透明度不起作用。kCGImageAlphaOnly只有 alpha 值,没有颜色值。另外 4 个都表示带有 alpha 通道。带有 Premultiplied,说明在图片解码压缩的时候,就将 alpha 通道的值分别乘到了颜色分量上,我们知道 alpha 就会影响颜色的透明度,我们如果在压缩的时候就将这步做掉了,那么渲染的时候就不必再处理 alpha 通道了,这样可以提高渲染速度。First 和 Last的区别就是 alpha 分量是在像素存储的哪一边。例如一个像素点32位,表示4个分量,那么从左到右,如果是 ARGB,就表示 alpha 分量在 first,RGBA 就表示 alpha 分量在 last。

综上可知:kCGImageAlphaPremultipliedLast提前把alpha信息和RGB做了相乘已经把计算结果计算好了,这样在显示位图的时候直接显示就行了,这样就提高了性能,而kCGImageAlphaLast没有计算alpha的值,这样的话在显示位图的时候就需要计算alpha信息,导致性能低下。能使用kCGImageAlphaPremultipliedLast就尽量使用。
参考文章:
[http://blog.imerc.xyz/2017/07/09/ios-image-decode/](http://blog.imerc.xyz/2017/07/09/ios-image-decode/)
[http://blog.leichunfeng.com/blog/2017/02/20/talking-about-the-decompression-of-the-image-in-ios/](http://blog.leichunfeng.com/blog/2017/02/20/talking-about-the-decompression-of-the-image-in-ios/)

你可能感兴趣的:(Large Image Downsizing)