【发布时间】:2020-06-04 22:39:22
【问题描述】:
我有一个应用程序,它使用 Metal 对屏幕进行一些渲染(必须使用 CAMetalLayer,而不是 MTKView),我想为用户提供保存结果的快照到磁盘。尝试在转换为 Objective-C 时遵循https://stackoverflow.com/a/47632198/2752221 的答案,我首先像这样编写了一个 commandBuffer 完成回调(注意这是手动保留/释放代码,而不是 ARC;抱歉,遗留代码):
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
[self performSelectorOnMainThread:@selector(saveImageTakingDrawable:) withObject:[drawable retain] waitUntilDone:NO];
optionKeyPressedAndUnhandled_ = NO;
}];
我在致电[commandBuffer presentDrawable:drawable] 后立即执行此操作;我的id <CAMetalDrawable> drawable 仍在范围内。这是我对saveImageTakingDrawable: 的实现:
- (void)saveImageTakingDrawable:(id <CAMetalDrawable>)drawable
{
// We need to have an image to save
if (!drawable) { NSBeep(); return; }
id<MTLTexture> displayTexture = drawable.texture;
if (!displayTexture) { NSBeep(); return; }
CIImage *ciImage = [CIImage imageWithMTLTexture:displayTexture options:nil];
// release the metal texture as soon as we can, to free up the system resources
[drawable release];
if (!ciImage) { NSBeep(); return; }
NSCIImageRep *rep = [NSCIImageRep imageRepWithCIImage:ciImage];
if (!rep) { NSBeep(); return; }
NSImage *nsImage = [[[NSImage alloc] initWithSize:rep.size] autorelease];
[nsImage addRepresentation:rep];
NSData *tiffData = [nsImage TIFFRepresentation];
if (!tiffData) { NSBeep(); return; }
... filesystem cruft culminating in ...
if ([tiffData writeToFile:filePath options:NSDataWritingWithoutOverwriting error:nil])
{
// play a sound to acknowledge saving
[[NSSound soundNamed:@"Tink"] play];
return;
}
NSBeep();
return;
}
结果是“叮当”的声音和一个 7.8 MB 大小合理的 .tif 文件 (1784x1090),但它是透明的,其中没有可用的图像数据;在 Hex Fiend 中查看文件显示整个文件都是零,除了相当简短的页眉和页脚部分。
我怀疑基本方法由于某种原因存在缺陷。当我尝试这个快照时,我得到了几个控制台日志:
2020-06-04 18:20:40.203669-0400 MetalTest[37773:1065740] [CAMetalLayerDrawable texture] should not be called after already presenting this drawable. Get a nextDrawable instead.
Input Metal texture was created with a device that does not match the current context device.
Input Metal texture was created with a device that does not match the current context device.
2020-06-04 18:20:40.247637-0400 MetalTest[37773:1065740] [plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x600000297260> F8BB1C28-BAE8-11D6-9C31-00039315CD46
2020-06-04 18:20:40.281161-0400 MetalTest[37773:1065740] HALC_ShellDriverPlugIn::Open: Can't get a pointer to the Open routine
第一个日志似乎表明我什至不允许在它首先呈现后从可绘制对象中取出纹理。那么......这样做的正确方法是什么?
更新:
请注意,我不喜欢saveImageTakingDrawable: 代码的后面部分。我很乐意写出 PNG 而不是 TIFF,如果有办法在不使用 CIImage、NSCIImageRep 或 NSImage 的情况下到达我要去的地方,那就更好了。我只想将drawable的纹理图像保存为PNG或TIFF,不知何故。
【问题讨论】:
-
是否允许我标记@KenThomases?我会尝试。 :->
-
是否可以使用此线程中的 NSTask 和 'screencapture' 代码:stackoverflow.com/questions/61731812/…
-
对于它的价值,标记不起作用,但我还是找到了它。 :)
标签: objective-c macos cocoa metal