我有一个小应用程序,允许用户用手指在屏幕上绘图。
通过创建UIImageView
和各种CGContextRef
函数,用户可以在其中绘制CG draw
。我主要使用函数CGContextAddLineToPoint
现在我的问题是:
用户可以绘制各种颜色的线条。我想让他能够使用"rubber"
工具用手指删除到目前为止绘制的图像的某些部分。我最初通过使用白色作为笔画(使用CGContextSetRGBStrokeColor
函数设置)来做到这一点,但它没有用完...因为我后来发现UIImage
UIImageView
实际上有一个透明的背景,而不是白色...所以我最终会得到一个带有白线的透明图像!
无论如何设置"transparent"
笔划颜色还是有其他方法可以清除用户手指下CGContextRef
的内容,当他移动它时?
感谢
答案 0 :(得分:57)
这样可以解决问题:
CGContextSetBlendMode(context, kCGBlendModeClear)
答案 1 :(得分:6)
我最终使用了Bresenham的线算法(当我不得不编写自己的图形例程时,回到过去的日子)......
- (void) contextEraseLine:(CGContextRef) ctx from:(CGPoint)startPoint to:(CGPoint) endPoint withThickness:(int)thickness {
int x, cx, deltax, xstep,
y, cy, deltay, ystep,
error, st, dupe;
int x0, y0, x1, y1;
x0 = startPoint.x;
y0 = startPoint.y;
x1 = endPoint.x;
y1 = endPoint.y;
// find largest delta for pixel steps
st = (abs(y1 - y0) > abs(x1 - x0));
// if deltay > deltax then swap x,y
if (st) {
(x0 ^= y0); (y0 ^= x0); (x0 ^= y0); // swap(x0, y0);
(x1 ^= y1); (y1 ^= x1); (x1 ^= y1); // swap(x1, y1);
}
deltax = abs(x1 - x0);
deltay = abs(y1 - y0);
error = (deltax / 2);
y = y0;
if (x0 > x1) { xstep = -1; }
else { xstep = 1; }
if (y0 > y1) { ystep = -1; }
else { ystep = 1; }
for ((x = x0); (x != (x1 + xstep)); (x += xstep))
{
(cx = x); (cy = y); // copy of x, copy of y
// if x,y swapped above, swap them back now
if (st) { (cx ^= cy); (cy ^= cx); (cx ^= cy); }
(dupe = 0); // initialize no dupe
if(!dupe) { // if not a dupe, write it out
//NSLog(@"(%2d, %2d)", cx, cy);
CGContextClearRect(ctx, CGRectMake(cx, cy, thickness, thickness));
}
(error -= deltay); // converge toward end of line
if (error < 0) { // not done yet
(y += ystep);
(error += deltax);
}
}
}
唷!要创建(有点)笨重的橡皮擦线还有很长的路要走。
要使用它,请执行以下操作:
- (void)eraseStart {
// erase lines
UIGraphicsBeginImageContext(drawingBoard.size);
ctx = UIGraphicsGetCurrentContext();
CGContextDrawImage(ctx,CGRectMake(0,0,drawingBoard.size.width, drawingBoard.size.height),[drawingBoard CGImage]);
}
- (void)eraseEnd {
drawingBoard = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[drawingView removeFromSuperview];
[drawingView release];
drawingView = [[UIImageView alloc] initWithImage:drawingBoard];
drawingView.frame = CGRectMake(intEtchX, intEtchY, intEtchWidth, intEtchHeight);
[self.view addSubview:drawingView];
}
这假设您已经创建了一个drawingView(UIImageView)和drawingBoard(UIImage)。
然后,要删除一行,只需执行以下操作:
CGContextRef ctx = UIGraphicsGetCurrentContext();
[self eraseStart];
[self contextEraseLine:ctx from:CGPointMake (x1, y1) to:CGPointMake (x2, y2) withThickness:10];
[self eraseEnd];
(用适当的值替换x1,y1,x2和y2)......
答案 2 :(得分:1)
我尝试过使用:
CGContextSetStrokeColorWithColor (myContext, [[UIColor clearColor] CGColor]);
但这不起作用,因为它似乎在上下文中“绘制”了一个不可见的颜色(和不可见的颜色+它绘制的任何颜色=它所绘制的颜色)。
我找到的唯一解决方案(不是最优的)是:
CGContextClearRect (myContext, CGRectMake(x, y, width, height));
不幸的是,这意味着您必须追踪一系列的行并自己生成行...
答案 3 :(得分:0)
如果您想用触摸擦除图像,这是我的代码....不推荐使用的部分不起作用,但是速度稍慢。
func addNewPathToImage(){
print("Start erasing or not erasing")
UIGraphicsBeginImageContextWithOptions(TopImageUIImageView.bounds.size, false, UIScreen.main.scale) // or 0 for the scale
//My image is aspect fit so I need to get rect
let aspect = TopImageUIImageView.image!.size.width / TopImageUIImageView.image!.size.height
let viewRatio = TopImageUIImageView.bounds.size.width / TopImageUIImageView.bounds.size.height
if aspect < viewRatio {
let scale = TopImageUIImageView.bounds.size.height / TopImageUIImageView.image!.size.height
let width = scale * TopImageUIImageView.image!.size.width
let topLeftX = (TopImageUIImageView.bounds.size.width - width) * 0.5
rect = CGRect(x: topLeftX, y: 0, width: width, height: TopImageUIImageView.bounds.size.height)
}
else {
let scale = TopImageUIImageView.bounds.size.width / TopImageUIImageView.image!.size.width
let height = scale * TopImageUIImageView.image!.size.height
let topLeftY = (TopImageUIImageView.bounds.size.height - height) * 0.5
rect = CGRect(x: 0.0, y: topLeftY, width: TopImageUIImageView.bounds.size.width, height: height)
}
////
context = UIGraphicsGetCurrentContext()
TopImageUIImageView.image?.draw(in: rect)
context?.setLineCap(.round)
context?.setLineWidth(brushSize)
if isErasing == true {
context?.setShadow(offset: CGSize(width: 0, height: 0), blur: blurNumber)
context?.setStrokeColor(UIColor.white.cgColor)
context?.setBlendMode(.clear)
}else{
print("test the unerase image .... ?")
context?.setStrokeColor(UIColor.init(patternImage: topImage.af_imageAspectScaled(toFit: CGSize(width: TopImageUIImageView.bounds.size.width, height: TopImageUIImageView.bounds.size.height))).cgColor)
}
// I am using these because I am using touch to define what to erase
context?.move(to: CGPoint(x: lastTouch.x, y: lastTouch.y))
context?.addLine(to: CGPoint(x: currentTouch.x, y: currentTouch.y))
context?.strokePath()
context?.closePath() // when add this line or the "context?.beginPath" get ERROR CGContextClosePath: no current point.
print("close the path")
//get your image
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
TopImageUIImageView.image = image
}
答案 4 :(得分:-2)
//erase part
if(mouseSwiped)
{
//**************Working Code*************//
UIGraphicsBeginImageContext(frontImage.frame.size);
[frontImage.image drawInRect:CGRectMake(0, 0, frontImage.frame.size.width, frontImage.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(),kCGImageAlphaNone); //kCGImageAlphaPremultipliedLast);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 10);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1, 0, 0, 10);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextClearRect (UIGraphicsGetCurrentContext(), CGRectMake(lastPoint.x, lastPoint.y, 10, 10));
CGContextStrokePath(UIGraphicsGetCurrentContext());
frontImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
mouseMoved++;
if (mouseMoved == 10)
{
mouseMoved = 0;
}
}
答案 5 :(得分:-13)
UIColor *clearColor = [UIColor clearColor];