iOS正确获取图片参数深入探究及CGImageRef的使用(附源码)

news2024/11/26 12:01:59

一 图片参数的正确获取

先拿一张图片作为测试使用
测试图片
图片参数如下:
图片参数
图片的尺寸为:
-宽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/551750.html

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

相关文章

从零开始 Spring Boot 32:AOP II

从零开始 Spring Boot 32&#xff1a;AOP II 图源&#xff1a;简书 (jianshu.com) 之前写过一篇文章从零开始 Spring Boot 26&#xff1a;AOP - 红茶的个人站点 (icexmoon.cn)&#xff0c;讨论了AOP的基本用法&#xff0c;但那篇文章相当粗疏&#xff0c;对Spring中的AOP技术讨…

免费快速部署ChatGPT线上聊天网页:ChatGPT API + Github + Railway

1、使用工具 &#xff08;1&#xff09;需要自己生成的openai api&#xff0c;获取API的网站&#xff1a;openAI API 获取方式&#xff1a;OpenAI的API key获取方法 &#xff08;2&#xff09;本次使用该参考项目进行部署&#xff1a;chatweb 需要将该项目fork到自己的仓库里 …

29 SQL——事务操作

create table account (id int auto_increment primary key comment 主键ID,name varchar(18) comment 姓名,money int comment 余额 )comment 账户表;insert into account(id, name ,money)values(null,张三,2000),(nul…

不定积分题型简单总结

不定积分 考研数学复习笔记&#xff0c;用来复习知识点用&#xff0c;如有不足还请指出&#xff0c;Thanks♪(&#xff65;ω&#xff65;)&#xff89; 文章目录 不定积分1 原函数/不定积分 概念和性质2 原函数存在定理3 不定积分的基本公式4 不定积分的基本计算4.1 三角代换型…

中间件-RabbitMQ

文章目录 1.什么是MQ1.1 特点1.2 MQ产品分类 2.RabbitMQ2.1.RabbitMQ介绍2.2.使用Docker安装RabbitMQ 3.SpringBoot中使用RabbitMQ3.1.SpringAMQP3.2使用步骤 1.什么是MQ RabbitMQ官方文档 消息队列(Message Queue&#xff0c;简称MQ)&#xff1a;是在消息的传输过程中保存消…

SpringBoot+Vue实现校园二手系统。前后端分离技术【完整功能介绍+实现详情+源码】

前言 文章内容有点长&#xff0c;建议打开右侧目录导航栏查看。 这个系统基本上可以改造为其它类似的系统。后台管理基本上一致。前台进行一些页面样式的改造就可以变成一个新的系统。有时间&#xff0c;做几个变体系统。 闲的无聊&#xff0c;把大学时候做的一个系统进行了重…

git源代码管理

文章目录 git源代码管理git单人本地仓库操作创建远程仓库&#xff08;github为例&#xff09;多人开发与冲突分支操作SSH&#xff08;安全外壳协议&#xff09; git源代码管理 文档连接&#xff1a;https://git-scm.com/docs git是用于源代码管理&#xff0c;方便多人协同开发…

架构整洁之道上篇(编程范式设计原则)

目录 1.概述 2.编程范式 2.1.结构化编程 2.2.面向对象编程 2.3.函数式编程 3.设计原则 3.1.单一职责原则 3.2.开闭原则 3.3.里氏替换原则 3.4.接口隔离原则 3.5.依赖反转原则 4.小结 1.概述 软件架构的终极目标是&#xff0c;用最小的人力成本来满足构建和维护该系…

2023 操作系统 R 复习大纲( 适用于太理软件 21 级)

目录 01.操作系统的定义 02.操作系统的基本类型及特征 1.批处理操作系统&#xff08;单、多道&#xff09; 2.分时操作系统 3.实时操作系统 03.操作系统的功能及特征 04.进程的定义、特征 05.进程基本状态及其转换原因 06.进程互斥、同步 07.进程控制块的内容、作用 …

Java数据类型之整数类型与浮点数

标识符&#xff08;名字&#xff09; 作用域 离其最近的大括号 { } &#xff01;&#xff01;&#xff01; 数据类型的分类 赋值时&#xff0c;不可超过数据类型的范围&#xff08;不可越界&#xff09; 常量的进制转换 tips&#xff1a;给变量赋值时&#xff0c;值可以为不同…

从代码层面理解Transformer

跑通 代码使用的是 https://github.com/jadore801120/attention-is-all-you-need-pytorch, commit-id 为: 132907d 各模块粗览 Transformer 主要包括一堆参数, 以及encoder和decoder forward的时候主要做了如下操作. 先 pad_mask过encoder过decoder输出logit 从train.py …

C语言-【指针一】-【什么是指针/指针类型】

对于初学者来说&#xff0c;是不是一提到指针&#xff0c;大家就头疼啊&#xff0c;哈哈哈&#xff0c;当然&#xff0c;它都这么“吓人”了&#xff0c;那么在C语言中扮演的角色也很重要&#xff0c;当然&#xff0c;它也是C语言中的一个特色&#xff0c;如果我们把它拿下的话…

ESP32CAM,点亮一个LED(Arduino平台)

前言 &#xff08;1&#xff09;在此&#xff0c;吐槽一下乐鑫的函数介绍&#xff0c;真的难找。恶心的一批。气死我了。 &#xff08;2&#xff09;接下来我将会介绍我是如何找到ESP32的Arduino平台的函数库的。你将会知道为啥我这么大的戾气。 &#xff08;3&#xff09;同时…

linux系统中输入与输出重定向

什么是输入输出重定向 我们在日常工作中最常用的是输出重定向&#xff0c;输出重定向就是将原本要打印到屏幕中的信息重定向到一个文件中。而输入重定向呢就是指把文件导入到命令中去&#xff0c;听起来是不是有点抽象啊&#xff0c;后面看博主举例说明就很好理由啦。 输出重定…

通讯录信息管理系统

系列文章 任务50 通讯录信息管理系统 文章目录 系列文章一、实践目的与要求1、目的2、要求 二、课题任务三、总体设计1.存储结构及数据类型定义2.程序结构3.所实现的功能函数4、程序流程图 四、小组成员及分工五、 测试插入按编号查找按姓名查找按城市查找更新排序浏览删除统计…

超好玩C++控制台打飞机小游戏,附源码

我终于决定还是把这个放出来。 视频在这&#xff1a;https://v.youku.com/v_show/id_XNDQxMTQwNDA3Mg.html 具体信息主界面上都有写。 按空格暂停&#xff0c;建议暂停后再升级属性。 记录最高分的文件进行了加密。 有boss&#xff08;上面视频2分47秒&#xff09;。 挺好…

轻松转换CAJ文件为PDF格式:免费工具和技巧

在处理中国知网&#xff08;CNKI&#xff09;数据库中的CAJ文件时&#xff0c;将其转换为更常用的PDF格式可以提供更广泛的共享和便捷的阅读体验。本文将介绍一种免费的工具和一些技巧&#xff0c;帮助您轻松地将CAJ文件转换为PDF格式。我们将使用记灵在线工具进行操作。 记灵…

推荐几本提高程序员职业素养的书

如果你是一名程序员&#xff0c;想要提长自己&#xff0c;那么这几本书推荐给你。 1、好代码 &#xff0c;坏代码 为了写出优良的代码&#xff0c;我们必须对手上的方案有合理的判断&#xff0c;并彻底想清楚特定方法的结果&#xff08;好的和坏的&#xff09;。为此&#xff…

F检验.医学统计实例详解

F检验是一种重要的医学统计方法&#xff0c;常用于检验两个或多个样本的方差是否相等&#xff0c;也被称为方差齐性检验。方差齐性检验是医学研究中的基本方法&#xff0c;因为许多重要的统计分析都要求样本方差相等&#xff0c;如方差分析、t检验等。以下将介绍F检验的基本原理…

简单上手Scrapy框架

创建一个Scrapy框架的爬虫程序 安装Scrapy库&#xff0c;直接通过pycharm搜索Scrapy进行安装即可 在终端执行 scrapy startproject 项目名 scrapy startproject Learn 示例 即可创建名为Learn的Scrapy程序&#xff0c;成功创建项目后&#xff0c;会已项目名称创建一个文件夹&…