从 CGImageRef 获取像素数据包含额外的字节?
Getting pixel data from CGImageRef contains extra bytes?
我正在考虑优化从 CGImage 获取像素数据的例程。目前这样做的方式(非常低效)是创建一个新的 CGContext,将 CGImage 绘制到上下文中,然后从上下文中获取数据。
我有以下优化例程来处理这个问题:
CGImageRef imageRef = image.CGImage;
uint8_t *pixelData = NULL;
CGDataProviderRef imageDataProvider = CGImageGetDataProvider(imageRef);
CFDataRef imageData = CGDataProviderCopyData(imageDataProvider);
pixelData = (uint8_t *)malloc(CFDataGetLength(imageData));
CFDataGetBytes(imageData, CFRangeMake(0, CFDataGetLength(imageData)), pixelData);
CFRelease(imageData);
这几乎行得通。通过查看和比较通过两种方法获得的像素数据的十六进制转储,我发现在上述情况下,每 6360 个字节有 8 个字节为 0。否则,数据是相同的。例如
这是与未优化版本的比较:
在8个字节的0之后,继续正确的像素数据。有人知道为什么会这样吗?
更新:
这是我正在优化的例程(截断的代码只是获取大小信息和其他不重要的东西;相关位是返回的像素数据):
CGContextRef context = NULL;
CGImageRef imageRef = image.CGImage;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst;
// ... SNIP ...
context = CGBitmapContextCreate(...);
CGColorSpaceRelease(colorSpace);
// ... SNIP ...
CGContextDrawImage(context, rect, imageRef);
uint8_t *pixelData = (uint8_t *)CGBitmapContextGetData(context);
CGContextRelease(context);
显然,仅仅为了获取底层像素数据,这是一项过多的工作。创建上下文,然后绘制到其中。第一个例程的速度要快 5 到 10 倍。但正如我所指出的,两个例程返回的像素数据几乎相同,除了在优化代码中每 6360 字节插入 8 个零字节值(在图像中突出显示)。
否则,其他一切都是一样的 -- 颜色值、字节顺序等。
位图数据在每行像素的末尾都有填充,以将每行的字节数四舍五入到更大的值。 (在本例中,是 16 字节的倍数。)
添加此填充是为了更快地处理和绘制图像。
您应该使用 CGImageGetBytesPerRow()
来找出每行占用多少字节。不要假设它与 CGImageGetWidth() * CGImageGetBitsPerPixel() / 8
相同;每行的字节数可能更大。
请记住,任意 CGImage
背后的数据可能不是您期望的格式。您不能假设所有图像都是每像素 32 位的 ARGB,没有填充。您应该使用 CG 函数来确定数据可能是什么格式,或者将图像重新绘制到位图上下文中,该位图上下文与您期望的格式完全相同。后者通常要容易得多——让 CG 为您进行转换。
(您没有显示要传递给 CGBitmapContextCreate
的参数。您是在计算精确的 bytesPerRow
还是传入 0?如果传入 0,CG 可能会添加为您填充,您可能会发现绘制到上下文中更快。)
我正在考虑优化从 CGImage 获取像素数据的例程。目前这样做的方式(非常低效)是创建一个新的 CGContext,将 CGImage 绘制到上下文中,然后从上下文中获取数据。
我有以下优化例程来处理这个问题:
CGImageRef imageRef = image.CGImage;
uint8_t *pixelData = NULL;
CGDataProviderRef imageDataProvider = CGImageGetDataProvider(imageRef);
CFDataRef imageData = CGDataProviderCopyData(imageDataProvider);
pixelData = (uint8_t *)malloc(CFDataGetLength(imageData));
CFDataGetBytes(imageData, CFRangeMake(0, CFDataGetLength(imageData)), pixelData);
CFRelease(imageData);
这几乎行得通。通过查看和比较通过两种方法获得的像素数据的十六进制转储,我发现在上述情况下,每 6360 个字节有 8 个字节为 0。否则,数据是相同的。例如
这是与未优化版本的比较:
在8个字节的0之后,继续正确的像素数据。有人知道为什么会这样吗?
更新: 这是我正在优化的例程(截断的代码只是获取大小信息和其他不重要的东西;相关位是返回的像素数据):
CGContextRef context = NULL;
CGImageRef imageRef = image.CGImage;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst;
// ... SNIP ...
context = CGBitmapContextCreate(...);
CGColorSpaceRelease(colorSpace);
// ... SNIP ...
CGContextDrawImage(context, rect, imageRef);
uint8_t *pixelData = (uint8_t *)CGBitmapContextGetData(context);
CGContextRelease(context);
显然,仅仅为了获取底层像素数据,这是一项过多的工作。创建上下文,然后绘制到其中。第一个例程的速度要快 5 到 10 倍。但正如我所指出的,两个例程返回的像素数据几乎相同,除了在优化代码中每 6360 字节插入 8 个零字节值(在图像中突出显示)。
否则,其他一切都是一样的 -- 颜色值、字节顺序等。
位图数据在每行像素的末尾都有填充,以将每行的字节数四舍五入到更大的值。 (在本例中,是 16 字节的倍数。)
添加此填充是为了更快地处理和绘制图像。
您应该使用 CGImageGetBytesPerRow()
来找出每行占用多少字节。不要假设它与 CGImageGetWidth() * CGImageGetBitsPerPixel() / 8
相同;每行的字节数可能更大。
请记住,任意 CGImage
背后的数据可能不是您期望的格式。您不能假设所有图像都是每像素 32 位的 ARGB,没有填充。您应该使用 CG 函数来确定数据可能是什么格式,或者将图像重新绘制到位图上下文中,该位图上下文与您期望的格式完全相同。后者通常要容易得多——让 CG 为您进行转换。
(您没有显示要传递给 CGBitmapContextCreate
的参数。您是在计算精确的 bytesPerRow
还是传入 0?如果传入 0,CG 可能会添加为您填充,您可能会发现绘制到上下文中更快。)