以下是绘画的代码片段。我可以在矢量绘图中撤消,就像存储点一样,从可变数组中删除最高的一个然后重绘。但是,它在光栅绘图中无法正常工作。
如果我使用UIGraphicsGetCurrentContext()作为上下文引用,则undo工作正常。但是,当发出撤消操作时,CGBitmapContextCreate()的上下文不会出现。
- (id)initWithFrame:(CGRect)frame {
objArray = [[NSMutableArray alloc] init];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
canvas = CGBitmapContextCreate(NULL, drawImage.frame.size.width, drawImage.frame.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGImageRef imgRef = CGBitmapContextCreateImage(canvas);
CGRect r = self.bounds;
CGContextDrawImage(context, CGRectMake(0, 0, r.size.width, r.size.height), imgRef);
if(ok) {
for (int i = 0; i < [objArray count]; i++) {
CGPoint point = [[[objArray objectAtIndex: i] objectAtIndex:0] CGPointValue];
CGContextMoveToPoint(canvas, point.x, point.y);
for (int j = 0; j < [[objArray objectAtIndex:i] count]; j++) {
point = [[[objArray objectAtIndex: i] objectAtIndex:j] CGPointValue];
CGContextAddLineToPoint(canvas, point.x, point.y);
CGContextStrokePath(**canvas**);
CGContextMoveToPoint(**canvas**, point.x, point.y);
}
}
}
CGImageRelease(imgRef);
}
- (void)undo:(id) sender {
NSLog(@"click");
if([objArray count] > 0)
[objArray removeLastObject];
ok = YES;
[self setNeedsDisplay];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSMutableArray *points = [NSMutableArray array];
UITouch *touch = nil;
if (touchPoint) {
touch = [touches member:touchPoint];
}
end = [touch locationInView:self];
[points addObject:[NSValue valueWithCGPoint:start]];
[points addObject:[NSValue valueWithCGPoint:end]];
[objArray addObject:points];
CGContextMoveToPoint(**canvas**, start.x, start.y);
CGContextAddLineToPoint(**canvas**, end.x, end.y);
CGContextSetLineCap(**canvas**, kCGLineCapRound);
CGContextSetLineWidth(**canvas**, 40.0);
CGContextStrokePath(**canvas**);
start = end;
[self setNeedsDisplay];
}
答案 0 :(得分:2)
使用光栅绘制每次都会更改画布中的像素,没有像矢量绘图中那样的对象。
因此,你拥有的唯一“状态”就是画布本身。为了允许撤消,您实际上需要在每次更改之前保存画布的副本。在进行更改之前,您将复制旧的位图上下文,然后进行更改。如果用户选择撤消,那么您只需将保存的上下文复制到正常上下文中。如果要允许多个撤消,则必须保存多个副本。
显然,这可能会占用大量内存。从技术上讲,你实际上并不需要保存整个画布,只需要保存整个画布的部分,并记录已更改部分的位置。如果更改很小,那么你将节省相当多的内存,但是一些更改会影响整个画布,而不会保存任何内容。
使用存储更改像素的算法可以节省更多内存,但处理开销可能不值得。
答案 1 :(得分:0)
假设您将图像存储在Image对象中,请创建一个堆栈:
堆栈undoStack = ... Stack redoStack = ...
高内存解决方案
当用户对图像进行更改时,您可以存储下一个图像(w更改),下一个图像和下一个图像,依此类推。当用户想要撤消时,您可以通过从undoStack弹出并推送到重做堆栈来恢复图像:
void undo(){
redoStack.push(undoStack.pop());
}
要重做,请使用相同的过程,但要向后。
低内存解决方案
焦点与上面相同,但现在不是存储整个图像,而是可以将修改后的图像与前一个图像(或原始图像)进行异或,并仅存储已更改的像素和这些像素的坐标发生了变化。如果更改不是很好,您甚至可以考虑对这个新的XORed图像进行四叉树打包以节省内存。