2011-09-21 11 views
5

Pracuję nad aplikacją do malowania dla iPhone'a. W moim kodzie używam imageView, który zawiera obraz konspektu, na którym umieszczam CAEAGLLayer do wypełniania kolorów w obrazie konspektu. Teraz biorę zrzut ekranu OpenGL ES [CAEAGLLayer] świadczonych zawartości przy użyciu funkcji:Zrzut ekranu z zawartości OpenGL ES dla aplikacji Paint

- (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;} 

łącząc to zrzut ekranu z zarys obrazu za pomocą funkcji:

- (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(); 

}

Zapisz ten obraz do FOTOGRAFICZNY korzystania funkcja

-(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]; } 

Powyższy kod działa, ale obraz qua Zła jakość zrzutu ekranu. Na konturach pędzla występuje szarawy zarys. Przesłałem zrzut ekranu mojej aplikacji, która jest kombinacją zawartości openglingowej & UIImage.

Screenshot

Czy istnieje jakiś sposób, aby wyświetlacz Retina zrzut zawartości OpenGLES-CAEaglelayer.

Z góry dziękuję!

Odpowiedz

4

Nie sądzę, że rozwiązanie problemu jest tutaj problemem. Jeśli nie widzisz szarych konturów na rysunku, gdy pojawi się on na ekranie, szanse na to, że obserwujesz artefakt kompresji podczas zapisywania. Obraz jest prawdopodobnie zapisywany jako obraz JPEG o niższej jakości, gdzie artefakty pojawią się na ostrych krawędziach, takich jak te na rysunku.

Aby obejść ten problem, Ben Weiss odpowiedź here zapewnia następujący kod dla zmuszając swój wizerunek zostać zapisane do biblioteki zdjęć jako 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 

Chociaż jest to prawdopodobnie najprostszy sposób na rozwiązanie problemu tutaj można również spróbować zastosować antysprawianie wielopróbkowe, co Apple opisuje w sekcji "Using Multisampling to Improve Image Quality" Przewodnika programowania OpenGL ES dla systemu iOS. Zależnie od tego, jak ograniczony jest współczynnik wypełnienia, MSAA może spowodować spowolnienie działania aplikacji.

+0

Dzięki Brad, tego właśnie szukałem! – user392406

1

Podczas tworzenia kontekstu bitmapowego CG używasz kCGImageAlphaPremultipliedLast. Chociaż nie widzę twojego kodu OpenGL, wydaje mi się mało prawdopodobne, że twój kontekst OpenGL renderuje premilpowane alfa. Niestety, IIRC, nie jest możliwe utworzenie nieprzemnożonego kontekstu bitmapowego CG w systemie iOS (używałbym kCGImageAlphaLast, ale myślę, że spowoduje to niepowodzenie wywołania kreacji), więc konieczne może być ręczne podniesienie wartości danych ręcznie między pobieranie z OpenGL i tworzenie kontekstu CG.

Z drugiej strony, czy istnieje powód, dla którego kontekst OpenGL ma kanał alfa? Czy możesz sprawić, że będzie on biały nieprzezroczysty, a następnie użyć kCGImageAlphaNoneSkipLast?