iOS Core Graphics Как стереть рисунок
Я следую этому руководству для моего приложения каракули.
http://www.raywenderlich.com/18840/how-to-make-a-simple-drawing-app-with-uikit
его функция стирания использует рисунок белого цвета. Но я использую фоновое изображение, и когда я стираю, мне действительно нужно стереть.
я пытался
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
Но это не работает. Вот мой код:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
_mouseSwiped = NO;
UITouch *touch = [touches anyObject];
_lastPoint = [touch locationInView:self.tempImageView];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
_mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.tempImageView];
UIGraphicsBeginImageContext(self.tempImageView.frame.size);
[self.tempImageView.image drawInRect:CGRectMake(0, 0, self.tempImageView.frame.size.width, self.tempImageView.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), _width );
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), _red, _green, _blue, 1.0);
if (_isErasing) {
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
}
else {
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
}
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.tempImageView.image = UIGraphicsGetImageFromCurrentImageContext();
[self.tempImageView setAlpha:_alpha];
UIGraphicsEndImageContext();
_lastPoint = currentPoint;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
CGSize size = self.tempImageView.frame.size;
if(!_mouseSwiped) {
UIGraphicsBeginImageContext(self.tempImageView.frame.size);
[self.tempImageView.image drawInRect:CGRectMake(0, 0, size.width, size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), _width);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), _red, _green, _blue, _alpha);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
self.tempImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
UIGraphicsBeginImageContext(self.drawImageView.frame.size);
[self.drawImageView.image drawInRect:CGRectMake(0, 0, size.width, size.height) blendMode:kCGBlendModeNormal alpha:1.0];
if (_isErasing) {
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
}
[self.tempImageView.image drawInRect:CGRectMake(0, 0, self.tempImageView.frame.size.width, self.tempImageView.frame.size.height) blendMode:kCGBlendModeNormal alpha:_alpha];
self.drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
self.tempImageView.image = nil;
UIGraphicsEndImageContext();
}
5 ответов
Решил эту проблему путем замены tempImageView и drawImageView, когда касание началось, если оно стирает
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
_mouseSwiped = NO;
UITouch *touch = [touches anyObject];
_lastPoint = [touch locationInView:self.tempImageView];
if (_isErasing) {
self.tempImageView.image = self.drawImageView.image;
self.drawImageView.image = nil;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
_mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.tempImageView];
UIGraphicsBeginImageContext(self.tempImageView.frame.size);
[self.tempImageView.image drawInRect:CGRectMake(0, 0, self.tempImageView.frame.size.width, self.tempImageView.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), _width );
if (_isErasing) {
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
}
else {
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), _red, _green, _blue, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
}
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.tempImageView.image = UIGraphicsGetImageFromCurrentImageContext();
[self.tempImageView setAlpha:_alpha];
UIGraphicsEndImageContext();
_lastPoint = currentPoint;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
CGSize size = self.tempImageView.frame.size;
if(!_mouseSwiped) {
UIGraphicsBeginImageContext(self.tempImageView.frame.size);
[self.tempImageView.image drawInRect:CGRectMake(0, 0, size.width, size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), _width);
if (_isErasing) {
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
}
else {
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), _red, _green, _blue, _alpha);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
}
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), _lastPoint.x, _lastPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
self.tempImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
UIGraphicsBeginImageContext(self.drawImageView.frame.size);
[self.drawImageView.image drawInRect:CGRectMake(0, 0, size.width, size.height) blendMode:kCGBlendModeNormal alpha:1.0];
[self.tempImageView.image drawInRect:CGRectMake(0, 0, size.width, size.height) blendMode:kCGBlendModeNormal alpha:_alpha];
self.drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
self.tempImageView.image = nil;
UIGraphicsEndImageContext();
}
Если кто-то еще интересуется, вот как это работает для меня в Swift 3. Спасибо за помощь OMGPOP
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
swiped = false
hideAllButtons()
if let touch = touches.first {
lastPoint = touch.location(in: self.view)
}
if isErasing {
self.tempImageView.image = self.mainImageView.image
self.mainImageView.image = nil
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
swiped = true
if let touch = touches.first {
let currentPoint = touch.location(in: view)
drawLineFrom(fromPoint: lastPoint, toPoint: currentPoint)
lastPoint = currentPoint
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
showAllButtons()
if !swiped {
drawLineFrom(fromPoint: lastPoint, toPoint: lastPoint)
}
UIGraphicsBeginImageContext(mainImageView.frame.size)
mainImageView.image?.draw(in: CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height), blendMode: .normal, alpha: 1.0)
tempImageView.image?.draw(in: CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height), blendMode: .normal, alpha: opacity)
mainImageView.image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
tempImageView.image = nil
}
// Draws a line between two points on the view
func drawLineFrom(fromPoint: CGPoint, toPoint: CGPoint) {
UIGraphicsBeginImageContext(view.frame.size)
let context = UIGraphicsGetCurrentContext()
tempImageView.image?.draw(in: CGRect(x:0, y:0, width: view.frame.size.width, height: view.frame.size.height))
context?.move(to: fromPoint)
context?.addLine(to: toPoint)
context?.setLineCap(.round)
context?.setLineWidth(brushWidth)
if isErasing {
context?.setBlendMode(.clear)
} else {
context?.setStrokeColor(red: red, green: green, blue: blue, alpha: 1.0)
context?.setBlendMode(.normal)
}
context?.strokePath()
tempImageView.image = UIGraphicsGetImageFromCurrentImageContext()
tempImageView.alpha = opacity
UIGraphicsEndImageContext()
}
Вот как у меня работает ластик. В функции touchesEnded я рисую контекст с помощью следующего кода:
//draw the main image on the context
self.mainImage.image?.draw(in: CGRect(x:0, y:0, width:self.view.frame.size.width, height:self.view.frame.size.height), blendMode: .normal, alpha: 1.0)
if(erasing == false) {
//draw the current stroke normally since we're not erasing
self.tempDrawImage.image?.draw(in: CGRect(x:0, y:0, width:self.view.frame.size.width, height:self.view.frame.size.height), blendMode: .normal, alpha: opacity!)
} else {
//let's create a mask of what we would like to erase by using the destinationIn function which according to the docs is the following
//R = D*Sa
//Destination * Source_Alpha
self.tempDrawImage.image?.draw(in: CGRect(x:0, y:0, width:self.view.frame.size.width, height:self.view.frame.size.height), blendMode: .destinationIn, alpha: 1.0)
//Let's apply this mask to the current drawing using XOR blending which removes any drawing underneath our mask but leaves everything else alone
self.mainImage.image?.draw(in: CGRect(x:0, y:0, width:self.view.frame.size.width, height:self.view.frame.size.height), blendMode: .xor, alpha: 1.0)
}
//let's apply the changes we've made to our mainImage
self.mainImage.image = UIGraphicsGetImageFromCurrentImageContext();
self.tempDrawImage.image = nil;
Чтобы лучше понять, как это работает, вы можете закомментировать отдельные розыгрыши, чтобы посмотреть, как они выглядят.
Вы можете столкнуться с некоторыми проблемами с наложением, когда у вас на краю штрихов останутся маленькие кусочки. Чтобы удалить это при рисовании в режиме стирания, включите алиасинг для контекста:
let ctx = UIGraphicsGetCurrentContext()
ctx?.setShouldAntialias(false)
Я использую один вид «холста» и следующую функцию для достижения «эффекта стирания». Мой холст прозрачный, и под ним у меня есть фон UIImageView с фотографией, поверх которой я рисую линии. После того, как я закончил рисовать на своем холсте и пользователь хочет получить окончательный рисунок, я объединяю холст и фон. Это стирает ранее нарисованные линии:
private func drawStroke(context: CGContext?, touch: UITouch, width: CGFloat, color: UIColor) {
guard let context = context else { return }
let previousLocation = touch.previousLocation(in: self)
let location = touch.location(in: self)
context.setBlendMode(color == .clear ? .clear : .normal)
context.setLineWidth(width)
context.setStrokeColor(color.cgColor)
context.setLineCap(.round)
context.move(to: previousLocation)
context.addLine(to: location)
context.strokePath()
}
Почему вы не рисуете / рисуете в отдельном виде?
TopView = Paint + жест...., BottomView = фоновое изображение.
стереть цвет = ClearColor (прозрачный)
В конце концов, если вы хотите сохранить свою композицию, вам нужно объединить обе картинки.