Скриншот содержимого OpenGL ES для приложения Paint - PullRequest
5 голосов
/ 21 сентября 2011

Я работаю над приложением рисования для iphone.В моем коде я использую imageView, который содержит контурное изображение, на которое я помещаю CAEAGLLayer для заливки цветов в контурном изображении.Сейчас я делаю скриншот визуализированного контента OpenGL ES [CAEAGLLayer], используя функцию:

- (UIImage*)snapshot:(UIView*)eaglview{
GLint backingWidth1, backingHeight1;

// 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, &backingWidth1);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight1);

NSInteger x = 0, y = 0, width = backingWidth1, height = backingHeight1;
NSInteger dataLength = width * height * 4;
GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));

// Read pixel data from the framebuffer
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glReadPixels(x, y, width, height, 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(width, height, 8, 32, width * 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 = eaglview.contentScaleFactor;
    widthInPoints = width / scale;
    heightInPoints = height / scale;
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(widthInPoints, heightInPoints), NO, scale);
}
else {
    // On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
    widthInPoints = width;
    heightInPoints = height;
    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;}

, комбинируя этот скриншот с контурным изображением, используя функцию:

- (void)Combine:(UIImage *)Back{


UIImage *Front =backgroundImageView.image;


//UIGraphicsBeginImageContext(Back.size);  
UIGraphicsBeginImageContext(CGSizeMake(640,960));
// Draw image1  
[Back drawInRect:CGRectMake(0, 0, Back.size.width*2, Back.size.height*2)];  

// Draw image2  
[Front drawInRect:CGRectMake(0, 0, Front.size.width*2, Front.size.height*2)];  

UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();  


UIImageWriteToSavedPhotosAlbum(resultingImage, nil, nil, nil);


UIGraphicsEndImageContext();  

}

Сохраните это изображение в фотоальбом, используя функцию

 -(void)captureToPhotoAlbum {
[self Combine:[self snapshot:self]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Success" message:@"Image saved to Photo Album" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
[alert release];    }

Над кодом работает, но качество изображения скриншота низкое.На контурах кисти есть сероватый контур.Я загрузил скриншот моего приложения, который представляет собой комбинацию содержимого opengles и UIImage.

Screenshot

Есть ли способ получить скриншот дисплея Retina для содержимого opengles-CAEaglelayer.

Заранее спасибо!

Ответы [ 2 ]

4 голосов
/ 21 сентября 2011

Я не верю, что решение - это ваша проблема здесь.Если вы не видите серые контуры на своем чертеже, когда он появляется на экране, скорее всего, вы наблюдаете артефакт сжатия в процессе сохранения.Ваше изображение, вероятно, сохраняется как изображение JPEG низкого качества, где на острых краях появляются артефакты, подобные тем, что на вашем рисунке.

Чтобы обойти это, ответ Бена Вейса здесь предоставляет следующий код для принудительного сохранения вашего изображения в библиотеке фотографий в формате PNG:

UIImage* im = [UIImage imageWithCGImage:myCGRef]; // make image from CGRef
NSData* imdata =  UIImagePNGRepresentation ( im ); // get PNG representation
UIImage* im2 = [UIImage imageWithData:imdata]; // wrap UIImage around PNG representation
UIImageWriteToSavedPhotosAlbum(im2, nil, nil, nil); // save to photo album

Хотя это, вероятно, самый простой способ решения вашей проблемы, вы также можете попробовать использовать мультисэмпловое сглаживание, так какApple описывает в разделе « Использование мультисэмплинга для улучшения качества изображения » Руководства по программированию OpenGL ES для iOS.В зависимости от того, насколько вы ограничены по скорости заполнения, MSAA может привести к небольшому замедлению работы вашего приложения.

1 голос
/ 21 сентября 2011

Вы используете kCGImageAlphaPremultipliedLast при создании контекста растрового изображения CG. Хотя я не вижу ваш код OpenGL, мне кажется маловероятным, что ваш контекст OpenGL отображает предварительно умноженную альфа. К сожалению, IIRC, невозможно создать не предварительно умноженный контекст растрового изображения CG на iOS (он будет использовать kCGImageAlphaLast, но я думаю, что это просто вызовет сбой при создании), поэтому вам может потребоваться предварительно умножить данные вручную между получить его из OpenGL и создать контекст CG.

С другой стороны, есть ли причина, по которой ваш контекст OpenGL имеет альфа-канал? Не могли бы вы сделать его непрозрачным белым, а затем использовать kCGImageAlphaNoneSkipLast?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...