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!");
}
}
* 更新 * 問題を絞り込むことができたと思います。コード行をコメントアウトした後、(デバイス上で)アプリを実行して、物事を絞り込む試行錯誤を始めました。(glReadPixels を使用して) 画面バッファーを取得し、CGImageRef を作成するTakeImageBufferSnapshot関数に問題があるようです。ここで、これから UIImage を作成しようとすると ([UIImage imageWithCGImage:] メソッドを使用して)、これが原因でアプリがクラッシュするようです。この行をコメントアウトすると、問題はないようです (という事実以外は)私はUIImage参照を持っていません)。
写真ライブラリに保存できるように、基本的に有効な UIImage 参照が必要です (テスト画像を使用しても問題なく動作するようです)。