从iOS -OpenGL ES 2.0上的两个JPEG加载RGBA图像



基于我在这里的问题中的概念以及我在这里的另一个问题中概述的PNG文件的问题,我将尝试从两个JPEG加载RGBA映像。一个将包含RGB,另一个仅包含Alpha。我可以将第二个保存为灰度jpeg或RGB,然后从红色组件中提取alpha数据。

在第二步中,我将把原始图像数据保存到缓存中的文件。然后,我将进行测试以确定加载原始数据或解压缩JPEG并构建原始数据更快。如果我确定它的速度更快,则在随后的负载下,我可以检查缓存中的原始文件的存在。如果不是,我会跳过该文件保存。

我知道如何将两个JPEG加载到两个uiimages中。我不确定的是将RGB与我用于Alpha使用的其他uiimage的任何频道交织在一起的最快或最有效的方法。

我看到了两种可能性。一个将在下面的评论中。遍历所有像素,然后将红色从" alpha jpeg"复制到Imagedata Steam的alpha。

另一个是,也许有一些魔术uiimage命令将一个频道从一个频道复制到另一个频道。如果我这样做了,那将在评论A周围。

有什么想法?

编辑 - 也..该过程无法破坏任何RGB信息。我需要这个过程的全部原因是,PNG来自Photoshop用Alpha的RGB,从而破坏RGB信息。我正在使用alpha用于自定义OpenGL着色器中的Alpha以外的其他功能。因此,我正在寻找可以将Alpha设置为镜头映射或照明地图或高度图或Alpha以外的其他内容的原始RGBA数据。

这是我的入门代码减去我的错误检查和其他专有废话。我有一系列纹理来管理有关纹理的所有内容:

if (textureInfo[texIndex].generated==NO) {
    glGenTextures(1, &textureInfo[texIndex].texture);
    textureInfo[texIndex].generated=YES;
}
glBindTexture(GL_TEXTURE_2D, textureInfo[texIndex].texture);
// glTexParameteri commands are here based on options for this texture
NSString *path = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@_RGB",name] ofType:type];
NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
UIImage *imageRGB = [[UIImage alloc] initWithData:texData];
path = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@_A",name] ofType:type];
texData = [[NSData alloc] initWithContentsOfFile:path];
UIImage *imageAlpha = [[UIImage alloc] initWithData:texData];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *imageDataRGB = malloc( heightRGB * widthRGB * 4 );
void *imageDataAlpha = malloc( heightA * widthA * 4 );
CGContextRef thisContextRGB = CGBitmapContextCreate( imageDataRGB, widthRGB, heightRGB, 8, 4 * widthRGB, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
CGContextRef thisContextA = CGBitmapContextCreate( imageDataAlpha, widthA, heightA, 8, 4 * widthA, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
// **** A. In here I want to mix the two.. take the R of imageA and stick it in the Alpha of imageRGB.
CGColorSpaceRelease( colorSpace );
CGContextClearRect( thisContextRGB, CGRectMake( 0, 0, widthRGB, heightRGB ) );
CGContextDrawImage( thisContextRGB, CGRectMake( 0, 0, widthRGB, heightRGB ), imageRGB.CGImage );
// **** B. OR maybe repeat the above 3 lines for the imageA.CGImage and then
// **** It could be done in here by iterating through the data and copying the R byte of imageDataA on to the A byte of the imageDataRGB
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, widthRGB, heightRGB, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageDataRGB);
// **** In here I could save off the merged imageData to a binary file and load that later if it's faster
glBindTexture(GL_TEXTURE_2D, textureInfo[texIndex].texture);
// Generates a full MipMap chain to the current bound texture.
if (useMipmap) {
    glGenerateMipmap(GL_TEXTURE_2D);
}
CGContextRelease(thisContextRGB);
CGContextRelease(thisContextA);
free(imageDataRGB);
free(imageDataAlpha);

i第二在上面的评论中提出的建议使用单独的纹理并在着色器中组合。但是,我要解释为什么这可能会更快...

纹理2D调用本身的数量与速度无关。影响速度的重要因素是:(1)从CPU到GPU需要复制多少数据?(您可以轻松测试,在每个呼叫中使用N/2像素两次调用Texture2d几乎与使用N -pixels一起调用一次的所有其他所有内容都完全一样快),以及(2)实现是否需要重新安排CPU内存中的数据在纹理2D之前(如果是,那么呼叫可能会非常慢)。有些纹理格式需要重新排列,有些则不需要。通常,至少RGBA,RGB565和YUV420或YUYV的某些变体不需要重新排列。步幅和宽度/高度是两个的力量也可能很重要。

我认为,如果无需重新排列数据,一个使用RGB呼叫,一个呼叫与A的呼叫大约与使用RGBA的呼叫一样快。

由于重新排列比副本要慢得多,因此复制RGBX(忽略第四个通道),然后是A,而不是重新排列RGB,然后在CPU上重新安排A,然后复制A复制。

P.S。"在第二步中,我将将原始图像数据保存到缓存中的文件中。然后,我将进行测试以确定加载原始数据或解压缩JPEG并构建原始数据更快的速度。" - 从内存以外的任何内容中读取原始数据可能比解压缩要慢得多。1兆像素的图像需要几十毫秒从JPEG解压缩,或数百毫秒来读取Flash Drive的原始数据。

这是对具有干净RGB的版本的Alpha的简单复制。尽管关于我的着色器是否更快地调用Texture2d 2或4次,但下面的方法是将未成熟的RGBA进入我的glTexImage2D(GL_TEXTURE_2D...的一种方式。

这是我的整个方法:

-(BOOL)quickLoadTexPartsToNumber:(int)texIndex imageNameBase:(NSString *)name ofType:(NSString *)type  flipImage:(bool)flipImage clamp:(bool)clamp  mipmap:(bool)useMipmap
{
    //NSLog(@"loading image: %@ into %i",name, texIndex);
    // generate a new texture for that index number..  if it hasn't already been done
    if (textureInfo[texIndex].generated==NO) {
        glGenTextures(1, &textureInfo[texIndex].texture);
        textureInfo[texIndex].generated=YES;
    }
    glBindTexture(GL_TEXTURE_2D, textureInfo[texIndex].texture);
    if (useMipmap) {
        if (clamp) {
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_NEAREST);
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
        }
        if (hardwareLimitions==HARDWARE_LIMITS_NONE) {
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR);
        }
        else {
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_LINEAR);
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST_MIPMAP_LINEAR);
        }
    }
    else {
        if (clamp) {
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
        }
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    }
    NSString *path = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@_RGB",name] ofType:type];
    NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
    UIImage *imageRGB = [[UIImage alloc] initWithData:texData];
    path = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@_A",name] ofType:type];
    texData = [[NSData alloc] initWithContentsOfFile:path];
    UIImage *imageAlpha = [[UIImage alloc] initWithData:texData];

    if (imageRGB == nil) {
        NSLog(@"************* Image %@ is nil - there's a problem", [NSString stringWithFormat:@"%@_RGB",name]);
        return NO;
    }
    if (imageAlpha == nil) {
        NSLog(@"************* Image %@ is nil - there's a problem", [NSString stringWithFormat:@"%@_A",name]);
        return NO;
    }

    GLuint widthRGB = CGImageGetWidth(imageRGB.CGImage);
    GLuint heightRGB = CGImageGetHeight(imageRGB.CGImage);
    GLuint widthAlpha = CGImageGetWidth(imageAlpha.CGImage);
    GLuint heightAlpha = CGImageGetHeight(imageAlpha.CGImage);
    if (widthRGB != widthAlpha || heightRGB!=heightAlpha) {
        NSLog(@"************* Image %@ - RBG and Alpha sizes don't match", name);
    }
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    // unsigned char is an 8 bit unsigned integer
    unsigned char *imageDataRGB = malloc( heightRGB * widthRGB * 4 );
    unsigned char *imageDataAlpha = malloc( heightAlpha * widthAlpha * 4 );
    CGContextRef thisContextRGB = CGBitmapContextCreate( imageDataRGB, widthRGB, heightRGB, 8, 4 * widthRGB, colorSpace, kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big );
    CGContextRef thisContextAlpha = CGBitmapContextCreate( imageDataAlpha, widthAlpha, heightAlpha, 8, 4 * widthAlpha, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
    if (flipImage)
    {
        // Flip the Y-axis  - don't want to do this because in this game I made all my vertex squares upside down.
        CGContextTranslateCTM (thisContextRGB, 0, heightRGB);
        CGContextScaleCTM (thisContextRGB, 1.0, -1.0);
        CGContextTranslateCTM (thisContextAlpha, 0, heightAlpha);
        CGContextScaleCTM (thisContextAlpha, 1.0, -1.0);
    }
    CGColorSpaceRelease( colorSpace );
    CGContextClearRect( thisContextRGB, CGRectMake( 0, 0, widthRGB, heightRGB ) );
    // draw the RGB version and skip the alpha
    CGContextDrawImage( thisContextRGB, CGRectMake( 0, 0, widthRGB, heightRGB ), imageRGB.CGImage );
    CGColorSpaceRelease( colorSpace );
    CGContextClearRect( thisContextAlpha, CGRectMake( 0, 0, widthAlpha, heightAlpha ) );
    CGContextDrawImage( thisContextAlpha, CGRectMake( 0, 0, widthAlpha, heightAlpha ), imageAlpha.CGImage );
    int count = 4 * widthRGB * heightRGB;
    for(int i=0; i < count; i+=4)
    {
        // copying the alpha (one byte) on to a non-premultiplied rgb is faster than copying the rgb over (3 bytes)
       imageDataRGB[i+3] = imageDataAlpha[i];
    }
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, widthRGB, heightRGB, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageDataRGB);
    glBindTexture(GL_TEXTURE_2D, textureInfo[texIndex].texture);
    // Generates a full MipMap chain to the current bound texture.
    if (useMipmap) {
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    CGContextRelease(thisContextRGB);
    CGContextRelease(thisContextAlpha);
    free(imageDataRGB);
    free(imageDataAlpha);
    return YES;
}

我确实尝试使用tif而不是png,无论我在此过程中尝试了什么,RGB正在使用Alpha进行promultiple,从而破坏RGB。

这种方法可能被认为是丑陋的,但对我来说在许多层面上都起作用,这是我能够将完整的RGBA88888 Unphemultiplippiped Image的唯一方法。

最新更新