Как получить UIImage из EAGLView?

Я пытаюсь получить UIImage из того, что отображается в моем EAGLView. Любые предложения о том, как это сделать?

EDIT: в качестве примечаний demianturner ниже вам больше не нужно отображать слой, вы можете (и должны) теперь использовать более высокий уровень [UIView drawViewHierarchyInRect:] . Кроме этого; это должно работать одинаково.

EAGLView – это просто своего рода вид, а его базовый CAEAGLLayer – всего лишь своего рода слой. Это означает, что стандартный подход для преобразования представления / слоя в UIImage будет работать. (Тот факт, что связанный вопрос – это UIWebview, не имеет значения, это просто еще один вид зрения.)

Вот очищенная версия кода Quakeboy. Я тестировал его на iPad, и все работает отлично. Улучшения include:

  • работает с любым размером EAGLView
  • работает с отображением сетчатки (точечная шкала 2)
  • заменил вложенный цикл на memcpy
  • очистка утечек памяти
  • сохраняет UIImage в фотоальбоме в качестве бонуса.

Используйте это как метод в своем EAGLView:

 -(void)snapUIImage { int s = 1; UIScreen* screen = [ UIScreen mainScreen ]; if ( [ screen respondsToSelector:@selector(scale) ] ) s = (int) [ screen scale ]; const int w = self.frame.size.width; const int h = self.frame.size.height; const NSInteger myDataLength = w * h * 4 * s * s; // allocate array and read pixels into it. GLubyte *buffer = (GLubyte *) malloc(myDataLength); glReadPixels(0, 0, w*s, h*s, 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*s; y++) { memcpy( buffer2 + (h*s - 1 - y) * w * 4 * s, buffer + (y * 4 * w * s), w * 4 * s ); } free(buffer); // work with the flipped buffer, so get rid of the original one. // 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 * s; CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; // make the cgimage CGImageRef imageRef = CGImageCreate(w*s, h*s, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); // then make the uiimage from that UIImage *myImage = [ UIImage imageWithCGImage:imageRef scale:s orientation:UIImageOrientationUp ]; UIImageWriteToSavedPhotosAlbum( myImage, nil, nil, nil ); CGImageRelease( imageRef ); CGDataProviderRelease(provider); CGColorSpaceRelease(colorSpaceRef); free(buffer2); } 
 -(UIImage *) saveImageFromGLView { NSInteger myDataLength = 320 * 480 * 4; // allocate array and read pixels into it. GLubyte *buffer = (GLubyte *) malloc(myDataLength); glReadPixels(0, 0, 320, 480, 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 <480; y++) { for(int x = 0; x <320 * 4; x++) { buffer2[(479 - y) * 320 * 4 + x] = buffer[y * 4 * 320 + 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 * 320; CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; // make the cgimage CGImageRef imageRef = CGImageCreate(320, 480, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); // then make the uiimage from that UIImage *myImage = [UIImage imageWithCGImage:imageRef]; CGImageRelease( imageRef ); CGDataProviderRelease(provider); CGColorSpaceRelease(colorSpaceRef); free(buffer2); return myImage; } 

Мне не удалось получить другие ответы здесь, чтобы правильно работать для меня.

Через несколько дней я наконец получил рабочее решение. Существует код, предоставленный Apple, который создает UIImage из EAGLView. Затем вам просто нужно перевернуть изображение по вертикали, так как UIkit перевернут.

Apple Provided Method – Изменено для того, чтобы быть внутри представления, которое вы хотите сделать в изображении.

  -(UIImage *) drawableToCGImage { GLint backingWidth2, backingHeight2; //Bind the color renderbuffer used to render the OpenGL ES view // If your application only creates a single color renderbuffer which is already bound at this point, // this call is redundant, but it is needed if you're dealing with multiple renderbuffers. // Note, replace "_colorRenderbuffer" with the actual name of the renderbuffer object defined in your class. glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); // Get the size of the backing CAEAGLLayer glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth2); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight2); NSInteger x = 0, y = 0, width2 = backingWidth2, height2 = backingHeight2; NSInteger dataLength = width2 * height2 * 4; GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte)); // Read pixel data from the framebuffer glPixelStorei(GL_PACK_ALIGNMENT, 4); glReadPixels(x, y, width2, height2, GL_RGBA, GL_UNSIGNED_BYTE, data); // Create a CGImage with the pixel data // If your OpenGL ES content is opaque, use kCGImageAlphaNoneSkipLast to ignore the alpha channel // otherwise, use kCGImageAlphaPremultipliedLast CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL); CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGImageRef iref = CGImageCreate(width2, height2, 8, 32, width2 * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast, ref, NULL, true, kCGRenderingIntentDefault); // OpenGL ES measures data in PIXELS // Create a graphics context with the target size measured in POINTS NSInteger widthInPoints, heightInPoints; if (NULL != UIGraphicsBeginImageContextWithOptions) { // On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration // Set the scale parameter to your OpenGL ES view's contentScaleFactor // so that you get a high-resolution snapshot when its value is greater than 1.0 CGFloat scale = self.contentScaleFactor; widthInPoints = width2 / scale; heightInPoints = height2 / scale; UIGraphicsBeginImageContextWithOptions(CGSizeMake(widthInPoints, heightInPoints), NO, scale); } else { // On iOS prior to 4, fall back to use UIGraphicsBeginImageContext widthInPoints = width2; heightInPoints = height2; UIGraphicsBeginImageContext(CGSizeMake(widthInPoints, heightInPoints)); } CGContextRef cgcontext = UIGraphicsGetCurrentContext(); // UIKit coordinate system is upside down to GL/Quartz coordinate system // Flip the CGImage by rendering it to the flipped bitmap context // The size of the destination area is measured in POINTS CGContextSetBlendMode(cgcontext, kCGBlendModeCopy); CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, widthInPoints, heightInPoints), iref); // Retrieve the UIImage from the current context UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); // Clean up free(data); CFRelease(ref); CFRelease(colorspace); CGImageRelease(iref); return image; 

}

И heres метод для переворачивания изображения

 - (UIImage *) flipImageVertically:(UIImage *)originalImage { UIImageView *tempImageView = [[UIImageView alloc] initWithImage:originalImage]; UIGraphicsBeginImageContext(tempImageView.frame.size); CGContextRef context = UIGraphicsGetCurrentContext(); CGAffineTransform flipVertical = CGAffineTransformMake( 1, 0, 0, -1, 0, tempImageView.frame.size.height ); CGContextConcatCTM(context, flipVertical); [tempImageView.layer renderInContext:context]; UIImage *flippedImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); //[tempImageView release]; return flippedImage; 

}

И вот ссылка на страницу Apple dev, где я нашел первый метод для справки. http://developer.apple.com/library/ios/#qa/qa1704/_index.html

CGDataProviderCreateWithData имеет обратный вызов для выпуска данных, где вы должны сделать выпуск:

 void releaseBufferData(void *info, const void *data, size_t size) { free((void*)data); } 

Затем сделайте это, как и другие примеры, но НЕ для получения данных:

 GLubyte *bufferData = (GLubyte *) malloc(bufferDataSize); CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bufferData, bufferDataSize, releaseBufferData); .... CGDataProviderRelease(provider); 

Или просто используйте CGDataProviderCreateWithCFData без релиза:

 GLubyte *bufferData = (GLubyte *) malloc(bufferDataSize); NSData *data = [NSData dataWithBytes:bufferData length:bufferDataSize]; CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data); .... CGDataProviderRelease(provider); free(bufferData); // Remember to free it 

Для получения дополнительной информации, пожалуйста, ознакомьтесь с этим:

Какой правильный шаблон управления памятью для буфера-> CGImageRef-> UIImage?

С помощью этого выше кода Брэда Ларсона вы должны отредактировать свой EAGLView.m

 - (id)initWithCoder:(NSCoder*)coder{ self = [super initWithCoder:coder]; if (self) { CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; eaglLayer.opaque = TRUE; eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; } return self; } 

Вы должны изменить значение numberWithBool YES

  • Простой способ изменить положение UIView?
  • Как настроить размер содержимого UIScrollView динамически
  • Рисование поэтапно в UIView (iPhone)
  • Ориентация в UIView добавлена ​​в UIWindow
  • Метод доступа после завершения анимации UIImageView
  • Как реализовать представление аккордеона для iPhone SDK-приложения?
  • Изменение привязки моего CALayer перемещает вид
  • Назначить xib для UIView в Swift
  • анимация addSubview
  • Как получить цвет пикселя в UIView?
  • UIView против UIViewController
  • Давайте будем гением компьютера.