2011-01-06 2 views
1

Ниже приведен фрагмент кода. Я могу отменить в векторном чертеже, точно так же, как хранить точки и удалить самую высокую из измененного массива, а затем перерисовать. Однако он не работает должным образом в растровом чертеже.Как реализовать отмену в приложении для рисования

Если я использую UIGraphicsGetCurrentContext() в качестве ссылки на контекст, отмена работает хорошо. Но контекст 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

Вы, скорее всего, получите помощь, если нам не обязательно посетить таинственную ссылку. Приложите усилия как можно меньше. У меня есть вероятный ответ, но я не хочу рисковать после вашей ссылки. –

+0

@Matthew Извините за это. Я удалил ссылку и поместил краткое описание. Буду признателен, если вы дадите мне какие-нибудь намеки. – yongjoon

ответ

2

С растровой графикой вы изменяете пиксели на холсте каждый т ime, нет никаких объектов, как в векторном чертеже.

В результате единственное «состояние», которое у вас есть, - это сам холст. Чтобы разрешить отмену, вам действительно нужно сохранить копию холста перед каждым изменением. Перед внесением изменения вы скопируете старый контекст растрового изображения, а затем внесите изменения. Если пользователь хочет отменить, вы просто скопируете сохраненный контекст поверх обычного. Если вы хотите разрешить несколько отменить, вам придется сохранять несколько копий.

Очевидно, что это может стать интенсивным. Технически вам не нужно сохранять весь холст, только часть, которая имеет изменения на нем, с записью положения измененного раздела. Если изменения невелики, вы сэкономите немного памяти, но некоторые изменения могут повлиять на весь холст, а не на сохранение ничего.

Возможно, вы сохраните еще больше памяти с помощью алгоритмов, в которых хранятся измененные пиксели, но накладные расходы на обработку данных вряд ли стоят того.

0

Assumming вы храните изображения в объекте Image, создать стек:

Stack undoStack = ... Stack redoStack = ...

Высокое разрешение памяти

Как пользователь вносит изменения в изображение, вы можете сохранить следующее изображение (с изменениями), а также следующее и другое и так далее. Когда пользователь хочет отменить , восстановление изображения, выскакивает из undoStack и толкая в стек повторе:

void undo(){ 
    redoStack.push(undoStack.pop()); 
} 

Чтобы повторить, использовать один и тот же процесс, но в обратном направлении.

Низкой память раствор

гармония такой же, как и выше, но теперь вместо того, чтобы хранить все изображение, вы можете XOR измененного изображения с предыдущим (или с исходным) и хранить только пиксели, которые изменились, и координаты, в которых происходят эти изменения.Вы даже можете рассмотреть упаковку четырехъядерного дерева этого нового изображения XORed, чтобы сохранить память, если изменения не велики.

Смежные вопросы