Rendering touchesMoved and Fingerpaint slow - iOS7 - rendering

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.

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();
}

CGContextClearRect not working smoothly in touchesMoved event in 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();

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!!!

UIGraphicsGetImageFromCurrentImageContext crop to content and not to bounding box

I have an area where a user can add their signature to an app, to verify an order.
They sign with their touch.
The only thing is, the frame for the signature is large, and if the user were to make a signature very small, when I save the image, I'm left with a wealth of empty space around the image, which, when I add it to an email further down the process can look horrible.
Is there any way, using that I can crop the image to whatever the bounds of the actual content is, and not the bounds of the box itself?
I would imagine the process would involve somehow detecting the content within the space and drawing a CGRect to match it's bounds, before passing this CGRect back to the context? But I'm not sure how to go about doing this in any way shape or form, this really is my first time using CGContext and the Graphics Frameworks.
Here's my signature drawing code:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:signView];
//Define Properties
[drawView.image drawInRect:CGRectMake(0, 0, drawView.frame.size.width, drawView.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineJoin(UIGraphicsGetCurrentContext(), kCGLineJoinBevel);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
CGContextSetShouldAntialias(UIGraphicsGetCurrentContext(), true);
CGContextSetAllowsAntialiasing(UIGraphicsGetCurrentContext(), true);
//Start Path
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
//Save Path to Image
drawView.image = UIGraphicsGetImageFromCurrentImageContext();
lastPoint = currentPoint;
}
Thanks for your help if you can offer it.
You can do this with by tracking the min and max touch values.
For example, make some min/max ivars
#interface ViewController () {
CGFloat touchRectMinX_;
CGFloat touchRectMinY_;
CGFloat touchRectMaxX_;
CGFloat touchRectMaxY_;
UIView *demoView_;
}
#end
Heres a demo rect
- (void)viewDidLoad {
[super viewDidLoad];
demoView_ = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
demoView_.backgroundColor = [UIColor redColor];
[self.view addSubview:demoView_];
}
Set them up with impossible values. You'll want to do this for each signature not each stroke, but how you do this is up to you. I suggest a reset on 'clear', assuming you have a clear button.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
touchRectMinX_ = CGFLOAT_MAX;
touchRectMinY_ = CGFLOAT_MAX;
touchRectMaxX_ = CGFLOAT_MIN;
touchRectMaxY_ = CGFLOAT_MIN;
}
Now record the changes
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
touchRectMinX_ = MIN(touchRectMinX_, currentPoint.x);
touchRectMinY_ = MIN(touchRectMinY_, currentPoint.y);
touchRectMaxX_ = MAX(touchRectMaxX_, currentPoint.x);
touchRectMaxY_ = MAX(touchRectMaxY_, currentPoint.y);
// You can use them like this:
CGRect rect = CGRectMake(touchRectMinX_, touchRectMinY_, fabs(touchRectMinX_ - touchRectMaxX_), fabs(touchRectMinY_ - touchRectMaxY_));
demoView_.frame = rect;
NSLog(#"Signature rect is: %#", NSStringFromCGRect(rect));
}
Hope this helps!

How can i create an eraser for this line, in Xcode?

How, i've this code. When the touch moved, the view adds a line.
Now, if i want to create an eraser for this line, how can i do?
Please, answer me early!
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:drawView];
UIGraphicsBeginImageContext(drawView.frame.size);
[drawView.image drawInRect:CGRectMake(0, 0, drawView.frame.size.width, drawView.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushDimension);
const CGFloat *components = CGColorGetComponents([brushColor CGColor]);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), components[0], components[1], components[2], components[3]);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
}
If you are looking for an erase function that the user can use touches to erase portion of the line instead of undo provide by RickyTheCoder, you have 2 options.
The first option is use the brush that has the same background color of
the background view so it perceive as line got erased while it
actually just got paint over with the color that is same as the background.
The second option is to use the brush with clear color and set the
blend mode to clear so it erase the line and the background view is still
visible.
if (isErase)
{
CGContextSetLineWidth(currentContext, 10);
CGContextSetStrokeColorWithColor(currentContext, [UIColor clearColor].CGColor);
CGContextSetFillColorWithColor(currentContext, [UIColor clearColor].CGColor);
CGContextSetBlendMode(currentContext, kCGBlendModeClear);
CGContextDrawPath(currentContext, kCGPathStroke);
}
i think this is what you are looking for:
http://soulwithmobiletechnology.blogspot.com/2011/06/redo-undo-in-paint-feature.html