I am working on a painting application using Quartz 2D for ipad. Now I want to add an eraser option so that user can manually erase portion of his drawn line with touch.I have also background image. Can anyone please help?
yes this is work well in my app ;-)
firstly you add this code in touch began
UITouch *touch = [touches anyObject];
lastPoint = [touch locationInView:imgview];
UIGraphicsBeginImageContext(imgview.frame.size);
[imgview.image drawInRect:CGRectMake(0, 0, imgview.frame.size.width, imgview.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), lineWidth);
CGContextSetStrokeColorWithColor(UIGraphicsGetCurrentContext(), [UIColor colorWithPatternImage:img].CGColor);
CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), [UIColor clearColor].CGColor);
CGContextSetShouldAntialias(UIGraphicsGetCurrentContext(), YES);
CGContextBeginPath(UIGraphicsGetCurrentContext());
here img is ur background image then on move touch you simple write the line stroke code that code is this
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:imgview];
NSLog(#"asdasdas");
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
imgview.image = UIGraphicsGetImageFromCurrentImageContext();
lastPoint = currentPoint;
then you see the final result is produce ;-)
if(erase)
{
UITouch *touch = [touches anyObject];
CGPoint currentTouch = [touch locationInView:extraImageVw];
CGFloat brushSize;
if (isEraser)
{
brushSize=25.0;
}
else
{
brushSize=25.0;
}
CGColorRef strokeColor = [UIColor whiteColor].CGColor;
UIGraphicsBeginImageContext(extraImageVw.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[extraImageVw.image drawInRect:CGRectMake(0, 0, extraImageVw.frame.size.width, extraImageVw.frame.size.height)];
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, brushSize);
if (isEraser) {
CGContextSetStrokeColorWithColor(UIGraphicsGetCurrentContext(), [UIColor colorWithPatternImage:[UIImage imageWithContentsOfFile:fullPathToFile]].CGColor);
}
else
{
CGContextSetStrokeColorWithColor(context, strokeColor);
CGContextSetBlendMode(context, kCGBlendModeClear);
}
CGContextSaveGState(UIGraphicsGetCurrentContext());
CGContextBeginPath(context);
CGContextMoveToPoint(context, Lastpoint.x, Lastpoint.y);
CGContextAddLineToPoint(context, currentTouch.x, currentTouch.y);
CGContextStrokePath(context);
extraImageVw.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Lastpoint = [touch locationInView:extraImageVw];
}
Related
I am having an app in which I am doing some sketching on a view.
So far, it was working fine until I installed ios7.
My app uses touches moved method for recognizing the change of a movement. But when I draw a line, touches method gets called but line doesn't get updated until I touch ends in ios7.
So there is a slight lag in drawing.
It works fine on ios6 and on ios7 simulator but when i test it on a real ios7 device, there is a lag in drawing algorithm.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (!isImageSelection) {
mouseSwiped = NO;
UITouch *touch = [touches anyObject];
if ( [touch view] != baseview) {
lastPoint2 = [touch locationInView:self.viewDrawing2];
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (!isImageSelection) {
// NSLog(#"in image selection==%d touch moved ",isImageSelection );
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
// if (([touch view] != btnInkColor) || ([touch view] != btnPenSize) || ([touch view] != baseview)) {
if ( [touch view] != baseview) {
CGPoint currentPoint = [touch locationInView:self.viewDrawing];
if(isEraser) {
// [[NSUserDefaults standardUserDefaults] floatForKey:#"strokeValue"];
UIGraphicsBeginImageContext(self.viewDrawing.frame.size);
[imgDrawing.image drawInRect:CGRectMake(0, 0, self.viewDrawing.frame.size.width, self.viewDrawing.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), stroke);
//uncommented by prerak
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
imgDrawing.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
} else {
float strokeT= [[NSUserDefaults standardUserDefaults] floatForKey:#"strokeValue"];
// NSLog(#"strokeT=%f",strokeT);
UIGraphicsBeginImageContext(self.viewDrawing.frame.size);
[imgDrawing.image drawInRect:CGRectMake(0, 0, self.viewDrawing.frame.size.width, self.viewDrawing.frame.size.height)];
// NSLog(#"STROKE %f",stroke);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), strokeT);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeCopy);
float redT=[[NSUserDefaults standardUserDefaults] floatForKey:#"redvalue"];
float greenT= [[NSUserDefaults standardUserDefaults] floatForKey:#"greenvalue"];
float blueT= [[NSUserDefaults standardUserDefaults] floatForKey:#"bluevalue"];
// NSLog(#"red=%f",redT);
// NSLog(#"green=%f",greenT);
// NSLog(#"blue=%f",blueT);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), redT, greenT, blueT, 1.0);
CGContextSetRGBFillColor(UIGraphicsGetCurrentContext(), redT, greenT, blueT, 1.0);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineJoin(UIGraphicsGetCurrentContext(), kCGLineJoinRound);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
imgDrawing.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
lastPoint = currentPoint;
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
//if (([touch view] != btnInkColor) || ([touch view] != btnPenSize) || ([touch view] != baseview)) {
if ( [touch view] != baseview) {
if (!isImageSelection) {
if(!mouseSwiped) {
if (isEraser) {
UIGraphicsBeginImageContext(self.viewDrawing.frame.size);
[imgDrawing.image drawInRect:CGRectMake(0, 0, self.viewDrawing.frame.size.width, self.viewDrawing.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), stroke);
// CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
imgDrawing.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
} else {
UIGraphicsBeginImageContext(self.viewDrawing.frame.size);
[imgDrawing.image drawInRect:CGRectMake(0, 0, self.viewDrawing.frame.size.width, self.viewDrawing.frame.size.height)];
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), stroke);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeCopy);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextSetRGBFillColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineJoin(UIGraphicsGetCurrentContext(), kCGLineJoinRound);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
imgDrawing.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
}
}
}
}
}
How can i solve this?
To find a instant solution, Replace this line
mainImage.image = UIGraphicsGetImageFromContext(UIGraphicsGetCurrentContext());
with
[mainImage performSelectorInBackground:#selector(setImage:) withObject:UIGraphicsGetImageFromCurrentImageContext()];
If you need an elaborate and accurate solution try to replace the MoveTo with CGMutablepath .
Hope this helps.
we have solved this problem using dispatch_async(dispatch_get_main_queue(), ^{)}; block in touchMoved method like this :
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
dispatch_async(dispatch_get_main_queue(), ^{
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
if(touch.view==self.vwSwipePage)
{
return;
}
if(flagIsEraser)
{
CGPoint currentPoint;
if(flagActiveViewPage)
{
currentPoint = [touch locationInView:self.mainImage];
UIGraphicsBeginImageContext(self.mainImage.frame.size);
[self.mainImage.image drawInRect:CGRectMake(0, 0, self.mainImage.frame.size.width, self.mainImage.frame.size.height)];
}
else
{
currentPoint = [touch locationInView:self.mainImage1];
UIGraphicsBeginImageContext(self.mainImage1.frame.size);
[self.mainImage1.image drawInRect:CGRectMake(0, 0, self.mainImage1.frame.size.width, self.mainImage1.frame.size.height)];
}
//clear using circle brush........
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context,20);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextSetStrokeColorWithColor(context, [[UIColor clearColor] CGColor]);
CGContextBeginPath(context);
CGContextMoveToPoint(context, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y);
CGContextStrokePath(context);
CGContextFlush(context);
if(flagActiveViewPage)
self.mainImage.image = UIGraphicsGetImageFromCurrentImageContext();
else
self.mainImage1.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
}
});
}
May this will Help u to solve ur problem.
Thanks
Here's listed same code with same problem on ios7 https://stackoverflow.com/questions/18198129/ios-7-making-my-apps-drawing-algorithm-lag people suggest moving drawing logic into drawRect:
I am new to iPhone development,
I am making an application in which i am trying to make a line that is straight so that it doesn't has any irregular curves it must be smooth
I have used core graphics but it doesn't seem to be working.
Screen shot
I Just want to make these lines drawn in red color with UITouch to be straight.
Should I go for openGl?
If yes, how can i implement.
drawImage = [[UIImageView alloc] initWithImage:nil];
drawImage.frame = viewField.frame;
[self.view addSubview:drawImage];
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = NO;
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 2) {
drawImage.image = nil;
return;
}
lastPoint = [touch locationInView:viewField];
//lastPoint.y = 20;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:viewField];
//currentPoint.y -= 20; // only for 'kCGLineCapRound'
UIGraphicsBeginImageContext(viewField.frame.size);
//Albert Renshaw - Apps4Life
[drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width, drawImage.frame.size.height)]; //originally self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound); //kCGLineCapSquare, kCGLineCapButt, kCGLineCapRound
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0); // for size
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0); //values for R, G, B, and Alpha
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 2) {
drawImage.image = nil;
return;
}
if(!mouseSwiped) {
//if color == green
UIGraphicsBeginImageContext(viewField.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width, drawImage.frame.size.height)]; //originally self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound); //kCGLineCapSquare, kCGLineCapButt, kCGLineCapRound
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
}
Thanks in Advance !
Judging by the image you posted, I suggest you change your approach.
Start drawing by double clicking.
Then tap (= touchesStarted and touchesEnded, not touchesMoved) on every single edge point in your polygon.
Draw a straight line between those points as you go along.
End the polygon by Double Clicking.
You could decide to close you path automatically if the end point is close enough to the start point.
Actually i got few samples for drawing image through free hand and i integrated as well in my application.I need additional functionalities such as undo/redo.How can i achieve this?Need help on this..I used following code.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
currentPoint.y -= 20;
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 10.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
mouseMoved++;
if (mouseMoved == 10) {
mouseMoved = 0;
}
}
CGMutablePathRef path;
path = CGPathCreateMutable();
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGPathMoveToPoint(path, NULL, previousPoint.x, previousPoint.y);
CGPathAddLineToPoint(path, NULL, lastPoint.x, lastPoint.y);
CGContextAddPath(context, path);
CGContextSetLineWidth(context, 10.0);
[[UIColor greenColor] setStroke];
CGContextDrawPath(context,kCGPathFillStroke);
}
Now you can perform Undo/Redo by path's index.
You can try storing all paths in an array.
When you draw a new one, add it last and draw it, when you delete - remove the last and redraw all. Keep removed in another array so you can redo actions, clear the redo array when a new path is added to the paths array.
That's the most straight-forward method I can think of.
I already tried kCGBlendModeXOR but it turn black after the transparency.
Here my code that i done , but it not what I want.
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
CGPoint lastPoint = [touch locationInView: [UIApplication sharedApplication].keyWindow];
UIGraphicsBeginImageContext(self.view.frame.size);
CGRect rect = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
[imageView_skype.image drawInRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, 36.0);
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextSetAlpha(context,0.10);
CGContextSetBlendMode(context, kCGBlendModeXOR);
CGContextBeginPath(context);
CGContextMoveToPoint(context, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y);
CGContextStrokePath(context);
imageView_skype.image = UIGraphicsGetImageFromCurrentImageContext();
your can use mask to do this
http://developer.apple.com/library/ios/#documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_images/dq_images.html
in your touches moved event draw a mask image only black and white
and mask your original image
I want to be able to save a CGContext into my NSUndoManager using these methods
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
currentPoint.x = currentPoint.x;
currentPoint.y = currentPoint.y;
mouseSwiped = YES;
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextSetShouldAntialias(UIGraphicsGetCurrentContext(), YES);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushSizeVal);
CGContextSetAlpha(UIGraphicsGetCurrentContext(), drawingColorAlpha);
CGContextSaveGState(UIGraphicsGetCurrentContext()); //Probably right here
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(),
drawingColorRed,
drawingColorGreen,
drawingColorBlue,
drawingColorAlpha);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(),
lastPoint.x,
lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(),
currentPoint.x,
currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext(); //drawImage is the UIImageView that I am drawing my context to
NSLog(#"current point x: %d current point y: %d",currentPoint.x, currentPoint.y); //Used for my purposes
lastPoint = currentPoint;
mouseMoved++;
and
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!optionsDisplayerVisible && canDraw)
{
if(!mouseSwiped)
{
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextSetShouldAntialias(UIGraphicsGetCurrentContext(), YES);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushSizeVal);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(),
drawingColorRed,
drawingColorGreen,
drawingColorBlue,
drawingColorAlpha);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext(); //drawImage is the UIImageView that I am drawing to
UIGraphicsEndImageContext();
}
}
}
By the way if you want to know I have my NSUndoManager named undoDrawing
I don't believe you want to save the CGContext, since it's part of a stack that will not be valid when you need it later. Instead, just save the image itself. First, don't create the context over the whole frame. You just need the rectangle between currentPoint and lastPoint. Then, before you start drawing, grab the image from the current context (UIGraphicsGetImageFromCurrentImageContext ()) and save that off along with the frame to the NSUndoManager.
If you're unfamiliar with optimizing your drawing just to the dirty rectangle, start with the simpler version of this and just save the entire image to the undomanager before drawing on it.