保存 CGContextRef
我有一个绘图应用程序,我想在其中创建一个撤消方法。绘图发生在 TouchesMoved: 方法内。
我正在尝试创建一个 CGContextRef 并将其推送到堆栈或将其保存在稍后可以恢复的上下文属性中,但我没有任何运气。任何建议都会很棒。这就是我所拥有的...
UIImageView *drawingSurface;
CGContextRef undoContext;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[drawingSurface.image drawInRect:CGRectMake(0, 0, drawingSurface.image.size.width, drawingSurface.image.size.height)];
UIGraphicsPushContext(context);
// also tried but cant figure how to restore it
undoContext = context;
UIGraphicsEndImageContext();
}
然后我有一个由撤消按钮触发的方法...
- (IBAction)restoreUndoImage {
UIGraphicsBeginImageContext(self.view.frame.size);
UIGraphicsPopContext();
drawingSurface.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
当我运行这个方法时,我相信我的绘图表面被分配为零,因为它只是删除了图像中的所有内容。
我的猜测是我不能以这种方式使用 pop 和 push 。但我似乎无法弄清楚如何保存上下文然后将其推回到绘图表面上。嗯嗯。任何帮助都会……嗯……有帮助。提前致谢 -
并且,仅供参考,这是我正在做的绘制到屏幕上的操作,效果很好。这是我的 TouchesMoved 里面的:
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[drawingSurface.image drawInRect:CGRectMake(0, 0, drawingSurface.image.size.width, drawingSurface.image.size.height)];
CGContextSetLineCap(context, kCGLineCapRound); //kCGLineCapSquare, kCGLineCapButt, kCGLineCapRound
CGContextSetLineWidth(context, self.brush.size); // for size
CGContextSetStrokeColorWithColor (context,[currentColor CGColor]);
CGContextBeginPath(context);
CGContextMoveToPoint(context, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y);
CGContextStrokePath(context);
drawingSurface.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I have a drawing app in which I would like to create an undo method. The drawing takes place inside the TouchesMoved: method.
I am trying to create a CGContextRef and push it to the stack OR save it in a context property that can be restored later but am not having any luck. Any advice would be great. Here is what I have ...
UIImageView *drawingSurface;
CGContextRef undoContext;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[drawingSurface.image drawInRect:CGRectMake(0, 0, drawingSurface.image.size.width, drawingSurface.image.size.height)];
UIGraphicsPushContext(context);
// also tried but cant figure how to restore it
undoContext = context;
UIGraphicsEndImageContext();
}
Then I have a method triggered by my undo button ...
- (IBAction)restoreUndoImage {
UIGraphicsBeginImageContext(self.view.frame.size);
UIGraphicsPopContext();
drawingSurface.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
When I run this, I believe my drawingSurface is being assigned nil because it just erases everything in the image.
My guess is I can't use pop and push this way. But I can't seem to figure out how to just save the context and then push it back onto the drawingSurface. Hmmmm. Any help would be ... well ... helpfull. Thanks in advance -
And, just for reference, here is what I am doing to draw to the screen, which is working great. This is inside my TouchesMoved:
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[drawingSurface.image drawInRect:CGRectMake(0, 0, drawingSurface.image.size.width, drawingSurface.image.size.height)];
CGContextSetLineCap(context, kCGLineCapRound); //kCGLineCapSquare, kCGLineCapButt, kCGLineCapRound
CGContextSetLineWidth(context, self.brush.size); // for size
CGContextSetStrokeColorWithColor (context,[currentColor CGColor]);
CGContextBeginPath(context);
CGContextMoveToPoint(context, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y);
CGContextStrokePath(context);
drawingSurface.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为您处理问题的方式是错误的并且上下文令人困惑。
在即时模式 API 中,您可以通过推送/弹出保存对象的“状态”,而不是图形表示。状态由线宽、颜色和位置等内容组成。图形表示是绘制操作的结果(位图),通常是您不想保存的内容。
相反,尝试保存用于创建绘图的“信息”。
我最初的建议是将形状创建和绘画分离。在 OSX 上,您可以使用 NSBezierPath,但对于 iOS,我们必须使用点数组。
例如,给定这个协议:
您可以实现这些功能:
现在子类化您的视图(我在这里称之为我的 MyView)并实现如下所示的内容:
这里唯一需要注意的是 setNeedsDisplay 的性能不是很好。最好使用 setNeedsDisplayInRect:,请参阅我关于 一种确定“绘制”矩形的有效方法。
至于撤消?您的撤消操作只是从 allPaths 数组中弹出最后一个对象。这个练习我将留给你:)
希望这有帮助!
I think you're approaching the problem the wrong way and confusing contexts.
In an immediate mode API you save the 'state' of objects with push/pop, not the graphical representation. The state consists of things like line widths, colours and positions. The graphical representation is the result of a paint operation (a bitmap) and generally something you don't want to save.
Instead try to save 'information' you use to create the drawing.
My initial suggestion would be to decouple your shape creation and painting. On OSX you can use NSBezierPath, but for iOS we have to use an array of points.
For example given this protocol:
You can implement these functions:
Now subclass your view (I call mine MyView here) and implement something like this:
The only cavet here is that setNeedsDisplay isn't very performant. It's better to use setNeedsDisplayInRect:, see my last post regarding an efficient way of determining the 'drawn' rect.
As for undo? Your undo operation is merely popping the last object from the allPaths array. This exercise I'll leave you to :)
Hope this helps!