首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >保存CGContextRef

保存CGContextRef
EN

Stack Overflow用户
提问于 2010-08-03 04:30:36
回答 1查看 3.2K关注 0票数 6

我有一个绘图应用程序,其中我想创建一个撤消方法。绘图发生在TouchesMoved:方法内部。

我正在尝试创建一个CGContextRef并将其推送到堆栈中,或者将其保存在一个上下文属性中,该属性可以在以后恢复,但没有任何运气。任何建议都是很棒的。这是我的资料..。

代码语言:javascript
复制
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();
}

然后我有一个方法被我的撤销按钮触发...

代码语言:javascript
复制
- (IBAction)restoreUndoImage {
 UIGraphicsBeginImageContext(self.view.frame.size);
 UIGraphicsPopContext();
 drawingSurface.image = UIGraphicsGetImageFromCurrentImageContext();
 UIGraphicsEndImageContext();
}

当我运行这个命令时,我相信我的drawingSurface被分配了nil,因为它只是擦除了图像中的所有内容。

我猜我不能这样使用pop和push。但我似乎想不出如何保存上下文,然后将其推回到drawingSurface上。嗯。任何帮助都是...好吧..。帮上忙了。提前谢谢你-

而且,仅供参考,这是我正在做的绘制到屏幕上的工作,它工作得很好。这是在我的TouchesMoved中:

代码语言:javascript
复制
 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();
EN

回答 1

Stack Overflow用户

发布于 2012-04-25 22:16:55

我认为你处理这个问题的方式是错误的,并且混淆了上下文。

在即时模式API中,您可以使用push/pop保存对象的“状态”,而不是图形表示。状态由线条宽度、颜色和位置等组成。图形表示是绘制操作(位图)的结果,通常是您不想保存的结果。

取而代之的是,尝试保存你用来创建绘图的‘信息’。

我最初的建议是将你的形状创建和绘画分离。在OSX上,你可以使用NSBezierPath,但是对于iOS,我们必须使用一个点数组。

例如,给定以下协议:

代码语言:javascript
复制
// ViewController.h
@protocol DrawSourceProtocol <NSObject>
- (NSArray*)pathsToDraw;
@end

@interface ViewController : UIViewController<DrawSourceProtocol>
@end

您可以实现以下函数:

代码语言:javascript
复制
// ViewController.m
@interface ViewController () {
  NSMutableArray *currentPath;  
  NSMutableArray *allPaths;
  MyView *view_;
}
@end

...

- (void)viewDidLoad {
  [super viewDidLoad];
  currentPath = [[NSMutableArray alloc] init];
  allPaths = [[NSMutableArray alloc] init];    
  view_ = (MyView*)self.view;
  view_.delegate = self;
}

- (NSArray*)pathsToDraw {  
  // Return the currently draw path too
  if (currentPath && currentPath.count) {
    NSMutableArray *allPathsPlusCurrent = [[NSMutableArray alloc] initWithArray:allPaths];
    [allPathsPlusCurrent addObject:currentPath];
    return allPathsPlusCurrent;
  }  
  return allPaths;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
  currentPath = [[NSMutableArray alloc] init];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
  // When a touch ends, save the current path
  [allPaths addObject:currentPath];
  currentPath = [[NSMutableArray alloc] init];
  [view_ setNeedsDisplay];    
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
  UITouch *touch = [touches anyObject];   
  CGPoint currentPoint = [touch locationInView:self.view];

  // We store the point with the help of NSValue
  [currentPath addObject:[NSValue valueWithCGPoint:currentPoint]];  

  // Update the view
  [view_ setNeedsDisplay];  
}

现在子类化你的视图(这里我称之为MyView ),并实现类似这样的东西:

代码语言:javascript
复制
// MyView.h
#import "ViewController.h"

@protocol DrawSourceProtocol;

@interface MyView : UIView {
   __weak id<DrawSourceProtocol> delegate_; 
}
@property (weak) id<DrawSourceProtocol> delegate;
@end

// MyView.m

@synthesize delegate = delegate_;

...

- (void)drawRect:(CGRect)rect { 
  NSLog(@"Drawing!");

  // Setup a context
  CGContextRef context = UIGraphicsGetCurrentContext();   
  CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
  CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
  CGContextSetLineWidth(context, 2.0);

  // Get the paths
  NSArray *paths = [delegate_ pathsToDraw];

  for (NSArray *aPath in paths) {
    BOOL firstPoint = TRUE;
    for (NSValue *pointValue in aPath) {
      CGPoint point = [pointValue CGPointValue];

      // Always move to the first point
      if (firstPoint) {
        CGContextMoveToPoint(context, point.x, point.y);
        firstPoint = FALSE;
        continue;
      }

      // Draw a point
      CGContextAddLineToPoint(context, point.x, point.y);
    }
  }

  // Stroke!
  CGContextStrokePath(context);
}

这里唯一的缺点是setNeedsDisplay的性能不是很好。最好使用setNeedsDisplayInRect:,请参阅我上一篇关于an efficient way of determining the 'drawn' rect的文章。

至于撤销?撤消操作只是从allPaths数组中弹出最后一个对象。在本练习中,我将留给您:)

希望这能有所帮助!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3391489

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档