【问题标题】:How can I make screen shot image from MTKView in iOS?如何在 iOS 中从 MTKView 制作屏幕截图?
【发布时间】:2016-01-31 15:33:07
【问题描述】:

我参考MetalKitEssentials,并通过MetalKitiOS 9.1中制作模型查看器应用程序。

我想从MTKView 制作屏幕截图(RGBA 格式)。 但是,我只得到黑色图像。

我该怎么办?

感谢您的阅读!

代码:

@implemtntation MetalViewController
{
    MTKView *metalView;
}

- (void)viewDidLoad
{
    [super viewDidload];
    [self setup];
}

- (void)setup
{
    metalDevice = MTLCreateSystemDefaultDevice();
    commandQueue = [metalDevice newCommandQueue];
    defaultLibrary = [metalDevice newDefaultLibrary];

    metalView = [[MTKView alloc] initWithFrame:self.view.frame];
    [self.view addSubview:metalView];

    metalView.delegate = self;
    metalView.device = metalDevice;
    metalView.sampleCount = 4;
    metalView.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
    metalView.opaque = false;
    metalView.framebufferOnly = true;
    // and more set up for Metal ...
}

// if you make screen shot, call this method.
- (IBAction)onCapture:(id)sender
{
    CGRect screenRect = [[UIScreen mainScreen] bounds];
    UIGraphicsBeginImageContextWithOptions(screenRect.size, YES, 0.0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextFillRect(context, screenRect);

    // draw image to context
    [metalView.layer renderInContext:context];

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    UIImageWriteToSavedPhotosAlbum(image, self,
                                   @selector(completeSavedImage:didFinishSavingWithError:contextInfo:), nil);
}

- (void)completeSavedImage:(UIImage *)_image didFinishSavingWithError:(NSError *)_error contextInfo:(void *)_contextInfo
{
    if (!_error)
    {
        NSLog(@"ok");
    }
    else
    {
        NSLog(@"error");
    }
}

@end

【问题讨论】:

    标签: ios objective-c metal


    【解决方案1】:

    自行解决。

    我找到了一个类似的topic

    我为以下几点编写代码。

    1:使用 Objective-C

    2:不使用扩展MTLTexture

    - (IBAction)onCapture:(id)sender
    {
        id<MTLTexture> lastDrawableDisplayed = [metalView.currentDrawable texture];
    
        int width = (int)[lastDrawableDisplayed width];
        int height = (int)[lastDrawableDisplayed height];
        int rowBytes = width * 4;
        int selfturesize = width * height * 4;
    
        void *p = malloc(selfturesize);
    
        [lastDrawableDisplayed getBytes:p bytesPerRow:rowBytes fromRegion:MTLRegionMake2D(0, 0, width, height) mipmapLevel:0];
    
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaFirst;
    
        CGDataProviderRef provider = CGDataProviderCreateWithData(nil, p, selfturesize, nil);
        CGImageRef cgImageRef = CGImageCreate(width, height, 8, 32, rowBytes, colorSpace, bitmapInfo, provider, nil, true, (CGColorRenderingIntent)kCGRenderingIntentDefault);
    
        UIImage *getImage = [UIImage imageWithCGImage:cgImageRef];
        CFRelease(cgImageRef);
        free(p);
    
        NSData *pngData = UIImagePNGRepresentation(getImage);
        UIImage *pngImage = [UIImage imageWithData:pngData];
        UIImageWriteToSavedPhotosAlbum(pngImage, self,
            @selector(completeSavedImage:didFinishSavingWithError:contextInfo:), nil);
    }
    

    但是,我在 getBytes 方法中收到以下 exec 错误。

    failed assertion `texture must not be a framebufferOnly texture.'
    

    此错误已在以下修复中得到修复。 所以,我改变了 MTKView 的设置。

    metalView.framebufferOnly = false;
    

    谢谢。

    【讨论】:

      【解决方案2】:

      参考:https://stackoverflow.com/a/33903182/767280.

      对于 swift 4.0,

      let lastDrawableDisplayed = metalView?.currentDrawable?.texture
      
      if let imageRef = lastDrawableDisplayed?.toImage() {
          let uiImage:UIImage = UIImage.init(cgImage: imageRef)
      }
      
      extension MTLTexture {
      
          func bytes() -> UnsafeMutableRawPointer {
              let width = self.width
              let height   = self.height
              let rowBytes = self.width * 4
              let p = malloc(width * height * 4)
      
              self.getBytes(p!, bytesPerRow: rowBytes, from: MTLRegionMake2D(0, 0, width, height), mipmapLevel: 0)
      
              return p!
          }
      
          func toImage() -> CGImage? {
              let p = bytes()
      
              let pColorSpace = CGColorSpaceCreateDeviceRGB()
      
              let rawBitmapInfo = CGImageAlphaInfo.noneSkipFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
              let bitmapInfo:CGBitmapInfo = CGBitmapInfo(rawValue: rawBitmapInfo)
      
              let selftureSize = self.width * self.height * 4
              let rowBytes = self.width * 4
              let releaseMaskImagePixelData: CGDataProviderReleaseDataCallback = { (info: UnsafeMutableRawPointer?, data: UnsafeRawPointer, size: Int) -> () in
                  return
              }
              let provider = CGDataProvider(dataInfo: nil, data: p, size: selftureSize, releaseData: releaseMaskImagePixelData)
              let cgImageRef = CGImage(width: self.width, height: self.height, bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: rowBytes, space: pColorSpace, bitmapInfo: bitmapInfo, provider: provider!, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent)!
      
              return cgImageRef
          }
      }
      

      【讨论】:

        【解决方案3】:

        self.mtkView.framebufferOnly = 否;

        - (UIImage *)imageWithCurrentTexture:(MTKView *)mtkView {
             CIContext * context = [CIContext contextWithMTLDevice:mtkView.device];
             CIImage *outputImage = [[CIImage alloc] initWithMTLTexture:mtkView.currentDrawable.texture options:@{kCIImageColorSpace:(__bridge_transfer id)CGColorSpaceCreateDeviceRGB()}];
             CGImageRef cgImg = [context createCGImage:outputImage fromRect:CGRectMake(0, 0, [UIScreen mainScreen].nativeBounds.size.width, [UIScreen mainScreen].nativeBounds.size.height)];
             UIImage *resultImg = [UIImage imageWithCGImage:cgImg scale:1.0 orientation:UIImageOrientationDownMirrored];
             CGImageRelease(cgImg);
             return resultImg;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-11-08
          • 2015-09-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-28
          • 1970-01-01
          • 2014-10-16
          相关资源
          最近更新 更多