iOS:在屏幕上捕获 CAEmitterLayer 粒子
Posted
技术标签:
【中文标题】iOS:在屏幕上捕获 CAEmitterLayer 粒子【英文标题】:iOS: capturing CAEmitterLayer particles on screen 【发布时间】:2012-08-01 15:12:43 【问题描述】:有没有办法在捕获 ios 设备屏幕时捕获 CAEmitterCells(使用 CAEmitterLayer 生成)?UIGetScreenImage() 有效,但由于它是私有方法,因此我不允许使用它.UIGraphicsBeginImageContext 似乎不起作用,只是从生成的图像中省略了粒子。
编辑: 这是我目前用来捕获视图的代码。实际上,我正在使用 aroth 在here 提供的代码录制一段 30 秒长的屏幕视频。它每秒记录 25 个自身的图像(它的一个 UIView 子类)及其子视图(在我们的例子中包括其层是 CAEmitterLayer 的 UIView),并使用 AVAssetWriter 来组成记录。 有点拗口,所以我就把相关的行放在这里: 我使用 XCode 中的 ARC 工具对代码进行了 ARC 编辑,因此代码在内存管理方面可能有点不同。
- (CGContextRef) createBitmapContextOfSize:(CGSize) size
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
int bitmapByteCount;
int bitmapBytesPerRow;
bitmapBytesPerRow = (size.width * 4);
bitmapByteCount = (bitmapBytesPerRow * size.height);
colorSpace = CGColorSpaceCreateDeviceRGB();
if (bitmapData != NULL)
free(bitmapData);
bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL)
fprintf (stderr, "Memory not allocated!");
return NULL;
context = CGBitmapContextCreate (bitmapData,
size.width,
size.height,
8, // bits per component
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaNoneSkipFirst);
CGContextSetAllowsAntialiasing(context,NO);
if (context== NULL)
free (bitmapData);
fprintf (stderr, "Context not created!");
return NULL;
CGColorSpaceRelease( colorSpace );
return context;
//static int frameCount = 0; //debugging
- (void) drawRect:(CGRect)rect
NSDate* start = [NSDate date];
CGContextRef context = [self createBitmapContextOfSize:self.frame.size];
//not sure why this is necessary...image renders upside-down and mirrored
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, self.frame.size.height);
CGContextConcatCTM(context, flipVertical);
[self.layer renderInContext:context];
CGImageRef cgImage = CGBitmapContextCreateImage(context);
UIImage* background = [UIImage imageWithCGImage: cgImage];
CGImageRelease(cgImage);
self.currentScreen = background;
//debugging
//if (frameCount < 40)
// NSString* filename = [NSString stringWithFormat:@"Documents/frame_%d.png", frameCount];
// NSString* pngPath = [NSHomeDirectory() stringByAppendingPathComponent:filename];
// [UIImagePNGRepresentation(self.currentScreen) writeToFile: pngPath atomically: YES];
// frameCount++;
//
//NOTE: to record a scrollview while it is scrolling you need to implement your UIScrollViewDelegate such that it calls
// 'setNeedsDisplay' on the ScreenCaptureView.
if (_recording)
float millisElapsed = [[NSDate date] timeIntervalSinceDate:startedAt] * 1000.0;
[self writeVideoFrameAtTime:CMTimeMake((int)millisElapsed, 1000)];
float processingSeconds = [[NSDate date] timeIntervalSinceDate:start];
float delayRemaining = (1.0 / self.frameRate) - processingSeconds;
CGContextRelease(context);
//redraw at the specified framerate
[self performSelector:@selector(setNeedsDisplay) withObject:nil afterDelay:delayRemaining > 0.0 ? delayRemaining : 0.01];
真的希望这会有所帮助。感谢您的支持!
【问题讨论】:
顺便说一句——你可以为CGBitmapContextCreate()
的data参数传递NULL,在这种情况下数据将由CG自动分配/释放跨度>
另外,我在这个 sn-p 中没有看到你的渲染代码?
你能解决这个问题吗?
【参考方案1】:
您是否尝试过使用-[CALayer renderInContext:]
?
【讨论】:
我认为他想要整个屏幕图像。啊,所以也许你的意思是渲染他想要的视图(可能包含 CAEmitterLayer)。这听起来很有希望。 进一步考虑,UIWindow
也是一个UIView
,因此有一个支持层——你也许可以渲染它。
我的想法是,如果他可以在一个图像中获得所有其他内容,他也许可以让 CAEmitterLayer 渲染为透明图像,它们将其覆盖在第一张图像上以获得合成。你必须跳过箍来渲染一个 CATiledLayer(问我是怎么知道的 :-)
@nielsbot 确实我做到了,我更新了我的问题,以便更清楚我的目标是什么。我确实尝试了 UIWindow 渲染,没有帮助。
@David H 您能否详细说明将 CAEmitterLayer 渲染为透明图像?具体怎么做呢? :) 顺便感谢您的想法!以上是关于iOS:在屏幕上捕获 CAEmitterLayer 粒子的主要内容,如果未能解决你的问题,请参考以下文章