从iOS上的两个jpeg加载RGBA图像 – OpenGL ES 2.0

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

在第二步中,我会将原始图像数据保存到caching中的文件中。 然后,我会做一个testing,以确定加载原始数据或解压JPEG文件并构build原始数据的速度更快。 如果我确定速度更快,那么在后续的加载中,我可以检查caching中是否存在原始文件。 如果没有,我会跳过该文件保存。

我知道如何将两个jpeg加载到两个UIImage中。 我不确定的是从一个UIImage交叉rgb的最快或最有效的方式与其他UIImage我使用的alpha的任何通道。

我看到两种可能性。 一个会在下面的注释B中。遍历所有像素,并将红色从“alpha jpeg”复制到imageData蒸汽的alpha。

另一个是,也许有一些神奇的UIImage命令将频道从一个频道复制到另一个频道。 如果我这样做,这将是附近的评论A的地方。

有任何想法吗?

编辑 – 此外,该进程不能破坏任何RGB信息。 我需要这个过程的全部原因是,来自photoshop的PNG预先将alpha与rgb相乘,从而破坏了rgb的信息。 我在自定义的OpenGL着色器中使用alpha而不是alpha。 所以我正在寻找原始的RGBA数据,我可以设置阿尔法任何东西作为高光地图或照明地图或高度地图或除alpha之外的东西。

这是我的初学者代码减去我的错误检查和其他专有废话。 我有一个纹理数组,用于pipe理有关纹理的所有内容:

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); 

我在上面的评论中提出了使用单独纹理并在着色器中进行组合的build议。 不过,我会解释为什么这可能会更快。

纹理二维调用本身的数量不应该与速度有很大关系。 影响速度的重要因素是:(1)需要将多less数据从CPU复制到GPU? (你可以很容易地testing,在每次调用中调用texture2D两次N / 2像素几乎和调用N次像素一样快),(2)实现是否需要重新排列CPU内存中的数据在texture2D之前(如果是,那么调用可能非常慢)。 一些纹理格式需要重新排列,有些则不需要; 通常至lessRGBA,RGB565和YUV420或YUYV的一些变体不需要重新排列。 步幅和宽度/高度是2的幂可能也是重要的。

我认为, 如果不需要重新排列数据,一个使用RGB的调用和一个使用A的调用与使用RGBA调用的速度大致相同。

由于重新排列比复制要慢得多,所以复制RGBX(忽略第四个通道)然后复制A,而不是在CPU上重新排列RGB和A,然后复制,可能会更快。

PS“第二步,我将原始图像数据保存到caching中的一个文件中,然后进行testing,以确定加载原始数据或解压JPEG文件并生成原始数据的速度更快。 – 从内存以外的任何地方读取原始数据可能比解压缩慢很多。 1百万像素的图像需要几十毫秒从jpeg解压缩,或几百毫秒从闪存驱动器读取原始数据。

这是一个非常简单的复制到具有清洁rgb的版本。 尽pipe关于我的着色器是否更快地调用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,不pipe在这个过程中我尝试了什么地方,rgb正在用alpha来预乘,从而破坏了rgb。

这种方法可能被认为是丑陋的,但是它对我来说在很多层面上都是可行的,并且是我能够将全部RGBA8888未预乘图像转换成OpenGL的唯一方法。