为什么这个GLView截屏代码返回一张空白/黑色的UIImage?

5

我正在使用以下代码截取 GLView 中的像素来进行截图。但问题是,它返回了一张完全黑色的 UIImage。该代码被调用于 LineDrawer.m 文件中,这是 GLView 代码的核心 - 因此从正确的 .m 文件中调用。如何保存实际的屏幕截图而不是黑色图像?

- (UIImage*) getGLScreenshot {

NSLog(@"1");

float scale = 0.0;
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
{
    // scale value should be 1.0 on 3G and 3GS, and 2.0 on iPhone 4.
    scale = [[UIScreen mainScreen] scale]; 
}

// these are swapped since the screen is rotatey
float h = 768 * scale;
float w = 924 * scale;

NSInteger myDataLength = w * h * 4;

// allocate array and read pixels into it.
GLubyte *buffer = (GLubyte *) malloc(myDataLength);
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

// gl renders "upside down" so swap top to bottom into new array.
// there's gotta be a better way, but this works.
GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
for(int y = 0; y <h; y++)
{
    for(int x = 0; x <w * 4; x++)
    {
        buffer2[(((int)h-1) - y) * (int)w * 4 + x] = buffer[y * 4 * (int)w + x];
    }
}

// make data provider with data.
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);

// prep the ingredients
int bitsPerComponent = 8;
int bitsPerPixel = 32;
int bytesPerRow = 4 * w;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

// make the cgimage
CGImageRef imageRef = CGImageCreate(w, h, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);

// then make the uiimage from that
UIImage *myImage = [UIImage imageWithCGImage:imageRef];
return myImage;

}

- (void)saveGLScreenshotToPhotosAlbum {
UIImageWriteToSavedPhotosAlbum([self getGLScreenshot], nil, nil, nil);
}

1
你需要释放两个缓冲区并释放 provider, colorSpaceRefimageRef。此外,你可能可以通过在某处提供负的 stride 值来执行垂直翻转。 - jhabbott
我的评论并不是对你问题的回答,我只是指出了你的内存泄漏问题。你应该了解CoreFoundation和Objective-C中的引用计数。此外,在使用malloc时,你需要注意C语言中的内存管理。 - jhabbott
当运行上述捕获代码时,您的OpenGL ES上下文可能未与当前线程关联。尝试在该方法开头添加[EAGLContext setCurrentContext:self.context];。此外,glReadPixels()仅会捕获当前在帧缓冲区中可见的内容,因此如果您在GLKView的-drawRect:中调用此函数,则该内容可能尚未呈现。我不确定使用GLKView强制执行此操作的正确方法,但在glReadPixels()之前加上glFinish()可能足够了。 - Brad Larson
你在循环中尝试过不翻转图像吗?你在控制台上输出了像素吗?它们真的是0(黑色)吗? - tomk
为了在使用缓冲区后释放它们,只需在代码末尾加上free(buffer); free(buffer2);即可。 - tomk
显示剩余2条评论
3个回答

1

0

试试这个,我经历了很多事情,最终找到了一个解决方案。

-(UIImage*)renderImg{
        GLint backingWidth = 0;
        GLint backingHeight = 0;
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
        GLubyte *buffer = (GLubyte *) malloc(backingWidth * backingHeight * 4);
        GLubyte *buffer2 = (GLubyte *) malloc(backingWidth * backingHeight * 4);

        glReadPixels(0, 0, backingWidth, backingHeight, GL_RGBA, GL_UNSIGNED_BYTE,
                     (GLvoid *)buffer);
        for (int y=0; y<backingHeight; y++) {
            for (int x=0; x<backingWidth*4; x++) {
                buffer2[y * 4 * backingWidth + x] =
                buffer[(backingHeight - y - 1) * backingWidth * 4 + x];
            }
        }
        free(buffer);
        CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2,
                                                                  backingWidth * backingHeight * 4,
                                                                  myProviderReleaseData);
        // set up for CGImage creation
        int bitsPerComponent = 8;
        int bitsPerPixel = 32;
        int bytesPerRow = 4 * backingWidth;
        CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
        // Use this to retain alpha
        CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
        CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
        CGImageRef imageRef = CGImageCreate(backingWidth, backingHeight,
                                            bitsPerComponent, bitsPerPixel,
                                            bytesPerRow, colorSpaceRef,
                                            bitmapInfo, provider,
                                            NULL, NO,
                                            renderingIntent);
        // this contains our final image.
        UIImage *newUIImage = [UIImage imageWithCGImage:imageRef];
        CGImageRelease(imageRef);
        CGColorSpaceRelease(colorSpaceRef);
        CGDataProviderRelease(provider);

        return newUIImage;
    }

我认为它应该完美地工作。


0

更改您的可绘制属性

eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:

            [NSNumber numberWithBool:YES],  
                kEAGLDrawablePropertyRetainedBacking, 
                kEAGLColorFormatRGB565, 
                kEAGLDrawablePropertyColorFormat, nil];

kEAGLDrawablePropertyRetainedBacking设置为YES


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