如何在Core Graphics中生成RGBA图像?

10

我正在尝试从文本生成一个RGBA8图像,用作OpenGL ES 2.0纹理。

+(UIImage *)imageFromText:(NSString *)text
{
  UIFont *font = [UIFont systemFontOfSize:20.0];  
  CGSize size  = [text sizeWithFont:font];

  CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  CGContextRef contextRef =  CGBitmapContextCreate (NULL,
                                                    size.width, size.height,
                                                    8, 4*size.width,
                                                    colorSpace,
                                                    kCGImageAlphaLast
                                                    );
  CGColorSpaceRelease(colorSpace);
  UIGraphicsPushContext(contextRef);

  [text drawAtPoint:CGPointMake(0.0, 0.0) withFont:font];
  UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

  UIGraphicsPopContext();

  return image;
}

很遗憾,没有 CGColorSpaceCreateDeviceRGBA,而使用 CGColorSpaceCreateDeviceRGB 将导致以下错误:

CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 32 bits/pixel; 3-component color space; kCGImageAlphaLast; 448 bytes/row.
我该如何创建OpenGL所需的正确RGBA8格式?
更新:我将CGBitmapContextCreate的最后一个参数从kCGImageAlphaNone(复制代码时的参数)更改为kCGImageAlphaLast,这是我尝试的几个变化之一。
更新2:如果上下文不是使用UIGraphicsBeginImageContext()创建的,则UIGraphicsGetImageFromCurrentImageContext()返回nil,因此需要以不同的方式提取图像:[UIImage imageWithCGImage:CGBitmapContextCreateImage(contextRef)]。
3个回答

16

你在创建过程中指定的颜色空间不会导致那样的错误。

你出现错误的原因是,在bytesPerRow中传递了4*size.width值,预计有4个颜色分量且每个分量占8位,但是 bitmapInfo参数为kCGImageAlphaNonekCGImageAlphaNone 意味着只有RGB而不是RGBA。如果你想要RGBA,最可能的是指定 kCGImageAlphaLastkCGImageAlphaPremultipliedLast

[编辑] 对不起。我应该说的是kCGImageAlphaPremultipliedLast,而不是kCGImageAlphaLast

因此,像这样:

CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGContextRef contextRef =  CGBitmapContextCreate(NULL,
                                                 size.width,
                                                 size.height,
                                                 8,
                                                 4 * size.width,
                                                 colorSpace,
                                                 kCGImageAlphaPremultipliedLast);

1
我也尝试过那个方法,但不幸的是我收到了相同的(或类似的)错误信息:“CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 32 bits/pixel; 3-component color space; kCGImageAlphaLast; 448 bytes/row.” - Ian Terrell
我已更新问题,显示在使用kCGImageAlphaLast时仍然出现错误。 - Ian Terrell
1
苹果文档称kCGImageAlphaXX自2.0版本起得到支持,但实际上只有kCGImageAlphaPremultipliedXXX似乎有效。 - Cross_
很抱歉,根据SDK的说明,CGBitmapContextCreate函数的最后一个参数应该是CGBitmapInfo类型,而不是CGImageAlpha常量。请参考以下链接:https://developer.apple.com/library/ios/documentation/graphicsimaging/Reference/CGBitmapContext/Reference/reference.html#//apple_ref/c/func/CGBitmapContextCreate - Rob van der Veer
@RobvanderVeer:CGBitmapInfo 包括 CGImageAlphaInfo 作为掩码的一部分。来自(https://developer.apple.com/library/ios/documentation/graphicsimaging/Reference/CGBitmapContext/Reference/reference.html#//apple_ref/c/func/CGBitmapContextCreate):“用于指定 alpha 通道信息的常量是使用 CGImageAlphaInfo 类型声明的,但可以安全地传递给此参数。您还可以传递与 CGBitmapInfo 类型相关联的其他常量。” - NSGod
显示剩余2条评论

1
我即使使用了"kCGImageAlphaPremultipliedLast",仍然遇到了相同的"unsupported parameter combination"错误。在我的情况下,问题是我得到的宽度是小数。通过将"int(width)"传递给CGBitmapContextCreate将其转换为整数解决了问题。
--根据Steven的评论编辑--
将小数宽度作为第二个参数输入的问题不是"CGBitmapContextCreate"将其解释为这样——如上所述,它被隐式地转换为参数的无符号整数类型。而是会产生"bytes_per_row"参数中的差异,因为int(width * 4)不等于int(width) * 4。例如,如果宽度为22.5,则宽度将截断为22,但"width * 4"计算结果为90,而不是88。

1
不可能的,在 CGBitmapContextCreate 中,宽度参数已经是一个(无符号)整数。强制转换已经为您完成。 - Steven Kramer
这个注释报告了一个观察结果,因此从定义上来说并不是不可能的,因为它已经发生了。话虽如此,我的分析还不完整。我已经编辑了我的回复并澄清了为什么使用分数宽度会有问题。 - er0
1
没错,我对观察/测量结果有疑问。谢谢你的澄清。顺便说一下,如果你像原帖中使用NULL作为数据参数,那么你还需要传递0作为每行字节数,这样系统才能选择一个正确(甚至更高效)的值。 - Steven Kramer

0
    CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);

    CGBitmapInfo    bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little;

    CGContextRef theContext = CGBitmapContextCreate(NULL, imgSize.width, imgSize.height, 8, 4*imgSize.width, colorSpace, bitmapInfo);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接