使用coregraphics,通过触摸擦除和删除UIImageVIew中的图像

我的问题和这里提到的一样。 我也在我的应用程序中使用两个图像,我需要的是通过触摸删除顶部图像。 然后通过触摸删除(如果需要)删除的部分。 我正在使用以下代码来擦除顶部图像。 这种方法也有问题。 这是图像很大,我使用Aspect Fit内容模式来正确显示它们。 当我触摸屏幕时,它在angular落而不是触摸的地方。 我认为接触点计算需要一些修复。 任何帮助将不胜感激。

第二个问题是如何通过触摸来删除已擦除的部分?

UIGraphicsBeginImageContext(self.imgTop.image.size); [self.imgTop.image drawInRect:CGRectMake(0, 0, self.imgTop.image.size.width, self.imgTop.image.size.height)]; self.frame.size.width, self.frame.size.height)]; CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound); GContextSetLineWidth(UIGraphicsGetCurrentContext(), pinSize); CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0, 0, 0, 1.0); CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeCopy); CGContextBeginPath(UIGraphicsGetCurrentContext()); CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y); CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y); CGContextStrokePath(UIGraphicsGetCurrentContext()); self.imgTop.contentMode = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); 

你的代码很模糊:你正在用imgTop创build一个上下文,然后与kCGBlendModeCopy混合黑色? 这会导致黑色被复制到imgTop上 。 我假设你想设置图层的content属性呢?

无论如何,这个class级做你所需要的。 只有一些有趣的方法(他们在顶部),其他的只是属性或init...例程。

 @interface EraseImageView : UIView { CGContextRef context; CGRect contextBounds; } @property (nonatomic, retain) UIImage *backgroundImage; @property (nonatomic, retain) UIImage *foregroundImage; @property (nonatomic, assign) CGFloat touchWidth; @property (nonatomic, assign) BOOL touchRevealsImage; - (void)resetDrawing; @end @interface EraseImageView () - (void)createBitmapContext; - (void)drawImageScaled:(UIImage *)image; @end @implementation EraseImageView @synthesize touchRevealsImage=_touchRevealsImage, backgroundImage=_backgroundImage, foregroundImage=_foregroundImage, touchWidth=_touchWidth; #pragma mark - Main methods - - (void)createBitmapContext { // create a grayscale colorspace CGColorSpaceRef grayscale=CGColorSpaceCreateDeviceGray(); /* TO DO: instead of saving the bounds at the moment of creation, override setFrame:, create a new context with the right size, draw the previous on the new, and replace the old one with the new one. */ contextBounds=self.bounds; // create a new 8 bit grayscale bitmap with no alpha (the mask) context=CGBitmapContextCreate(NULL, (size_t)contextBounds.size.width, (size_t)contextBounds.size.height, 8, (size_t)contextBounds.size.width, grayscale, kCGImageAlphaNone); // make it white (touchRevealsImage==NO) CGFloat white[]={1., 1.}; CGContextSetFillColor(context, white); CGContextFillRect(context, contextBounds); // setup drawing for that context CGContextSetLineCap(context, kCGLineCapRound); CGContextSetLineJoin(context, kCGLineJoinRound); CGColorSpaceRelease(grayscale); } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch=(UITouch *)[touches anyObject]; // the new line that will be drawn CGPoint points[]={ [touch previousLocationInView:self], [touch locationInView:self] }; // setup width and color CGContextSetLineWidth(context, self.touchWidth); CGFloat color[]={(self.touchRevealsImage ? 1. : 0.), 1.}; CGContextSetStrokeColor(context, color); // stroke CGContextStrokeLineSegments(context, points, 2); [self setNeedsDisplay]; } - (void)drawRect:(CGRect)rect { if (self.foregroundImage==nil || self.backgroundImage==nil) return; // draw background image [self drawImageScaled:self.backgroundImage]; // create an image mask from the context CGImageRef mask=CGBitmapContextCreateImage(context); // set the current clipping mask to the image CGContextRef ctx=UIGraphicsGetCurrentContext(); CGContextSaveGState(ctx); CGContextClipToMask(ctx, contextBounds, mask); // now draw image (with mask) [self drawImageScaled:self.foregroundImage]; CGContextRestoreGState(ctx); CGImageRelease(mask); } - (void)resetDrawing { // draw black or white CGFloat color[]={(self.touchRevealsImage ? 0. : 1.), 1.}; CGContextSetFillColor(context, color); CGContextFillRect(context, contextBounds); [self setNeedsDisplay]; } #pragma mark - Helper methods - - (void)drawImageScaled:(UIImage *)image { // just draws the image scaled down and centered CGFloat selfRatio=self.frame.size.width/self.frame.size.height; CGFloat imgRatio=image.size.width/image.size.height; CGRect rect={0.,0.,0.,0.}; if (selfRatio>imgRatio) { // view is wider than img rect.size.height=self.frame.size.height; rect.size.width=imgRatio*rect.size.height; } else { // img is wider than view rect.size.width=self.frame.size.width; rect.size.height=rect.size.width/imgRatio; } rect.origin.x=.5*(self.frame.size.width-rect.size.width); rect.origin.y=.5*(self.frame.size.height-rect.size.height); [image drawInRect:rect]; } #pragma mark - Initialization and properties - - (id)initWithCoder:(NSCoder *)aDecoder { if ((self=[super initWithCoder:aDecoder])) { [self createBitmapContext]; _touchWidth=10.; } return self; } - (id)initWithFrame:(CGRect)frame { if ((self=[super initWithFrame:frame])) { [self createBitmapContext]; _touchWidth=10.; } return self; } - (void)dealloc { CGContextRelease(context); [super dealloc]; } - (void)setBackgroundImage:(UIImage *)value { if (value!=_backgroundImage) { [_backgroundImage release]; _backgroundImage=[value retain]; [self setNeedsDisplay]; } } - (void)setForegroundImage:(UIImage *)value { if (value!=_foregroundImage) { [_foregroundImage release]; _foregroundImage=[value retain]; [self setNeedsDisplay]; } } - (void)setTouchRevealsImage:(BOOL)value { if (value!=_touchRevealsImage) { _touchRevealsImage=value; [self setNeedsDisplay]; } } @end 

一些说明:

  • 这个class级保留你需要的两个图像。 它有一个touchRevealsImage属性来设置模式为绘制或擦除,并且可以设置线条的宽度。

  • 在初始化时,它创build了一个CGBitmapContextRef ,灰度, CGBitmapContextRef ,没有alpha,具有相同大小的视图。 此上下文用于存储将应用于前景图像的遮罩。

  • 每次在屏幕上移动手指时, CGBitmapContextRef使用CoreGraphics在CGBitmapContextRef上画一条线,白色表示图像,黑色表示隐藏。 通过这种方式我们正在存储ab / w绘图。

  • drawRect:例程简单地绘制背景,然后从CGBitmapContextRef创build一个CGImageRef并将其作为一个掩码应用到当前上下文中。 然后绘制前景图像。 绘制它使用的图像- (void)drawImageScaled:(UIImage *)image ,它只是绘制缩放和居中的图像。

  • 如果您打算调整视图大小,您应该实现一个方法来复制或重新创build新的大小的面具,覆盖- (void)setFrame:(CGRect)frame

  • - (void)reset方法简单地清除掩码。

  • 即使位图上下文没有任何alpha通道,所使用的灰度色彩空间也是 alpha:这就是为什么每次设置一个颜色时,我都必须指定两个分量。

使用<code> EraseImageView </ code>类的示例应用程序