You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何CGBitmapContextCreate要求bytesPerRow为预期值的两倍?

iOS(Objective-C)单像素灰度位图上下文创建报错问题

问题场景

尝试在iOS(Objective-C)环境下生成单像素8位灰度像素缓冲区,精简代码如下:

CGFloat width = 1;
CGFloat height = 1;

CVPixelBufferRef buffer;
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, 
                                      width, 
                                      height,  
                                      kCVPixelFormatType_OneComponent8,
                                      nil, 
                                      &buffer);

CVPixelBufferLockBaseAddress(buffer, 0);
void *data = CVPixelBufferGetBaseAddress(buffer);

CGColorSpaceRef space = CGColorSpaceCreateDeviceGray();

CGContextRef ctx = CGBitmapContextCreate(data, 
                                         width, 
                                         height, 
                                         8, 
                                         0, 
                                         space, 
                                         (CGBitmapInfo) kCGImageAlphaNoneSkipLast);

// ... draw into context

CVPixelBufferUnlockBaseAddress(buffer, 0);

运行后收到错误提示:

CGBitmapContextCreate: invalid data bytes/row: should be at least 2 for 8 integer bits/component, 1 components, kCGImageAlphaNoneSkipLast.

疑问:为何API要求bytesPerRow为预期值的两倍?将CGBitmapContextCreate的width参数减半后可运行,但传入自定义bytesPerRow仍报错,忽略了什么关键点?


问题原因与解决方案

核心错误:位图信息参数与行字节数处理不当

  1. 位图信息参数误用
    kCGImageAlphaNoneSkipLast是为RGB/RGBA这类多分量像素格式设计的,它会让Core Graphics错误假设像素包含alpha通道,进而错误计算行字节数的对齐要求。对于单分量8位灰度图,必须使用kCGImageAlphaNone来明确告知无alpha通道。

  2. 行字节数未匹配CVPixelBuffer的实际值
    CVPixelBuffer会为了内存访问效率自动对行字节数做对齐(比如对齐到2字节或4字节),你不能传入0让CGBitmapContextCreate自行推导,必须通过CVPixelBufferGetBytesPerRow(buffer)获取缓冲区实际的行字节数。

修正后的代码

CGFloat width = 1;
CGFloat height = 1;

CVPixelBufferRef buffer = NULL;
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, 
                                      width, 
                                      height,  
                                      kCVPixelFormatType_OneComponent8,
                                      nil, 
                                      &buffer);

if (status != kCVReturnSuccess) {
    // 处理缓冲区创建失败逻辑
    return;
}

CVPixelBufferLockBaseAddress(buffer, 0);
void *data = CVPixelBufferGetBaseAddress(buffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(buffer); // 获取实际行字节数

CGColorSpaceRef graySpace = CGColorSpaceCreateDeviceGray();
// 使用正确的位图信息,并传入匹配的行字节数
CGContextRef ctx = CGBitmapContextCreate(data, 
                                         width, 
                                         height, 
                                         8, 
                                         bytesPerRow, 
                                         graySpace, 
                                         kCGImageAlphaNone);

if (ctx) {
    // 执行绘制操作
    // ...
    
    CGContextRelease(ctx);
}

// 释放资源,避免内存泄漏
CGColorSpaceRelease(graySpace);
CVPixelBufferUnlockBaseAddress(buffer, 0);
CVPixelBufferRelease(buffer);

关键细节说明

  • 位图信息匹配:单分量灰度图必须搭配kCGImageAlphaNone,确保Core Graphics正确识别像素格式,避免错误的行字节数计算。
  • 行字节数对齐:CVPixelBuffer的行字节数由系统自动对齐,直接使用CVPixelBufferGetBytesPerRow获取的值,才能保证与缓冲区的内存布局一致。
  • 资源管理:手动释放所有创建的Core Foundation对象(CGColorSpaceRef、CGContextRef、CVPixelBufferRef),防止内存泄漏。

内容的提问来源于stack exchange,提问作者Jordan Campbell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 04:45:32