iOS正确获取图片参数深入探究及CGImageRef的使用

news2024/11/21 1:36:26

一 图片参数的正确获取

先拿一张图片作为测试使用
测试图片
图片参数如下:
图片参数
图片的尺寸为:
-宽1236个像素点
-高748个像素点
-色彩空间为RGB
-描述文件为彩色LCD
-带有Alpha通道
请记住这几个参数,待会儿我们演示如何正确获取。

将这张图片分别放在三个位置
位置1: 2x图位置
在这里插入图片描述

位置2: 3x图位置
在这里插入图片描述

位置3: bundle中
在这里插入图片描述

然后我们通过代码分别获取这三个不同位置的图片,然后输出他的宽高以及CGImageRef对象获取的宽高,代码如下:
在这里插入图片描述
输出结果如图所示:

在这里插入图片描述

会发现,如果单纯的使用[UIImage imageNamed:@“”];方法来获取图片之后,直接输出图片的宽高和图片的原尺寸是不相符的:
如果是2X位置的图片,输出的高度为图片真实高度/2的结果
如果是3X位置的图片,输出的高度为图片真实高度/3的结果
如果是从bundle中直接获取图片,输出的宽高为真实的结果。
原因是因为IOS会根据我们存放图片的位置不同,在加载的时候对比例进行处理,如果只是单纯的展示的话并不会有问题,但是如果是做图片区域裁剪,那么需要注意使用[UIImage imageNamed:@“”]获取到的图片对象的size并不是图片的真实尺寸,而是要使用CGImageRef来获取到图像的结构体指针,再去获取到真正的图片尺寸。

官方文档里对[UIImage imageNamed:@“”]是这样描述的:
在这里插入图片描述
系统会从缓存中寻找这张图片,并对图片进行适当调整以返回适合屏幕显示的图片,所以如果这张图片在项目中会多次用到,那么可以用这个方法来加载图片以提高内存资源利用效率和加载速度,如果只是使用一次的话,更推荐使用imageWithContentsOfFile:方法来加载图片,这样图片不会被加载到缓存中,较少内存压力。

二 使用CGImageRef获得图片的详细参数

CGImageRef中还存储了很多图片的信息,打印一下
在这里插入图片描述
可以看到输出的参数有:
CGColorSpace
kCGColorSpaceICCBased : ICCBased颜色空间 ICCBased颜色空间基于 ICC( 国际色彩组织 ) 制定的跨平台颜色配置文件
kCGColorSpaceModelRGB:使用RGB颜色空间
LCD : 使用LCD色域
width = 1236 :图片的宽度为1236个像素点
height = 748 :图片的高度为748个像素点
bpc = 8:每个通道有8bit 也就是支持256个色值
bpp = 32: 每个像素有32位,R通道8位 + G通道8位 + B通道8位 + A通道8位 = 32位
row bytes = 4944:每行占用4944个字节,计算公式为(每个像素32位*每行1236个像素点/8bit = 4944字节
kCGImageAlphaNoneSkipLast : 有alpha通道,且在最末尾,但是不存储alhpa值
0 (default byte order):这个其实存储的是CGBitmapInfo,使用默认的字节序
kCGImagePixelFormatPacked:像素格式信息,根据像素格式压缩
is mask? No:是否为Mask图层,Mask图层是设置其显示部分与不显示部分达到特殊的效果的方法
has masking color? No:是否有mask color,如果设置有的话对应的颜色会变成透明
has soft mask:是否有渐变遮罩
has matte? No:是否有蒙版,mask和matte两个的作用都是控制图像的透明区域的。通常mask都是在图层(节点)上临时绘制的。而matte很多时候都是使用现成的黑白图作为控制透明区域的图来使用。
should interpolate? Yes:是否抗锯齿

使用CGImageRef 我们几乎可以获得我们想要的任何参数。

三 获取CGImageRef属性值的常用方法

先获取到CGImageRef的引用,本章节介绍的方法全部基于该引用演示:

	UIImage *img = [UIImage imageNamed:@"8BitImg2x"];
	CGImageRef imgRef = [img CGImage];

1.获取图片的宽度

size_t CGImageGetWidth(CGImageRef cg_nullable image)

该方法返回一个sizt_t类型的数值,size_t 的全称是size type,是无符号整型,size_t的真实类型与操作系统有关。
在32位的系统中定义为 typedef unsigned int size_t;
在64位系统中定义为 typedef unsigned long size_t;
使用的时候把它作为无符号整数使用就可以了

CGImageGetWidth方法返回图片的像素宽度,使用及输出示例如下:

    size_t imgWidth = CGImageGetWidth(imgRef);
    printf("图片的像素宽度为:%zu",imgWidth);
	输出结果:图片的像素宽度为:1236

2.获取图片的高度

size_t CGImageGetHeight(CGImageRef cg_nullable image)

跟获取图片宽度的方法类似,该方法返回图片的高度,使用示例及结果输出如下

	size_t imgHeight = CGImageGetHeight(imgRef);
    printf("图片的像素高度为:%zu",imgHeight);
	输出结果:图片的像素高度为:748

3.获取图片每个颜色通道占用的位数(bpp)

CGImageGetBitsPerComponent(CGImageRef cg_nullable image)

使用及输出示例如下:

    size_t bitsPerComponent = CGImageGetBitsPerComponent(imgRef);
    printf("每个通道占用的位数:%zu",bitsPerComponent);
	输出结果:每个通道占用的位数:8

4.获取每个像素点占用的位数

size_t CGImageGetBitsPerPixel(CGImageRef cg_nullable image)

使用及输出示例如下:

	size_t bitsPerPixel = CGImageGetBitsPerPixel(imgRef);
    printf("每个像素占用的位数:%zu",bitsPerPixel);
	输出结果:每个像素占用的位数:32

其实通过CGImageGetBitsPerComponent方法及CGImageGetBitsPerPixel,我们已经可以得知该图片格式为32位,每个通道8位,所以该图片也就是4通道,RGBA格式,带有alpha通道的图片,这在我们需要判断图片是否带有alpha通道的场景下还是很有用的。

针对这个方法,文尾还有更进一步的深究,一定要看。(划重点)

5.获取每行像素占用的字节数

size_t CGImageGetBytesPerRow(CGImageRef cg_nullable image)

使用及输出示例如下:

    size_t bitsPerRow = CGImageGetBytesPerRow(imgRef);
    printf("每行像素占用的位数:%zu",bitsPerRow);
	输出结果:每行像素占用的位数:4944

计算方法为:图片的宽度1236(宽有1236个像素点) * 每个像素占用的位数32 ÷ 每个字节的位数8(1byte = 8bit) = 每行像素占用的字节数4944

6.获取图片的颜色空间

CGColorSpaceRef __nullable CGImageGetColorSpace(CGImageRef cg_nullable image)

使用及输出示例如下:

    CGColorSpaceRef colorSpaceRef = CGImageGetColorSpace(imgRef);
    NSLog(@"颜色空间为%@",colorSpaceRef);

如果是8位三通道的图片,那么CGImageGetBitsPerPixel方法返回的结果就是24,拿一张不带alpha通道的图片验证一下:
使用及输出示例如下:

	输出结果:颜色空间为<CGColorSpace 0x60000151fea0> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1)

代表使用的是RGB颜色空间

7.获取图片的alpha信息

使用及输出示例如下:

    CGImageAlphaInfo imageAlphaInfo = CGImageGetAlphaInfo(imgRef);
    NSLog(@"alpha通道信息为 %u",imageAlphaInfo);
	输出结果:alpha通道信息为 5

通过CGImageAlphaInfo的枚举值来查阅

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 */
};

可知该图片的alpha信息为kCGImageAlphaNoneSkipLast,代表该图片有alpha通道且在末尾,但是忽略该值,并不参与图片实际显示的计算。

CGImageAlphaInfo的作用:
(1)位图是否包含alpha通道
(2)alpha位在图像数据中的位置,在bimap首位还是末尾
(3)alpha值是否被预乘,在显示的时候是否需要将每个通道的值乘上alpa值作为最终展示的值
Alpha混合是通过使用线性插值公式将源图像的颜色分量与目标图像的颜色成分相结合来实现的。

对于每个枚举值的说明如下
kCGImageAlphaFirst 阿尔法分量存储在每个像素的最高有效位中。例如,非预乘ARGB。
kCGImageAlphaLast 阿尔法分量被存储在每个像素的最低有效位中。例如,非预乘RGBA。
kCGImageAlphaNone 没有alpha通道。
kCGImageAlphaNoneSkipFirst 没有alpha通道。如果像素的总大小大于颜色空间中颜色分量数量所需的空间,则忽略最高有效位。
kCGImageAlphaOnly 没有颜色数据,只有一个alpha通道。
kCGImageAlphaNoneSkipLast 没有alpha通道。
kCGImageAlphaPremultipliedFirst 阿尔法分量存储在每个像素的最高有效位中,并且颜色分量已经乘以该阿尔法值。例如,预乘ARGB。
kCGImageAlphaPremultipliedLast 阿尔法分量存储在每个像素的最低有效位中,并且颜色分量已经乘以该阿尔法值。例如,预乘RGBA。

8.获取像素点里的字节排序

CGImageByteOrderInfo CGImageGetByteOrderInfo(CGImageRef cg_nullable image)

使用及输出示例如下:

    CGImageByteOrderInfo imageByteOrderInfo = CGImageGetByteOrderInfo(imgRef);
    NSLog(@"imageByteOrderInfo信息为 %d",imageByteOrderInfo);
	输出结果:imageByteOrderInfo信息为 0

CGImageByteOrderInfoCGImageAlphaInfo的枚举值来查阅

typedef CF_ENUM(uint32_t, CGImageByteOrderInfo) {
    kCGImageByteOrderMask     = 0x7000,
    kCGImageByteOrderDefault  = (0 << 12),
    kCGImageByteOrder16Little = (1 << 12),
    kCGImageByteOrder32Little = (2 << 12),
    kCGImageByteOrder16Big    = (3 << 12),
    kCGImageByteOrder32Big    = (4 << 12)
} CG_AVAILABLE_STARTING(10.0, 2.0);

可知该图片使用的字节排序位默认排序kCGImageByteOrderDefault

CGImageByteOrderInfo定义了一个bitmap中像素读取的顺序,主要分为大端小端读取模式
大端模式:高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中
小端模式:高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中
苹果手机使用的是小端读取模式,如果在做到需要配置像素字节读取顺序这种需求的时候,需要留意一下像素字节的读取顺序,如果读取错误的话会导致颜色和图片的显示错误

常用枚举值的定义如下
kCGImageByteOrder16Little 16位小端读取
kCGImageByteOrder16Big 16位大端读取
kCGImageByteOrder32Little 32位小端读取
kCGImageByteOrder32Big 23位大端读取

需要注意,quartz 2D引擎在iOS端只支持 kCGImageByteOrderDefault,kCGImageByteOrder16Little,kCGImageByteOrder16Big这三种读取模式

8.获取图片的CGBitmapInfo信息

CGBitmapInfo CGImageGetBitmapInfo(CGImageRef cg_nullable image)

使用及输出示例如下:

    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imgRef);
    NSLog(@"bitmapInfo信息为 %d",bitmapInfo);
	输出结果:bitmapInfo信息为 5

枚举值定义如下:

typedef CF_OPTIONS(uint32_t, CGBitmapInfo) {
    kCGBitmapAlphaInfoMask = 0x1F,

    kCGBitmapFloatInfoMask = 0xF00,
    kCGBitmapFloatComponents = (1 << 8),

    kCGBitmapByteOrderMask     = kCGImageByteOrderMask,
    kCGBitmapByteOrderDefault  = kCGImageByteOrderDefault,
    kCGBitmapByteOrder16Little = kCGImageByteOrder16Little,
    kCGBitmapByteOrder32Little = kCGImageByteOrder32Little,
    kCGBitmapByteOrder16Big    = kCGImageByteOrder16Big,
    kCGBitmapByteOrder32Big    = kCGImageByteOrder32Big
} CG_AVAILABLE_STARTING(10.0, 2.0);

需要注意,CGBitmapInfo 在使用的时候是需要跟适当的常量使用 | 操作符配合链接使用的 ,官方文档解释如下:
在这里插入图片描述
所以我们在定义CGBitmapInfo作为参数传值使用的时候,一般会使用CGImageAlphaInfo及CGImageByteOrderInfo搭配使用,来定义图片是否含有alpha通道及读取顺序,举例如下:

CGBitmapInfo alphaInfo = = kCGImageAlphaLast  | kCGImageByteOrder16Little; //alpha通道在末尾,且使用16位小端读取的方式来读取

所以使用CGImageGetBitmapInfo获取该图片的信息输出5,应该搭配文初获取的图片信息来看
在这里插入图片描述
kCGImageAlphaNoneSkipLast | kCGImageByteOrderDefault = 5
所以当我们直接获取CGBitmapInfo的值的时候,图片输出结果为5

其余的几种方法使用频率较低,可以翻阅api文档查阅

附: CGImageGetBitsPerPixel深究

在实际的项目开发中,使用CGImageGetBitsPerPixel获取的图片位数也并不一定准确
接下来使用五张不同的图片来演示CGImageGetBitsPerPixel获取像素位数的问题:

第一张图片 格式为 8bpc 24bpp 的Png格式的图片,也就是每通道有8位,不带alpha通道,bitmap为24位,但是使用CGImageGetBitsPerPixel输出的结果却是32位,结果错误

第二张图片 格式为 8bpc 24bpp 的Jpg格式的图片,也就是每通道有8位,不带alpha通道,bitmap为24位,但是使用CGImageGetBitsPerPixel输出的结果却是32位,结果错误

第三张图片 格式为 8bpc 24bpp 的Tiff格式的图片,也就是每通道有8位,不带alpha通道,bitmap为24位,但是使用CGImageGetBitsPerPixel输出的结果是24位,结果正确

第四张图片 格式为 16bpc 48bpp 的Png格式的图片,也就是每通道有16位,不带alpha通道,bitmap为48位,但是使用CGImageGetBitsPerPixel输出的结果是48位,结果正确

第五张图片 格式为 16bpc 48bpp 的Tiff格式的图片,也就是每通道有16位,不带alpha通道,bitmap为48位,但是使用CGImageGetBitsPerPixel输出的结果是48位,结果正确

使用五张图片信息如下 【命名规则(以img3CPng8Bit为例) img + 3C(3channel 3通道) + Png(图片格式) + 8Bit(通道位深) = img3CPng8Bit,统一命名规则方便代码演示区分】
在这里插入图片描述
读取代码及输出结果如下:

	NSString *path8BitPng = [[NSBundle mainBundle] pathForResource:@"img3CPng8Bit" ofType:@".png"];
    NSData *bundleImgData8BitPng = [NSData dataWithContentsOfFile:path8BitPng];
    UIImage *bundleImage8BitPng = [UIImage imageWithData:bundleImgData8BitPng];
    CGImageRef imgRef8BitPng = [bundleImage8BitPng  CGImage];
    size_t bitsPerComponent8BitPng  = CGImageGetBitsPerComponent(imgRef8BitPng );
    printf("img8Bit3CPng 每个通道占用的位数:%zu \n",bitsPerComponent8BitPng );
    size_t bitsPerPixel8BitPng  = CGImageGetBitsPerPixel(imgRef8BitPng);
    printf("img8Bit3CPng 每个像素占用的位数:%zu \n\n",bitsPerPixel8BitPng );
    
    NSString *path8BitJpg = [[NSBundle mainBundle] pathForResource:@"img3Cjpg8Bit" ofType:@".jpg"];
    NSData *bundleImgData8BitJpg = [NSData dataWithContentsOfFile:path8BitJpg];
    UIImage *bundleImage8BitJpg = [UIImage imageWithData:bundleImgData8BitJpg];
    CGImageRef imgRef8BitJpg = [bundleImage8BitJpg  CGImage];
    size_t bitsPerComponent8BitJpg  = CGImageGetBitsPerComponent(imgRef8BitJpg );
    printf("img8Bit3CJpg 每个通道占用的位数:%zu \n",bitsPerComponent8BitJpg );
    size_t bitsPerPixe8BitJpg  = CGImageGetBitsPerPixel(imgRef8BitJpg);
    printf("img8Bit3CJpg 每个像素占用的位数:%zu \n\n",bitsPerPixe8BitJpg );
    
    NSString *path8Bit3CTiff = [[NSBundle mainBundle] pathForResource:@"img3CTiff8Bit" ofType:@".tif"];
    NSData *bundleImgData8Bit3CTiff = [NSData dataWithContentsOfFile:path8Bit3CTiff];
    UIImage *bundleImage8Bit3CTiff = [UIImage imageWithData:bundleImgData8Bit3CTiff];
    CGImageRef imgRef8Bit3CTiff = [bundleImage8Bit3CTiff  CGImage];
    size_t bitsPerComponent8Bit3CTiff  = CGImageGetBitsPerComponent(imgRef8Bit3CTiff );
    printf("img8Bit3CTiff 每个通道占用的位数:%zu \n",bitsPerComponent8Bit3CTiff );
    size_t bitsPerPixel8Bit3CTiff  = CGImageGetBitsPerPixel(imgRef8Bit3CTiff);
    printf("img8Bit3CTiff 每个像素占用的位数:%zu \n\n",bitsPerPixel8Bit3CTiff );
    
    NSString *path16Bit3CPng = [[NSBundle mainBundle] pathForResource:@"img3CPng16Bit" ofType:@".png"];
    NSData *bundleImgData16Bit3CPng = [NSData dataWithContentsOfFile:path16Bit3CPng];
    UIImage *bundleImage16Bit3CPng = [UIImage imageWithData:bundleImgData16Bit3CPng];
    CGImageRef imgRef16Bit3CPng = [bundleImage16Bit3CPng  CGImage];
    size_t bitsPerComponent16Bit3CPng  = CGImageGetBitsPerComponent(imgRef16Bit3CPng );
    printf("img16Bit3CPng 每个通道占用的位数:%zu \n",bitsPerComponent16Bit3CPng );
    size_t bitsPerPixe16Bit3CPng  = CGImageGetBitsPerPixel(imgRef16Bit3CPng);
    printf("img16Bit3CPng 每个像素占用的位数:%zu \n\n",bitsPerPixe16Bit3CPng );
    
    NSString *path16Bit3CTiff = [[NSBundle mainBundle] pathForResource:@"img3CTiff16Bit" ofType:@".tif"];
    NSData *bundleImgData16Bit3CTiff = [NSData dataWithContentsOfFile:path16Bit3CTiff];
    UIImage *bundleImage16Bit3CTiff = [UIImage imageWithData:bundleImgData16Bit3CTiff];
    CGImageRef imgRef16Bit3CTiff = [bundleImage16Bit3CTiff  CGImage];
    size_t bitsPerComponent16Bit3CTiff  = CGImageGetBitsPerComponent(imgRef16Bit3CTiff );
    printf("img16Bit3CTiff 每个通道占用的位数:%zu \n",bitsPerComponent16Bit3CTiff );
    size_t bitsPerPixel16Bit3CTiff  = CGImageGetBitsPerPixel(imgRef16Bit3CTiff);
    printf("img16Bit3CTiff 每个像素占用的位数:%zu \n\n",bitsPerPixel16Bit3CTiff );
输出结果为:
img8Bit3CPng 每个通道占用的位数:8 
img8Bit3CPng 每个像素占用的位数:32 

img8Bit3CJpg 每个通道占用的位数:8 
img8Bit3CJpg 每个像素占用的位数:32 

img8Bit3CTiff 每个通道占用的位数:8 
img8Bit3CTiff 每个像素占用的位数:24 

img16Bit3CPng 每个通道占用的位数:16 
img16Bit3CPng 每个像素占用的位数:48 

img16Bit3CTiff 每个通道占用的位数:16 
img16Bit3CTiff 每个像素占用的位数:48 

可以看到
8位3通道的Png及jpeg格式图片使用CGImageGetBitsPerPixel方法获取到的结果并不是24,而是32;
8位3通道tiff格式、16位3通道png格式、16位3通道tiff格式的图片输出结果都正确

猜测可能是苹果在加载最常用的8bpc格式的png及jpeg图片的时候,如果图片本身没有alpha通道,从本地读取图片数据的过程中,会默认给图片增加一个不透明的值位255的alpha通道,论证该猜想如下:

集成opencv框架,使用该框架创建一个宽度为3000,高度为4000的矩阵,再将该矩阵转化为8bpc 3通道的纯红色的图片,然后使用读取该图片信息,代码及输出如下

    cv::Mat originImgMat1 = Mat(3000, 4000, CV_8UC3);
    for(int row = 0; row < 3000; row ++){
        for(int col = 0; col < 4000; col ++){
            originImgMat1.at<Vec3b>(row,col)[0] = 255;
            originImgMat1.at<Vec3b>(row,col)[1] = 0;
            originImgMat1.at<Vec3b>(row,col)[2] = 0;
        }
    }
    
    UIImage *image = [CVTools2 UIImageFromCVMat:originImgMat1];
    CGImageRef imageRef = [image CGImage];
    size_t imgbitsPerComponent  = CGImageGetBitsPerComponent(imageRef );
    printf("imgbitsPerComponent 每个通道占用的位数:%zu \n",imgbitsPerComponent );
    size_t imgBitsPerPixe  = CGImageGetBitsPerPixel(imageRef);
    printf("imgBitsPerPixe 每个像素占用的位数:%zu \n\n",imgBitsPerPixe );

UIImageFromCVMat 方法:

+(UIImage *)UIImageFromCVMat:(cv::Mat)cvMat
{
    NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize()*cvMat.total()];
    CGColorSpaceRef colorSpace;
    if (cvMat.elemSize() == 1) {
        colorSpace = CGColorSpaceCreateDeviceGray();
    } else {
        colorSpace = CGColorSpaceCreateDeviceRGB();
    }
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
    // Creating CGImage from cv::Mat
    CGBitmapInfo alphaInfo;
    if(cvMat.channels() == 4){
        alphaInfo = kCGImageAlphaLast  | kCGImageByteOrder16Little;
    }else{
        alphaInfo = kCGImageAlphaNone | kCGImageByteOrderDefault;
    }
    CGImageRef imageRef = CGImageCreate(cvMat.cols,                                 //width
                                        cvMat.rows,                                 //height
                                        8,                                          //bits per component
                                        8 * cvMat.elemSize(),                       //bits per pixel
                                        cvMat.step[0],                            //bytesPerRow
                                        colorSpace,                                 //colorspace
                                        alphaInfo,// bitmap info
                                        provider,                                   //CGDataProviderRef
                                        NULL,                                       //decode
                                        true,                                      //should interpolate
                                        kCGRenderingIntentDefault                   //intent
                                        );
    // Getting UIImage from CGImage
    UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpace);
    return finalImage;
}
输出结果为:
imgbitsPerComponent 每个通道占用的位数:8 
imgBitsPerPixe 每个像素占用的位数:24 

可以看到输出的结果是正确的。

将该图片写入沙盒,然后读取出来集成到项目中再次读取。代码及输出如下

    NSString *path = [[NSBundle mainBundle] pathForResource:@"red" ofType:@".png"];
    NSData *bundleImgData = [NSData dataWithContentsOfFile:path];
    UIImage *bundleImage = [UIImage imageWithData:bundleImgData];
    CGImageRef imgRef = [bundleImage  CGImage];
    size_t bitsPerComponent  = CGImageGetBitsPerComponent(imgRef );
    printf("bitsPerComponent 每个通道占用的位数:%zu \n",bitsPerComponent );
    size_t bitsPerPixel  = CGImageGetBitsPerPixel(imgRef);
    printf("bitsPerPixel 每个像素占用的位数:%zu \n\n",bitsPerPixel );
输出结果:
bitsPerComponent 每个通道占用的位数:8 
bitsPerPixel 每个像素占用的位数:32 

可见从本地读取图片的时候,又增加上了alpha通道。所以可以论证【可能是苹果在加载最常用的8bpc格式的png及jpeg图片的时候,如果图片本身没有alpha通道,从本地读取图片数据的过程中,会默认给图片增加一个不透明的值位255的alpha通道】这个观点。

有其他想法欢迎留言一起交流学习,后续会增加使用quartz 2D来完成图片裁剪需求的多种实现方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/540923.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

光纤衰减器作用及使用说明

在光纤通信中&#xff0c;光信号的强度过大或过小都会对信号的传输和接收产生不良的影响&#xff0c;因此光衰减器在光通信系统中起到了重要的作用。那什么是光衰减器呢&#xff1f;它又有什么作用呢&#xff1f;下面跟着小易一起来了解一下吧&#xff01; 一、什么是光纤衰减…

APP自动化测试工具的作用和特点

随着移动应用的迅速发展&#xff0c;APP的自动化测试工具变得越来越重要。APP自动化测试工具可以帮助开发者在应用程序的不同平台上执行测试&#xff0c;从而检测和确保应用程序的完整性、稳定性和可靠性。下面将介绍APP自动化测试工具的作用和特点。 一、作用 提高测试效率&am…

Android自定义控件——控件的测量和绘制

控件的测量和绘制 控件架构setContentView()MeasureSpecViewView的测量View的绘制 ViewGroupViewGroup的测量ViewGroup的绘制 自定义View对现有控件进行扩展案例一&#xff1a;添加背景案例二&#xff1a;文字闪动 创建复合控件重写View实现全新控件案例一&#xff1a;弧线展示…

FLEXPART--空气块轨迹-扩散模式

模式简介&#xff1a; FLEXPART(Flexible Particle Dispersion Model)模式是由挪威大气研究所(Norwegian Institute for Air Research)和德国慕尼黑工业大学(Technical University of Munich)联合开发的空气块轨迹&#xff0d;扩散模式, 其通过计算区域内所有气块的运动轨迹进…

PLE - 多任务模型(腾讯)

文章目录 1、动机2、模型结构3、代码实现细节&#xff1a; Progressive Layered Extraction (PLE): A Novel Multi-Task Learning (MTL) Model for Personalized Recommendations论文发表在 RecSys-2020&#xff0c; best paper。ple主要缓解了mtl里两大问题&#xff1a;负迁移…

如何在海量、庞杂、混合的数据中发现价值?

数字时代&#xff0c;数据上升为国家战略&#xff0c;数据成为重要的生产要素和资产&#xff0c;得到了越来越多企业的重视&#xff0c;也成为企业数字化转型的重要抓手。据IDC中国预测&#xff0c;2025年中国大数据生产量有望增长至48.6ZB。 随着越来越大的数据量&#xff0c…

【C++从0到王者】第六站:类和对象(下)

文章目录 一、再谈构造函数1.构造函数体赋值2.初始化列表1>初始化列表的使用2>初始化列表的注意事项 3.explicit关键词 二、static成员1.如何统计当前程序中变量的个数2.static的特性3.从1加到n4.设计一个类&#xff0c;只能在栈或者堆上开辟空间 三、友元1.友元函数2.友…

一个简化、落地的实时数据仓库解决方案

从传统的经验来讲&#xff0c;数据仓库有一个很重要的功能是记录数据变化历史。通常&#xff0c;数据仓库都希望从业务上线的第一天开始有数据&#xff0c;然后一直记录到现在。但实时处理技术&#xff0c;又是强调当前处理状态的一门技术&#xff0c;所以当这两个相互对立的方…

聚合数据证件识别接口-基于PHP示例代码

1、开通接口 以下代码示例基于聚合数据提供的证件识别接口&#xff0c;使用前需要先注册申请本接口&#xff0c;获得请求密钥key。 接口文档地址&#xff1a;https://www.juhe.cn/docs/api/id/153 2、功能介绍 通过自动识别的方式获取常规证件文字内容&#xff0c;免去用户…

react函数式组件转化为string---renderToString

需求 使用aggrid的过程中&#xff0c;某个自定义的图标需要传dom的字符串。 但在react的开发中&#xff0c;一般都是组件的概念&#xff08;ReactNode&#xff0c;JSX.Element&#xff09; 因此需要一个方法将dom组件转化为字符串 收获 找到了官网的API——renderToString 作…

虚拟主机部署ssl证书(https)流程

注意事项&#xff1a; 1、域名要做别名解析指向二级域名 2、证书已经申请完成&#xff0c;其他公司的证书要下载导入到西部数码。 虚拟主机部署教程如下&#xff1a; 部署证书 首先要将域名绑定到主机上&#xff0c;在主机控制面板找到【SSL部署】按钮。 在西部数码申请过证…

FFmpeg 媒体文件播放 格式变化流程简述

例如&#xff0c;要播放一个 MP4 文件&#xff0c;这个文件要经过啥呢&#xff1f; 一个 MP4 文件中包含了&#xff1a;视频压缩数据流&#xff08;如H.264、H.265&#xff09;和音频压缩数据&#xff08;如aac、MP3&#xff09; 首先需要经过解码成为原始数据&#xff0c;视频…

数据库原理及应用上机实验一

✨作者&#xff1a;命运之光 ✨专栏&#xff1a;数据库原理及应用上机实验报告整理 目录 ✨一、实验目的和要求 ✨二、实验内容与步骤 &#x1f353;&#x1f353;前言&#xff1a; 数据库原理及应用上机实验报告的一个简单整理后期还会不断完善&#x1f353;&#x1f353;…

HarmonyOS低代码开发-创建新工程方式

使用低代码开发应用或服务有以下两种开发方式&#xff1a; 创建一个支持低代码开发的新工程&#xff0c;开发应用或服务的UI界面。在已有工程中&#xff0c;创建Visual文件来开发应用或服务的UI界面。ArkTS工程和JS工程使用低代码的步骤相同&#xff0c;接下来以JS工程为例讲解…

Web自动化框架中验证码识别处理全攻略,自动化测试神器,让测试更得心应手。

目录 前言&#xff1a; 一. Web自动化测试框架搭建 1. 选择一个自动化测试工具 2. 安装环境 3. 初始化一个Selenium驱动 二. 添加自动化测试用例 1. 编写测试脚本 2. 运行测试脚本 三. 验证码识别与处理 1. 验证码种类 2. 验证码处理方式 四. 结语 Web自动化测试&#…

指针不可怕,请爱它呵护它(狗头)

&#x1f929;本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 &#x1f970;内容专栏&#xff1a;这里是《C知识系统分享》专栏&#xff0c;笔者用重金(时间和精力)打造&#xff0c;基础知识一网打尽&#xff0c…

opencv_c++学习(十一)

一、绘制基础图形 绘制直线&#xff1a; line(InputOutputArray img. Point pt1, Point pt2, const Scalar & color, int thickness 1,llineType int LINE_8, int shift 0pt1:直线起始点在图像中的坐标。 pt2:直线终点在图像中的坐标。 color:直线的颜色&#xff0c;…

《2023新一代数字办公白皮书》正式发布!| 爱分析报告

2023年5月12日&#xff0c;受北京市数字办公安全创新联合体委托&#xff0c;由自主可控新鲜事和爱分析联合撰写的《2023新一代数字办公白皮书》&#xff08;以下简称《白皮书》&#xff09;在“2023通明湖论坛 信创基础底座创新发展分论坛”上正式发布。 《白皮书》详细阐述了新…

box的符号距离函数

序 能用解析的方法算的&#xff0c;叫符号距离函数。只能数值解的&#xff0c;叫符号距离场。 它就是横平竖直的几个平面&#xff0c;点到平面的距离是很好算的。 初步认识 有个网页&#xff0c;可以玩一玩&#xff1a; About | Physics Simulation in Visual Computing (…

抖音seo源码开发,开源技术保姆式搭建

抖音seo源码优化逻辑 抖音SEO是通过一系列的技术手段和优化策略来提升视频内容在抖音平台内的曝光率和排名。其中主要包括以下几个方面&#xff1a; 1.关键词优化。通过对视频的标题、描述等元素的关键词进行优化&#xff0c;提高相关性和匹配度&#xff0c;让用户更容易搜索到…