我有几张具有Alpha透明度的PNG图像。当用于一般的Quartz东西(如UI)时,这些显示正确。但是,当我拍摄图像并将其放入OpenGL时,我发现我得到的数据的实线alpha值为255。我使用的似乎是通常的UIImage转换为CGImage并渲染到上下文中。我将在下面发布相关的代码。

我做了很多搜索,最后偶然发现了一种解决方法,我想在这里分享,但是它很慢,因为它必须遍历每个像素,并将该原始Alpha复制到Alpha通道中。我很想知道解决这个问题的方法。我没有在构建中切换任何PNG选项(不确定在哪里设置)以查看是否有帮助。

谢谢

首先,从我的应用程序中获取一个UIImage,我将其添加为:

UIImage *image = [UIImage imageNamed:imageName];

然后我将其转换为CGImageRef,然后执行通常的上下文创建,例如仅此相关行:
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height,
                                             bitsPerComponent, bytesPerRow,
                                             CGImageGetColorSpace(spriteImage),
                                                   kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

然后,接下来的两行是让我了解REAL png原始数据的魔力……我可能应该检查RGBA与其他格式的比较,但是我很懒……在此之后,我绘制图像,然后返回并修复Alpha……是的我知道我可以在一个循环中做到这一点,并跳过字节,这现在更易读...
// THIS data actually HAS the alpha!!
CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(spriteImage));
GLubyte *pixels = (GLubyte *)CFDataGetBytePtr(data);

// 3
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);


// Sadly we now have to loop and fix the ALPHA directly from the raw PNG source
// data as otherwise we get wrong/missing alpha...
for (int y=0; y < height; ++y) {
    for (int x=0; x < width; ++x) {
        int byteIndex = (bytesPerRow * y) + (x * bytesPerPixel);

        spriteData[byteIndex + 3] = pixels[byteIndex +3 ];
    }
}

然后我执行通常的glTexture调用等...,它可以正常工作。.如果我在上面省略了复制循环,则会得到没有alpha的实体子画面。如果执行上述操作,我的精灵将正确透明地绘制。

我知道iOS会做所有预乘的事情,但这似乎是坏的……至少希望以上内容可以对某人有所帮助,但必须有更好的方法?

有什么想法吗?谢谢!

最佳答案

好吧,我想我会根据我的发现和推测来回答自己的问题……

首先,UIImage和CGImage提供的数据将被预乘alpha。如果您使用的是经过优化的PNG,那将是这样。似乎在那时,alpha是无用的。根据Apple直接提供的示例GLImageProcessing代码,似乎获得原始PNG alpha的正确方法是使用CGImageGetDataProvider方法(如其示例)。具体来说,无需任何处理即可获得图像。需要注意的是,数据很可能以BGR而不是RGB顺序排列,这对它们进行优化很有意义。如果需要,他们的示例代码可以进行转换。就我而言,我这样做:

CGImageRef spriteImage = image.CGImage;
if (!spriteImage) {
    NSLog(@"Failed to load image");
    exit(1);
}

CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(CGImage));
pixels = (GLubyte *)CFDataGetBytePtr(data);

// … do other GL calls here like gl Gen and Bind…

// NOTE the reverse BGRA here for the 7th parameter only!:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)width, (int)height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels);

// Don't forget to release BOTH the CF data and the CGImage or you will get memory leaks!
CFRelease(data);        // Release the CF data

这对我有用,我得到了正确的Alpha,它是快速而正确的。需要注意的一点是,我不必重新调整图像大小……如果您对此有所关注,则可以像往常一样执行通常的CGBitmapContextCreate和ContextDraw东西,它们仍然可以正确处理提供的数据。别忘了释放……我忘记了这,就像泄漏内存一样。

希望这可以帮助某人...

07-28 02:35
查看更多