我正在尝试将 OpenGL 缓冲区(视图中当前显示的内容)保存到设备的照片库中。下面的代码片段在模拟器上运行良好。但对于实际设备,它正在崩溃。我相信我创建从屏幕捕获的 UIImage 的方式可能存在问题。
- 此操作通过 IBAction 事件句柄方法启动。
- 我用来保存图像的函数是 UIImageWriteToSavedPhotosAlbum(我最近将其更改为 ALAssetsLibrary 的 writeImageToSavedPhotosAlbum)。
- 我已确保我的应用程序有权访问照片库。
- 我还确保我的 CGImageRed 是全局定义的(在文件顶部定义)并且我的 UIImage 是一个(非原子,保留)属性。
有人可以帮我解决这个问题吗?我想要一个从 glReadPixels 数据生成的有效 UIImage 引用。
下面是相关的代码片段(调用保存到照片库):
-(void)TakeImageBufferSnapshot:(CGSize)dimensions
{
NSLog(@"TakeSnapShot 1 : (%f, %f)", dimensions.width, dimensions.height);
NSInteger size = dimensions.width * dimensions.height * 4;
GLubyte *buffer = (GLubyte *) malloc(size);
glReadPixels(0, 0, dimensions.width, dimensions.height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
GLubyte *buffer2 = (GLubyte *) malloc(size);
int height = (int)dimensions.height - 1;
int width = (int)dimensions.width;
for(int y = 0; y < dimensions.height; y++)
{
for(int x = 0; x < dimensions.width * 4; x++)
{
buffer2[(height - 1 - y) * width * 4 + x] = buffer[y * 4 * width + x];
}
}
NSLog(@"TakeSnapShot 2");
// make data provider with data.
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, size, NULL);
if (buffer) free(buffer);
if (buffer2) free(buffer2);
// prep the ingredients
int bitsPerComponent = 8;
int bitsPerPixel = 32;
int bytesPerRow = 4 * self.view.bounds.size.width;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
NSLog(@"TakeSnapShot 3");
// make the cgimage
g_savePhotoImageRef = CGImageCreate(dimensions.width, dimensions.height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
NSLog(@"TakeSnapShot 4");
// then make the uiimage from that
self.savePhotoImage = [UIImage imageWithCGImage:g_savePhotoImageRef];
CGColorSpaceRelease(colorSpaceRef);
CGDataProviderRelease(provider);
}
-(void)SaveToPhotoAlbum
{
ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
NSLog(@"Authorization status: %d", status);
if (status == ALAuthorizationStatusAuthorized)
{
[self TakeImageBufferSnapshot:self.view.bounds.size];
// UPDATED - DO NOT proceed to save to album below.
// Instead, set the created image to a UIImageView IBOutlet.
// On the simulator this shows the screen/buffer captured image (as expected) -
// but on the device (ipad) this doesnt show anything and the app crashes.
self.testImageView.image = self.savePhotoImage;
return;
NSLog(@"Saving to photo album...");
UIImageWriteToSavedPhotosAlbum(self.savePhotoImage,
self,
@selector(photoAlbumImageSave:didFinishSavingWithError:contextInfo:),
nil);
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Access is denied"
message:@"Allow access to your Photos library to save this image."
delegate:nil
cancelButtonTitle:@"Close"
otherButtonTitles:nil, nil];
[alert show];
}
}
- (void)photoAlbumImageSave:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)context
{
self.savePhotoImage = nil;
CGImageRelease(g_savePhotoImageRef);
if (error)
{
NSLog(@"Error saving photo to albums: %@", error.description);
}
else
{
NSLog(@"Saved to albums!");
}
}
* 更新 * 我想我已经设法缩小我的问题范围。我开始进行反复试验,在注释掉代码行后我运行应用程序(在设备上),以缩小范围。看起来我可能对TakeImageBufferSnapshot函数有问题,该函数获取屏幕缓冲区(使用 glReadPixels)并创建一个 CGImageRef。现在,当我尝试从中创建 UIImage 时(使用 [UIImage imageWithCGImage:] 方法,这似乎就是应用程序崩溃的原因。如果我将这一行注释掉,似乎没有问题(除了事实上我没有 UIImage 参考)。
我基本上需要一个有效的 UIImage 参考,以便我可以将其保存到照片库(使用测试图像似乎可以正常工作)。