2013-06-09 3 views
2

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

Код я пытался работы для UIKit, но возвращает черный экран для OpenGLES частей

CGSize imageSize = [[UIScreen mainScreen] bounds].size; 
    if (NULL != UIGraphicsBeginImageContextWithOptions) 
     UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0); 
    else 
     UIGraphicsBeginImageContext(imageSize); 

    CGContextRef context = UIGraphicsGetCurrentContext(); 

    // Iterate over every window from back to front 
    for (UIWindow *window in [[UIApplication sharedApplication] windows]) 
    { 
     if (![window respondsToSelector:@selector(screen)] || [window screen] == [UIScreen mainScreen]) 
     { 
      // -renderInContext: renders in the coordinate space of the layer, 
      // so we must first apply the layer's geometry to the graphics context 
      CGContextSaveGState(context); 
      // Center the context around the window's anchor point 
      CGContextTranslateCTM(context, [window center].x, [window center].y); 
      // Apply the window's transform about the anchor point 
      CGContextConcatCTM(context, [window transform]); 
      // Offset by the portion of the bounds left of and above the anchor point 
      CGContextTranslateCTM(context, 
            -[window bounds].size.width * [[window layer] anchorPoint].x, 
            -[window bounds].size.height * [[window layer] anchorPoint].y); 


      for (UIView *subview in window.subviews) 
      { 
       CAEAGLLayer *eaglLayer = (CAEAGLLayer *) subview.layer; 
       if([eaglLayer respondsToSelector:@selector(drawableProperties)]) { 
        NSLog(@"reponds"); 
        /*eaglLayer.drawableProperties = @{ 
                kEAGLDrawablePropertyRetainedBacking: [NSNumber numberWithBool:YES], 
                kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8 
                };*/ 
        UIImageView *glImageView = [[UIImageView alloc] initWithImage:[self snapshotx:subview]]; 
        glImageView.transform = CGAffineTransformMakeScale(1, -1); 
        [glImageView.layer renderInContext:context]; 

        //CGImageRef iref = [self snapshot:subview withContext:context]; 
        //CGContextDrawImage(context, CGRectMake(0.0, 0.0, 640, 960), iref); 

       } 

       [[window layer] renderInContext:context]; 

       // Restore the context 
       CGContextRestoreGState(context); 
      } 
     } 
    } 

    // Retrieve the screenshot image 
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 

    UIGraphicsEndImageContext(); 

    return image; 

и

- (UIImage*)snapshotx:(UIView*)eaglview 
{ 
    GLint backingWidth, backingHeight; 

    //glBindRenderbufferOES(GL_RENDERBUFFER_OES, _colorRenderbuffer); 
    //don't know how to access the renderbuffer if i can't directly access the below code 

    // Get the size of the backing CAEAGLLayer 
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); 
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); 

    NSInteger x = 0, y = 0, width = backingWidth, height = backingHeight; 
    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, 
            // Fix from Apple implementation 
            // (was: kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast). 
            kCGBitmapByteOrderDefault, 
            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; 
} 

Любые советы о том, как смешивать два, не имея возможности изменить классы в остальной части приложения?

Спасибо!

ответ

1

Я вижу, что вы пытались сделать там, и это не очень плохое понятие. Кажется, есть одна большая проблема: вы не можете просто позвонить glReadPixels в любое удобное для вас время. Прежде всего, вы должны убедиться, что буфер заполнен данными (пикселями), которые вам действительно нужны, и во-вторых, он должен быть вызван в той же теме, что и его часть GL работает ...

Если взгляды GL не у вас может возникнуть большая проблема с вызовом этого метода скриншотов, вам нужно вызвать метод, который вызовет привязку его внутреннего контекста, и если он будет анимироваться, вам нужно будет знать, когда цикл выполняется, чтобы гарантировать, что пиксели, которые вы получаете, одинаковы как те, которые были представлены на взгляд.

В любом случае, если вы пройдете все те, вам, вероятно, придется «прыгать» через разные темы или ждать окончания цикла. В этом случае я предлагаю вам использовать блоки, которые возвращают изображение скриншота, которое должно передаваться как параметр метода, чтобы вы могли его поймать всякий раз, когда он возвращается. Было сказано, что было бы лучше, если бы вы могли переопределить некоторые методы в представлениях GL, чтобы иметь возможность вернуть вам изображение скриншота через блок обратного вызова и написать некоторую рекурсивную систему.

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

Обратите внимание, что вам просто не разрешено делать скриншот (например, одно нажатие кнопки «Дом» и «Заблокировать» одновременно) в вашем приложении. Что касается части UIView, которая так легко создает изображение из нее, так это то, что UIView перерисовывается в графический контекст независимо от экрана; как если бы вы могли взять какой-то GL-трубопровод и связать его с вашим собственным буфером и контекстом и нарисовать его, это может привести к тому, что он сможет получить свой скриншот независимо и может быть выполнен в любом потоке.

+0

Хорошо, что имеет смысл, если бы я должен был иметь доступ к взглядам OpenGLES, я должен иметь вызов снимка там и есть способ, которым я могу поставить его в нужное время, когда буфер полон ? Возможно, glview: screenshot {[mysingleton glscreenshot]}? –

0

На самом деле, я пытаюсь сделать что-то подобное: я выложу в полной мере, когда я гладила его, но вкратце:

  • использовать метод renderInContext слоя вашего SuperView в
  • в
  • в подвиды, которые используют OpenGL, реализуйте слоя делегата drawLayer: InContext: метод
  • , чтобы сделать ваше мнение в контексте, используйте CVOpenGLESTextureCacheRef

слой вашего SuperView в будет ок l1 renderInContext: на каждом из подслоев - с помощью метода делегата ваш GLView отвечает за его слой.

Использование кеша текстур намного, намного быстрее, чем glReadPixels: это, вероятно, будет узким местом.

Сэм

Смежные вопросы