CGContextClearRect not working smoothly in touchesMoved event in objective c - objective-c

I used this code, it works partly but image not crop properly
output seen like this
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:_img.superview];
UIGraphicsBeginImageContext(self.img.frame.size);
[_img.image drawInRect:CGRectMake(0, 0, _img.frame.size.width, _img.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 10);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextClearRect (UIGraphicsGetCurrentContext(), CGRectMake(currentPoint.x, currentPoint.y, 15, 15));
CGContextStrokePath(UIGraphicsGetCurrentContext());
_img.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}

I face same problem earlier then i tried below code and it's work for me
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.img_main];
// NSLog(#"Current ponint : %f,%f",currentPoint.x,currentPoint.y);
self.img_main.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
self.img_main.contentMode = UIViewContentModeScaleAspectFit;
UIGraphicsBeginImageContextWithOptions(self.img_main.bounds.size, NO, 0.0);
[_img_main.image drawInRect:CGRectMake(0,0, self.img_main.bounds.size.width,self.img_main.bounds.size.height)];
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
//For clearing Size and Mode
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush_Size );
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeDestinationOut);
//For Clearing Opacity
CGContextSetAlpha(UIGraphicsGetCurrentContext(), brush_opacity);
CGContextStrokePath(UIGraphicsGetCurrentContext());
_img_main.image = UIGraphicsGetImageFromCurrentImageContext();
CGContextFlush(UIGraphicsGetCurrentContext());
UIGraphicsEndImageContext();

Related

Core graphics drawing stretches when orientation changes

I am making an app that allows you to draw, and it is working well in portrait mode. However, when I rotate the screen, the drawn image becomes distorted (squashed and stretched). What would I need to do to make it retain the image's dimensions even though the UIImageView has changed its dimensions?
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = NO;
UITouch *touch = [touches anyObject];
lastPoint = [touch locationInView:self.view]; // first point touched
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view]; // second point touched (to be connected to first point)
// initialize the UIImageView that will be drawn on
UIGraphicsBeginImageContext(self.view.frame.size);
//UIGraphicsBeginImageContextWithOptions(self.view.frame.size, NO, 0.0); // use this instead of previous line to make smoother drawings
if (!erasing) // choose tempDrawImage if not erasing
[self.tempDrawImage.image drawInRect:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
else // choose mainImage if erasing
[self.mainImage.image drawInRect:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
// draw a line with CGContextAddLineToPoint from lastPoint to currentPoint
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
if (!erasing) { // color selected
// set brush size, opacity, and stroke color
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush );
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
// draw the path
CGContextStrokePath(UIGraphicsGetCurrentContext());
// draw on the tempDrawImage UIImageView
self.tempDrawImage.image = UIGraphicsGetImageFromCurrentImageContext();
[self.tempDrawImage setAlpha:opacity];
}
else { // eraser selected
// set brush size
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeClear);
// draw the path
CGContextStrokePath(UIGraphicsGetCurrentContext());
// draw on the tempDrawImage UIImageView
self.mainImage.image = UIGraphicsGetImageFromCurrentImageContext();
//[self.mainImage setAlpha:1.0];
}
UIGraphicsEndImageContext();
lastPoint = currentPoint;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// if screen was not swiped (i.e. the screen was only tapped), draw a single point
if(!mouseSwiped) {
UIGraphicsBeginImageContext(self.view.frame.size);
//UIGraphicsBeginImageContextWithOptions(self.view.frame.size, NO, 0.0); // use this instead of previous line to make smoother drawings
if (!erasing) {
[self.tempDrawImage.image drawInRect:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, opacity);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
self.tempDrawImage.image = UIGraphicsGetImageFromCurrentImageContext();
}
else {
[self.mainImage.image drawInRect:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeClear);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
self.mainImage.image = UIGraphicsGetImageFromCurrentImageContext();
}
UIGraphicsEndImageContext();
}
///////BRUSH STROKE IS DONE; BEGIN UIIMAGEVIEW MERGE//////
if (!erasing) {
// initialize mainImage (for merge)
UIGraphicsBeginImageContext(self.mainImage.frame.size);
// merge tempDrawImage with mainImage
[self.mainImage.image drawInRect:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height) blendMode:kCGBlendModeNormal alpha:1.0];
[self.tempDrawImage.image drawInRect:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height) blendMode:kCGBlendModeNormal alpha:opacity];
self.mainImage.image = UIGraphicsGetImageFromCurrentImageContext();
// clear tempDrawImage
self.tempDrawImage.image = nil;
}
UIGraphicsEndImageContext();
}

Rendering touchesMoved and Fingerpaint slow - iOS7

I have a app that allows fingerprinting. For this I use touchesBegan, touchesMoved, touchesEnded. On iOS6 it works smooth, when moving the finger, the line is painted. But on iOS7, only the first point from touchesBegan is painted and on touchesEnded, the line is painted.
Does anyone has a similar issue and/or solution.
(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:drawImage];
// currentPoint.y -= 20; // only for 'kCGLineCapRound'
UIGraphicsBeginImageContext(drawImage.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(), 30.0); // for size
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 1.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;
mouseMoved++;
if (mouseMoved == 10) {
mouseMoved = 0;
}
}
EDIT and solution!
Don't try to draw or call draw routines inside the touch delegates. The newer devices might support faster and higher resolution touch detection, and thus your app might be getting touch messages way to fast to draw in time, thus choking your UI run loop. Trying to update faster than 60 fps can do that.
Instead save your touch data points somewhere, and then draw later, for instance inside a polling animation loop callback (using CADisplayLink or a repeating timer), outside the touch handler, thus not choking the UI.
Comment from Lawrence Ingraham in Apple Developer Forum
Based on this, I have made the following changes:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
currentPoint = [touch locationInView:self.view];
[self performSelector:#selector(drawFinger) withObject:nil afterDelay:0.0];
}
- (void)drawFinger
{
UIGraphicsBeginImageContext(imgDibujo.frame.size);
[imgDibujo.image drawInRect:CGRectMake(0, 0, imgDibujo.frame.size.width, imgDibujo.frame.size.height)]; //originally self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound); //kCGLineCapSquare, kCGLineCapButt, kCGLineCapRound
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), delegate.lineAncho); // for size
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), delegate.colorR, delegate.colorG, delegate.colorB, delegate.colorS); //values for R, G, B, and Alpha
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
imgDibujo.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
}
It works now perfect on all iPad devices. Hope that this is helpfully for you.

ios map- couple of line while am draw a line

in my app i want to do while the user touch and move on the map i want to draw couple of line. how can i do this. am using this below code for draw a single line.
code:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:drawImage];
currentPoint.y -= 20;
mapView.scrollEnabled = NO;
lastpinpoint1.x = 170.000000;
lastpinpoint1.y = 327.000000;
UIGraphicsBeginImageContext(drawImage.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[imgMap drawInRect:CGRectMake(0, 0, drawImage.frame.size.width,drawImage.frame.size.height)];
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, 2.0);
// CGContextSetRGBStrokeColor(ctx, 0.0, 0.5, 0.6, 1.0);
CGContextSetStrokeColorWithColor(ctx, [[UIColor redColor] CGColor]);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, lastpinpoint.x, lastpinpoint.y);
CGContextMoveToPoint(ctx, lastpinpoint1.x, lastpinpoint1.y);
CGContextAddLineToPoint(ctx, currentPoint.x, currentPoint.y);
CGContextStrokePath(ctx);
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
In this above code with out this CGContextMoveToPoint(ctx, lastpinpoint1.x, lastpinpoint1.y); this line for draw a single line. but i have added this CGContextMoveToPoint(ctx, lastpinpoint1.x, lastpinpoint1.y); line for draw a second line. Now what am did wrong in this code. please help me. Issue is: while am move the finger on the map i want to draw a couple of line from different point to one current point. thanks for advance.
Try this answer
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
lastPoint = [touch locationInView:self];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self];
UIGraphicsBeginImageContext(self.frame.size);
[self.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0 , 0.0, 1.0, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.image = UIGraphicsGetImageFromCurrentImageContext();
[self setAlpha:1.0];
UIGraphicsEndImageContext();
UIGraphicsBeginImageContext(self.frame.size);
[self.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x+20, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x+20, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0 , 0.0, 1.0, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.image = UIGraphicsGetImageFromCurrentImageContext();
[self setAlpha:1.0];
UIGraphicsEndImageContext();
lastPoint = currentPoint;
}
Hope it helps!!!

setting bounds for imageview in a colouring book type app

I am making an app in which user can fill and stroke colours within an imageview with touches. But i want that when the user is filling a colour within an imageview bounds he/she should not spill colour out of that imageview if accidently touches outside it. I have implemented this till now. Any suggestions?
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = NO;
UITouch *touch = [touches anyObject];
lastPoint = [touch locationInView:self.view];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
// mouseSwiped = YES;
// UITouch *touch = [touches anyObject];
// CGPoint currentPoint = [touch locationInView:self.view];
//
// UIGraphicsBeginImageContext(self.view.frame.size);
// [self.tempDrawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
// CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
// CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
// CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
// CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush );
// CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
// CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
//
// CGContextStrokePath(UIGraphicsGetCurrentContext());
// self.tempDrawImage.image = UIGraphicsGetImageFromCurrentImageContext();
// [self.tempDrawImage setAlpha:opacity];
// UIGraphicsEndImageContext();
//
// lastPoint = currentPoint;
if(CGRectContainsPoint([testImage bounds], lastPoint))
{
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
UIGraphicsBeginImageContext(self.view.frame.size);
[self.testImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush );
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.testImage.image = UIGraphicsGetImageFromCurrentImageContext();
[self.testImage setAlpha:opacity];
UIGraphicsEndImageContext();
lastPoint = currentPoint;
}
else
{
// CGRectContainsPoint(testImage.frame, lastPoint) = ;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if(!mouseSwiped) {
UIGraphicsBeginImageContext(self.view.frame.size);
[self.testImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, opacity);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
self.tempDrawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
UIGraphicsBeginImageContext(self.mainImage.frame.size);
[self.mainImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) blendMode:kCGBlendModeNormal alpha:1.0];
[self.tempDrawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) blendMode:kCGBlendModeNormal alpha:opacity];
self.mainImage.image = UIGraphicsGetImageFromCurrentImageContext();
self.tempDrawImage.image = nil;
UIGraphicsEndImageContext();
}
What happens if your create a path over the borders of your view and set this as the clipping path of your view, I think nothing should draw outside that anymore once set.

Objective C: How do i smoothen the brush like a real brush?

I am building a brush app, it's almost finish and what i did was just a basic brush/drawing tool. I want to give it a more brush-like feel because in my current output it has angles and it doesn't look like a real brush ink.
here's my code:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
touchSwiped = YES;
UITouch *touch = [touches anyObject];
currentTouch = [touch locationInView:self.view];
currentTouch.y -= 20;
UIGraphicsBeginImageContext(self.view.frame.size);
[touchDraw.image drawInRect:CGRectMake(0, 0, touchDraw.frame.size.width, touchDraw.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 35.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), redAmt, blueAmt, greenAmt, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), endingPoint.x, endingPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentTouch.x, currentTouch.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
touchDraw.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
endingPoint = currentTouch;
touchMoved++;
if (touchMoved == 10) {
touchMoved = 0;
}
}
I don't know that you'll be able to use touch events for this without getting the angles you describe. The resolution of the events just aren't discrete enough.
OpenGL seems a better fit. Check out Apple's GLPaint sample code for an example.
Try using the quadCurve instead of addLineToPoint.. Quad Curve make a line in a two points that don't have an angle and make your line a curve..
CGPoint midPoint(CGPoint p1,CGPoint p2)
{
return CGPointMake ((p1.x + p2.x) * 0.5,(p1.y + p2.y) * 0.5);
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event//upon moving
{
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
previousPoint2 = previousPoint1;
previousPoint1 = currentTouch;
currentTouch = [touch locationInView:self.view];
CGPoint mid1 = midPoint(previousPoint2, previousPoint1);
CGPoint mid2 = midPoint(currentTouch, previousPoint1);
// here's your ticket to the finals..
CGContextMoveToPoint(context, mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(context, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
CGContextStrokePath(context)
}