进一步的修订,这现在是社区 wiki,因为我在单独回答这个问题时犯了很多错误,这是有道理的。
尽管 CoreGraphics 初步可以使用类似以下代码的方式为您执行 32 位到 16 位的转换,但它会报告“4 个整数位/分量;16 位/像素;3 分量颜色空间;kCGImageAlphaPremultipliedLast”是不受支持的参数组合。因此,CoreGraphics 似乎无法在内部理解 4 位/通道图像。
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, buffer, width*height*4, NULL);
CGImageRef inputImage = CGImageCreate( width, height,
8, 32, width*4,
colourSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big,
dataProvider,
NULL, NO,
kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);
unsigned char *outputImage = (unsigned char *)malloc(width*height*2);
CGContextRef targetContext = CGBitmapContextCreate( outputImage,
width, height,
4, width*2,
colourSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGContextDrawImage(targetContext, CGRectMake(0, 0, width, height), inputImage);
/* uplopad outputImage to OpenGL here! */
CGContextRelease(targetContext);
CGImageRelease(inputImage);
CGColorSpaceRelease(colourSpace);
free(outputImage);
但是,根据文档:
支持的像素格式为 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange、kCVPixelFormatType_420YpCbCr8BiPlanarFullRange 和 kCVPixelFormatType_32BGRA,但在 iPhone 3G 上支持的像素格式为 kCVPixelFormatType_422YpCbCr8 和 kCVPixelFormatType_32BGRA。
因此,为了减小您收到的内容的大小,您可以切换到 YCbCr 颜色空间。当缓冲区返回双平面时(即,整个图像的所有 y 分量,然后所有 Cb 和 Cr 分量作为一个单独的块),您可以将它们作为两个单独的纹理上传到 OpenGL 并在着色器中重新组合,假设您很高兴将自己限制在 3GS 及更高版本,并且可以负担得起在 SGX iOS 设备上可用的 8 个纹理单元中的 2 个。
YCbCr 是一个颜色空间,将颜色分别表示为亮度(Y)和颜色(CbCr)。经验表明,颜色通道可以以低于亮度的频率进行采样,而任何人都无法分辨。像素格式的“420”部分描述了每 4 个 Y 分量有多少个 Cb 和 Cr 分量——本质上它告诉你每四个 Y 样本得到一个 Cb 样本和一个 Cr。因此你有一个总共六个字节来描述四个像素,对于 12 位/像素而不是 RGB 中的 24 位/像素。这样可以节省 50% 的存储空间。
出于 GL 的目的,您可能会产生额外的费用,因为它是两次上传而不是一次。如果你想避免依赖纹理读取,你还需要使用三个变量,我认为 SGX 仅限于其中的八个。