Printing 是否有方法将金属输出捕获为位图或其他适合打印的格式?

Printing 是否有方法将金属输出捕获为位图或其他适合打印的格式?,printing,bitmap,metal,Printing,Bitmap,Metal,我正在使用MTKit将一个应用程序从OpenGL转换为Metal。最初的应用程序允许用户打印正在查看的OpenGL生成的屏幕(我也用核心图形完成了这项工作)。我想用金属做同样的事。我原以为找到解决问题的办法或至少找到解决问题的方法很容易,但我被卡住了。有没有人解决了这个问题,或者有没有人对我应该寻找什么有任何线索 我是一个经验丰富的Mac程序员(我更喜欢Objective-C解决方案,但我在其他方面做了一些工作),我是Metal的高级新手 MacOS 10.15.3,所有MacBook 斯威夫

我正在使用MTKit将一个应用程序从OpenGL转换为Metal。最初的应用程序允许用户打印正在查看的OpenGL生成的屏幕(我也用核心图形完成了这项工作)。我想用金属做同样的事。我原以为找到解决问题的办法或至少找到解决问题的方法很容易,但我被卡住了。有没有人解决了这个问题,或者有没有人对我应该寻找什么有任何线索

我是一个经验丰富的Mac程序员(我更喜欢Objective-C解决方案,但我在其他方面做了一些工作),我是Metal的高级新手

  • MacOS 10.15.3,所有MacBook
  • 斯威夫特5
  • 代码11.2.1

我假设您想从MTKView保存图像。但是这个函数应该适用于任何纹理。也不要忘记设置:
framebufferOnly=false

bool-takeScreenshot=true;
///每当视图需要渲染帧时调用
-(void)drawInMTKView:(非空MTKView*)视图
{
//为当前可绘制对象的每个渲染过程创建新的命令缓冲区
id commandBuffer=[\u commandQueue commandBuffer];
commandBuffer.label=@“MyCommand”;
//获取从视图的可绘制纹理生成的renderPassDescriptor
MTLRenderPassDescriptor*renderPassDescriptor=view.currentRenderPassDescriptor;
id currentSwapChainTexture=view.currentDrawable.texture;
//您的渲染代码。。。
[commandBuffer addCompletedHandler:^(id cb)
{
如果(截图)
{
保存纹理(currentSwapChainTexture);
截图=假;
}
}];
//在此处完成渲染并将命令缓冲区推送到GPU
[命令缓冲区提交];
//CPU-GPU同步
if(截图)[commandBuffer waituntlcompleted];

保存纹理功能:

void SaveTexture(id<MTLTexture> texture)
{
    int width = (int) texture.width;
    int height = (int) texture.height;
    int bytePerPixel = 4;
    int bytesPerRow = width * bytePerPixel;
    int bytesCount = width * height * bytePerPixel;
    int bitsPerComponent = 8;
    int bitsPerPixel = 32;

    void *imageBytes = malloc(bytesCount);
    void *destBytes = malloc(bytesCount);

    MTLRegion mtlregion = MTLRegionMake2D(0, 0, width, height);
    [texture getBytes:imageBytes bytesPerRow:bytesPerRow fromRegion:mtlregion mipmapLevel:0];

    vImage_Buffer src;
    src.data = imageBytes;
    src.width = width;
    src.height = height;
    src.rowBytes = bytesPerRow;


    vImage_Buffer dest;
    dest.data = destBytes;
    dest.width = width;
    dest.height = height;
    dest.rowBytes = bytesPerRow;

    // BGRA -> RGBA (Swap)
    const uint8_t map[4] = {2, 1, 0, 3};
    vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags);


    CGColorSpaceRef cgColorSpaceRef = CGColorSpaceCreateWithName(kCGColorSpaceDisplayP3); //kCGColorSpaceSRGB - For sRGB
    CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
    CGContextRef context = CGBitmapContextCreate(destBytes, width, height, bitsPerComponent, bytesPerRow, cgColorSpaceRef, bitmapInfo);
    CGImageRef cgImage = CGBitmapContextCreateImage(context);

    // Your NSImage
    NSImage * image = [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize];

    // Save to Photos
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^
     {
        [PHAssetCreationRequest creationRequestForAssetFromImage: image];
    }

                                      completionHandler:^(BOOL success, NSError * error)
     {
        if(success) printf("Success \n");
    }];



    free(imageBytes);
    free(destBytes);
    CGColorSpaceRelease(cgColorSpaceRef);
    CGContextRelease(context);
    CGImageRelease(cgImage);
    texture = nil;
}
void SaveTexture(id纹理)
{
int width=(int)texture.width;
int height=(int)texture.height;
int bytePerPixel=4;
int bytesPerRow=宽度*bytePerPixel;
int字节数=宽度*高度*字节像素;
int bitsPerComponent=8;
int bitsPerPixel=32;
void*imageBytes=malloc(字节数);
void*destBytes=malloc(字节数);
MTLRegion MTLRegion=MTLRegionMake2D(0,0,宽度,高度);
[texture getBytes:imageBytes bytesPerRow:bytesPerRow fromRegion:mtlregion mipmapLevel:0];
vImage_缓冲区src;
src.data=imageBytes;
src.width=宽度;
src.height=高度;
src.rowBytes=bytesPerRow;
vImage_缓冲区目的地;
dest.data=destBytes;
dest.width=宽度;
目的地高度=高度;
dest.rowBytes=bytesPerRow;
//BGRA->RGBA(交换)
常数映射[4]={2,1,0,3};
vImagePermuteChannels_argb888(&src,&dest,map,kvImageNoFlags);
CGColorSpaceRef CGColorSpaceRef=CGColorSpaceCreateWithName(kCGColorSpaceDisplayP3);//kCGColorSpaceSRGB-用于sRGB
CGBitmapInfo bitmapInfo=KCGIMAGEAlphaPremultipledLast | kCGBitmapByteOrder32Big;
CGContextRef context=CGBitmapContextCreate(destBytes、宽度、高度、bitsPerComponent、bytesPerRow、cgColorSpaceRef、bitmapInfo);
CGImageRef cgImage=CGBitmapContextCreateImage(上下文);
//你的NSImage
NSImage*image=[[NSImage alloc]initWithCGImage:cgImage size:NSZeroSize];
//保存到照片
[[PHPhotoLibrary sharedPhotoLibrary]性能更改:^
{
[PhaseSetCreationRequest creationRequestForAssetFromImage:image];
}
completionHandler:^(布尔成功,N错误*错误)
{
if(success)printf(“success\n”);
}];
空闲(imageBytes);
空闲(字节);
cgColorSpacereLase(cgColorSpaceRef);
CGContextRelease(上下文);
CGImageRelease(cgImage);
纹理=零;
}

你到底需要打印什么,屏幕还是纹理?首先是屏幕。一般来说,我以后可能需要打印屏幕外的纹理。但我发现,对于你下面的回答,这并不重要;-)谢谢!稍后再试。效果很好。非常感谢,0xBFE1A8。感谢你的快速回答-我非常感谢你的关注。有e nit:当然,其中一个必须强制对视图进行刷新循环,以引发完成处理程序的执行,这对于SetNeedsDisplay来说足够简单。显示结束时,我手头有一个漂亮的CGImage,但为了一致性,我真的想打印它,而不是存档它。当然,我可以创建视图并仅在ma上打印在线程中,所以需要使用dispatch_async运行打印。有点复杂,但它可以工作。
void SaveTexture(id<MTLTexture> texture)
{
    int width = (int) texture.width;
    int height = (int) texture.height;
    int bytePerPixel = 4;
    int bytesPerRow = width * bytePerPixel;
    int bytesCount = width * height * bytePerPixel;
    int bitsPerComponent = 8;
    int bitsPerPixel = 32;

    void *imageBytes = malloc(bytesCount);
    void *destBytes = malloc(bytesCount);

    MTLRegion mtlregion = MTLRegionMake2D(0, 0, width, height);
    [texture getBytes:imageBytes bytesPerRow:bytesPerRow fromRegion:mtlregion mipmapLevel:0];

    vImage_Buffer src;
    src.data = imageBytes;
    src.width = width;
    src.height = height;
    src.rowBytes = bytesPerRow;


    vImage_Buffer dest;
    dest.data = destBytes;
    dest.width = width;
    dest.height = height;
    dest.rowBytes = bytesPerRow;

    // BGRA -> RGBA (Swap)
    const uint8_t map[4] = {2, 1, 0, 3};
    vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags);


    CGColorSpaceRef cgColorSpaceRef = CGColorSpaceCreateWithName(kCGColorSpaceDisplayP3); //kCGColorSpaceSRGB - For sRGB
    CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
    CGContextRef context = CGBitmapContextCreate(destBytes, width, height, bitsPerComponent, bytesPerRow, cgColorSpaceRef, bitmapInfo);
    CGImageRef cgImage = CGBitmapContextCreateImage(context);

    // Your NSImage
    NSImage * image = [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize];

    // Save to Photos
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^
     {
        [PHAssetCreationRequest creationRequestForAssetFromImage: image];
    }

                                      completionHandler:^(BOOL success, NSError * error)
     {
        if(success) printf("Success \n");
    }];



    free(imageBytes);
    free(destBytes);
    CGColorSpaceRelease(cgColorSpaceRef);
    CGContextRelease(context);
    CGImageRelease(cgImage);
    texture = nil;
}