How can I erase a line between two CGpoint? - ios

I am creating a line in ipad as user touch the screen and and drag the finger. Problem is line is creating on every point in by (touchMoved:) we we drag it. But in last it should only one not many. How can I erase or remove last line after created new one? Here is my code:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if(ArrowDraw==YES){
NSLog(#"ArrowDrawing");
if ([[event allTouches]count]==1){
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:FullImageView];
UIGraphicsBeginImageContext(self.view.frame.size);
[self.tempDrawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), firstPoint.x, firstPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 1 );
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.tempDrawImage.image = UIGraphicsGetImageFromCurrentImageContext();
[self.tempDrawImage setAlpha:opacity];
UIGraphicsEndImageContext();
//firstPoint = currentPoint;
NSLog(#"TouchMoving x=%f y=%f",firstPoint.x,firstPoint.y);
}
UIGraphicsBeginImageContext(self.FullImageView.frame.size);
[self.FullImageView.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.FullImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.tempDrawImage.hidden=YES;
}
}

The key is to not update the image, but rather just draw the arrow on top of the image. Then replace the arrow with another as the touchesMoved come in.
For example, I might use the QuartzCore.framework by adding it to your target's "Link Binary With Libraries" and add the following line to the start of your .m:
#import <QuartzCore/QuartzCore.h>
Then you can define a new ivar for your CAShapeLayer:
CAShapeLayer *shapeLayer;
Finally, then update your touchesMoved to something like:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (ArrowDraw==YES){
if ([[event allTouches]count]==1) {
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:FullImageView];
if (!shapeLayer)
{
shapeLayer = [CAShapeLayer layer];
shapeLayer.lineWidth = 1;
shapeLayer.strokeColor = [[UIColor blackColor] CGColor];
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
[FullImageView.layer addSublayer:shapeLayer];
}
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:firstPoint];
[path addLineToPoint:currentPoint];
shapeLayer.path = [path CGPath];
}
}
}
You can modify that UIBezierPath to include the arrowhead if you need that, too, for example:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (ArrowDraw==YES){
if ([[event allTouches]count]==1) {
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:FullImageView];
if (!shapeLayer) {
[self createShapeLayer];
}
shapeLayer.path = [[self arrowPathFrom:firstPoint to:currentPoint arrowheadSize:10.0] CGPath];
}
}
}
- (void)createShapeLayer
{
shapeLayer = [CAShapeLayer layer];
shapeLayer.lineWidth = 1;
shapeLayer.strokeColor = [[UIColor blackColor] CGColor];
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
[FullImageView.layer addSublayer:shapeLayer];
}
- (UIBezierPath *)arrowPathFrom:(CGPoint)start to:(CGPoint)end arrowheadSize:(CGFloat)arrowheadSize
{
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:start];
[path addLineToPoint:end];
// add arrowhead
CGFloat angle = atan2(end.y - start.y, end.x - start.x) + M_PI * 3.0 / 4.0;
[path addLineToPoint:CGPointMake(cos(angle) * arrowheadSize + end.x, sin(angle) * arrowheadSize + end.y)];
[path addLineToPoint:end];
angle = atan2(end.y - start.y, end.x - start.x) - M_PI * 3.0 / 4.0;
[path addLineToPoint:CGPointMake(cos(angle) * arrowheadSize + end.x, sin(angle) * arrowheadSize + end.y)];
[path addLineToPoint:end];
return path;
}

Related

Draw line on image by handgetsture in objective c

I have set image's content mode aspect fit.
Now issue is that, when I'm drawing line on image, that time image's content mode set scaletofill and my image stretched. So I want solution for when I'm drawing line on image, image content mode remain same.
U can download myproject from this link.
I'm using following code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if(self.tempImage.image==nil)
{
return;
}
colorPicker.hidden = YES;
UITouch *touch = [touches anyObject];
lastPoint = [touch locationInView:self.view];
lastPoint.y -= 20;
_pointsArray = [NSMutableArray array];
[_pointsArray addObject:NSStringFromCGPoint(lastPoint)];
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.tempImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, brush);
CGContextSetStrokeColorWithColor(UIGraphicsGetCurrentContext(), self.selectedColor.CGColor);
CGContextMoveToPoint(context, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(context, lastPoint.x, lastPoint.y);
CGContextStrokePath(context);
self.tempImage.image = UIGraphicsGetImageFromCurrentImageContext();
[self setupExternalScreen];
UIGraphicsEndImageContext();
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if(self.tempImage.image==nil)
{
return;
}
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
currentPoint.y -= 20;
UIGraphicsBeginImageContext(self.view.frame.size);
[self.tempImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(context, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y);
//Now set our brush size and opacity and brush stroke color:
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, brush);
CGContextSetStrokeColorWithColor(UIGraphicsGetCurrentContext(), self.selectedColor.CGColor);
CGContextSetBlendMode(context,kCGBlendModeNormal);
CGContextStrokePath(context);
self.tempImage.image = UIGraphicsGetImageFromCurrentImageContext();
[self.tempImage setAlpha:opacity];
UIGraphicsEndImageContext();
lastPoint = currentPoint;
[self setupExternalScreen];
[self.pointsArray addObject:NSStringFromCGPoint(lastPoint)];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if(self.tempImage.image==nil)
{
return;
}
//handle single tap, make _pointsArray has two identical points, draw a line between them
if (_pointsArray.count == 1) {
[_pointsArray addObject:NSStringFromCGPoint(lastPoint)];
}
[self.stack addObject:_pointsArray];
NSLog(#"color -> %# \nwidth->%f", self.selectedColor.description, brush);
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
[dic setObject:self.selectedColor forKey:#"color"];
[dic setObject:[NSNumber numberWithFloat:brush] forKey:#"width"];
[self.contextArray addObject:dic];
[self setupExternalScreen];
[self.undoManager registerUndoWithTarget: self
selector: #selector(popDrawing)
object: nil];
}
In this code, view frame set in UIGraphicsBeginImageContext. I think it will possible using subclass of UIImageView. I don't know exact solution.
Please see this Screenshot, u will easily understand my problem
Thanks in advance

How to draw line with in a image not whole UIImageView?

Before Colouring the image:
After Colouring the Image:
This is my code :
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
touchPoint = [touch locationInView:self.imgColor];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(touchPoint.x,touchPoint.y)];
[path addLineToPoint:CGPointMake(startingPoint.x,startingPoint.y)];
startingPoint=touchPoint;
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor redColor] CGColor];
[self.imgColor.layer addSublayer:shapeLayer];
[arrLayer addObject:shapeLayer];
NSLog(#"Touch moving point =x : %f Touch moving point =y : %f", touchPoint.x, touchPoint.y);
}
Depend upon the user touch, it's drawing a line inside UIImageView.
What i need is :
If image size is to small, then I don't like to allow draw outside the image.
Within the image user have to draw ,is there any way? Please suggest me.
Add this code to your touch handing view.
override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
return CGRectContainsPoint(doggyImage.frame, point)
}
Code provided in the first comment if (!CGRectContainsPoint(doggyImage.frame, touchPoint)) is some condition that you can use to check whether the touch point is in one specific view, where I think you should use to compare with your dog image (I don't know which variable it is, so I used doggyImage. Maybe self.imgColor is the correct one or not).
And for simplest solution, you need to do at least two things
If touchesBegan outside the doggyImage, don't do anything, just return.
Prevent lines been draw from inside to outside, so use the same condition, and apply the same code you used in touchesEnd to handle something like stopDrawLine.
More advanced method would include computing the nearest point from the touch to the image if it's outside, and draw it on the edge.
BTW, currently in your touchesMoved, you created one new UIBezierPath every single touch point, resulting in hundreds of discrete small pieces of line. You may want to try to new a path when touchesBegan and addLineToPoint in touchesMoved. So that the whole line is in one path, and you can therefore offer freatures like "undo".
take one CGRect object Globally assign its value as follow
CGRect imagerect = CGRectMake(imgColor.center.x - (imgColor.image.size.width/2 + imgColor.frame.origin.x), imgColor.center.y - (imgColor.image.size.height/2+ imgColor.frame.origin.y), imgColor.image.size.width, imgColor.image.size.height);
now in touchesMoved method put one condition before drawing if( CGRectContainsPoint(imagerect, touchPoint))
so the method will be like
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
touchPoint = [touch locationInView:self.imgColor];
if( CGRectContainsPoint(imagerect, touchPoint))
{
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(touchPoint.x,touchPoint.y)];
[path addLineToPoint:CGPointMake(startingPoint.x,startingPoint.y)];
startingPoint=touchPoint;
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor redColor] CGColor];
[self.imgColor.layer addSublayer:shapeLayer];
[arrLayer addObject:shapeLayer];
NSLog(#"Touch moving point =x : %f Touch moving point =y : %f", touchPoint.x, touchPoint.y);
}
}
Might be this is not perfect solution but i try to make same as your requirements. please try with this
#import "ViewController.h"
#interface ViewController ()
{
CGPoint touchPoint,startingPoint;
CALayer *layer;
float x1;
float y1;
IBOutlet UIImageView *imgColor;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
layer = [CALayer layer];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
-(void)viewDidAppear:(BOOL)animated
{
CGSize scaledImageSize = imgColor.image.size;
CGRect imageFrame = CGRectMake(roundf(0.5f*(CGRectGetWidth(imgColor.bounds)-scaledImageSize.width)), roundf(0.5f*(CGRectGetHeight(imgColor.bounds)-scaledImageSize.height)), roundf(scaledImageSize.width), roundf(scaledImageSize.height));
x1 = imageFrame.origin.x ;
y1 = imageFrame.origin.y ;
}
- (UIColor*)getRGBAsFromImage:(UIImage*)image atX:(int)x andY:(int)y
{
if (x < 0 || y<0 || x> image.size.width || y > image.size.height) {
return nil;
}
// First get the image into your data buffer
CGImageRef imageRef = [image CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);
// Now your rawData contains the image data in the RGBA8888 pixel format.
NSUInteger byteIndex = (bytesPerRow * y) + x * bytesPerPixel;
CGFloat alpha = ((CGFloat) rawData[byteIndex + 3] ) / 255.0f;
CGFloat red = ((CGFloat) rawData[byteIndex] ) / alpha;
CGFloat green = ((CGFloat) rawData[byteIndex + 1] ) / alpha;
CGFloat blue = ((CGFloat) rawData[byteIndex + 2] ) / alpha;
byteIndex += bytesPerPixel;
if (red >= 0 || green >= 0 || blue >= 0) {
return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}
return nil;
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
touchPoint = [touch locationInView:imgColor];
;
if ([self getRGBAsFromImage:imgColor.image atX:touchPoint.x - x1 andY:touchPoint.y - y1] && !(touchPoint.x == 0 && touchPoint.y == 0)) {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(touchPoint.x,touchPoint.y)];
[path addLineToPoint:CGPointMake(startingPoint.x,startingPoint.y)];
startingPoint=touchPoint;
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 1.0;
shapeLayer.fillColor = [[UIColor redColor] CGColor];
[imgColor.layer addSublayer:shapeLayer];
}
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
{
touchPoint = CGPointMake(0, 0);
}
#end

How to find out uncoloured area uibeizerpath?

That greycolour is UIImageView and the White colour font is Image.
That image Placed inside UIImageView.
I like to colour only inside the font ,not an whole UIImageview for that i am going to find out the coordinates of the image .
i am new to this kind of concept so kindly some one guide me how to colour only inside the image ,there are 50+ images is there ,it is not static so give some good idea .
This is the code i am using to draw inside the UIImageView:
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
touchPoint = [touch locationInView:self.imgColor];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(touchPoint.x,touchPoint.y)];
[path addLineToPoint:CGPointMake(startingPoint.x,startingPoint.y)];
startingPoint=touchPoint;
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor redColor] CGColor];
[self.imgColor.layer addSublayer:shapeLayer];
[arrLayer addObject:shapeLayer];
NSLog(#"Touch moving point =x : %f Touch moving point =y : %f", touchPoint.x, touchPoint.y);
}
Use this custom UIImage view:
CustomView.h
#interface CustomView : UIImageView
#end
CustomView.m
#interface CustomView ()
{
CGPoint touchPoint,startingPoint;
UIView *drawingView;
}
#end
#implementation CustomView
-(void)awakeFromNib
{
drawingView = [[UIView alloc] initWithFrame:self.bounds];
drawingView.backgroundColor = [UIColor clearColor];
[self addSubview:drawingView];
[self updateMask];
}
- (void)updateMask
{
CALayer *maskLayer = [CALayer layer];
maskLayer.geometryFlipped = YES;
maskLayer.contents = (id)self.image.CGImage;
switch (self.contentMode)
{
case UIViewContentModeScaleToFill:
maskLayer.contentsGravity = kCAGravityResize;
break;
case UIViewContentModeScaleAspectFit:
maskLayer.contentsGravity = kCAGravityResizeAspect;
break;
case UIViewContentModeScaleAspectFill:
maskLayer.contentsGravity = kCAGravityResizeAspectFill;
break;
case UIViewContentModeCenter:
maskLayer.contentsGravity = kCAGravityCenter;
break;
case UIViewContentModeTop:
maskLayer.contentsGravity = kCAGravityTop;
break;
case UIViewContentModeBottom:
maskLayer.contentsGravity = kCAGravityBottom;
break;
case UIViewContentModeLeft:
maskLayer.contentsGravity = kCAGravityLeft;
break;
case UIViewContentModeRight:
maskLayer.contentsGravity = kCAGravityRight;
break;
case UIViewContentModeTopLeft:
maskLayer.contentsGravity = kCAGravityTopLeft;
break;
case UIViewContentModeTopRight:
maskLayer.contentsGravity = kCAGravityTopRight;
break;
case UIViewContentModeBottomLeft:
maskLayer.contentsGravity = kCAGravityBottomLeft;
break;
case UIViewContentModeBottomRight:
maskLayer.contentsGravity = kCAGravityBottomRight;
break;
default:
break;
}
maskLayer.frame = drawingView.bounds;
drawingView.layer.mask = maskLayer;
}
- (void)setImage:(UIImage *)image
{
[super setImage:image];
[self updateMask];
}
- (void)layoutSubviews
{
[super layoutSubviews];
drawingView.frame = self.bounds;
drawingView.layer.mask.frame = drawingView.bounds;
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
touchPoint = [touch locationInView:self];
if (!CGPointEqualToPoint(startingPoint, CGPointZero))
{
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(touchPoint.x,touchPoint.y)];
[path addLineToPoint:CGPointMake(startingPoint.x,startingPoint.y)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor redColor] CGColor];
[drawingView.layer addSublayer:shapeLayer];
}
startingPoint=touchPoint;
// [arrLayer addObject:shapeLayer];
NSLog(#"Touch moving point =x : %f Touch moving point =y : %f", touchPoint.x, touchPoint.y);
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
{
startingPoint = CGPointZero;
}
#end

Generate image that was drawn

In my xcode project, the user draws an object manually. So for example they can draw a apple or triangle.
I need to save I guess the coordinates or the line path of what they draw.
How can I store the line path or re-create the image that the user has drawn. I don't want to save the image, but I want to learn from the image the user drew by knowing the specific line path?
Here is the code
.h
int mouseMoved;
BOOL mouseSwiped;
CGPoint lastPoint;
UIImageView *drawImage;
viewdidload {
drawImage = [[UIImageView alloc] initWithImage:nil];
drawImage.frame = self.view.frame;
[self.view addSubview:drawImage];
self.view.backgroundColor = [UIColor lightGrayColor];
mouseMoved = 0;
}
.m
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
BOOL mouseSwiped = NO;
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 2) {
drawImage.image = nil;
return;
}
lastPoint = [touch locationInView:self.view];
lastPoint.y -= 20;
}
- (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(), 5.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;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 2) {
drawImage.image = nil;
return;
}
_startPoint = [touch locationInView:self.view];
if(!mouseSwiped) {
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(), 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();
}
}
-(void)digitalSignatureCalled{
//viewSign.backgroundColor = [UIColor lightGrayColor];
//create a frame for our signature capture based on whats remaining
imageFrame = CGRectMake(0, 50, 500, 450);
//allocate an image view and add to the main view
mySignatureImage = [[UIImageView alloc] initWithImage:nil];
mySignatureImage.frame = imageFrame;
mySignatureImage.backgroundColor = [UIColor whiteColor];
[viewSign addSubview:mySignatureImage];
}
//when one or more fingers touch down in a view or window
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//did our finger moved yet?
fingerMoved = NO;
UITouch *touch = [touches anyObject];
//just clear the image if the user tapped twice on the screen
if ([touch tapCount] == 2) {
mySignatureImage.image = nil;
return;
}
//we need 3 points of contact to make our signature smooth using quadratic bezier curve
currentPoint = [touch locationInView:mySignatureImage];
lastContactPoint1 = [touch previousLocationInView:mySignatureImage];
lastContactPoint2 = [touch previousLocationInView:mySignatureImage];
}
//when one or more fingers associated with an event move within a view or window
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
//well its obvious that our finger moved on the screen
fingerMoved = YES;
UITouch *touch = [touches anyObject];
//save previous contact locations
lastContactPoint2 = lastContactPoint1;
lastContactPoint1 = [touch previousLocationInView:mySignatureImage];
//save current location
currentPoint = [touch locationInView:mySignatureImage];
//find mid points to be used for quadratic bezier curve
CGPoint midPoint1 = [self midPoint:lastContactPoint1 withPoint:lastContactPoint2];
CGPoint midPoint2 = [self midPoint:currentPoint withPoint:lastContactPoint1];
//create a bitmap-based graphics context and makes it the current context
UIGraphicsBeginImageContext(imageFrame.size);
//draw the entire image in the specified rectangle frame
[mySignatureImage.image drawInRect:CGRectMake(0, 0, imageFrame.size.width, imageFrame.size.height)];
//set line cap, width, stroke color and begin path
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 3.0f);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
//begin a new new subpath at this point
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), midPoint1.x, midPoint1.y);
//create quadratic Bézier curve from the current point using a control point and an end point
CGContextAddQuadCurveToPoint(UIGraphicsGetCurrentContext(),
lastContactPoint1.x, lastContactPoint1.y, midPoint2.x, midPoint2.y);
//set the miter limit for the joins of connected lines in a graphics context
CGContextSetMiterLimit(UIGraphicsGetCurrentContext(), 2.0);
//paint a line along the current path
CGContextStrokePath(UIGraphicsGetCurrentContext());
//set the image based on the contents of the current bitmap-based graphics context
mySignatureImage.image = UIGraphicsGetImageFromCurrentImageContext();
//remove the current bitmap-based graphics context from the top of the stack
UIGraphicsEndImageContext();
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
//just clear the image if the user tapped twice on the screen
if ([touch tapCount] == 2) {
mySignatureImage.image = nil;
return;
}
//if the finger never moved draw a point
if(!fingerMoved) {
UIGraphicsBeginImageContext(imageFrame.size);
[mySignatureImage.image drawInRect:CGRectMake(0, 0, imageFrame.size.width, imageFrame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 3.0f);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
mySignatureImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
}
//calculate midpoint between two points
- (CGPoint) midPoint:(CGPoint )p0 withPoint: (CGPoint) p1 {
return (CGPoint) {
(p0.x + p1.x) / 2.0,
(p0.y + p1.y) / 2.0
};
}
-(void)clickToSave:(id)sender{
//convert image into .png format.
viewNewSign.image = mySignatureImage.image;
if (mySignatureImage.image == nil) {
imgString = #"NoSignature";
}else{
imgString = [self getStringFromImage:mySignatureImage.image];
}
NSLog(#"image saved = %#",imgString);
NSLog(#"image length = %lu",(unsigned long)imgString.length);
viewSign.hidden = TRUE;
scroll.scrollEnabled = YES;
[scroll bringSubviewToFront:viewSign];
}
-(NSString *)getStringFromImage:(UIImage *)image{
if(image){
NSData *dataObj = UIImagePNGRepresentation(image);
//[appDelegate showAlert:#"Data Size" message:[NSString stringWithFormat:#"Data length = %lu",(unsigned long)dataObj.length]];
return [dataObj base64EncodedStringWithOptions:0];
} else {
return #"";
}
}
-(void)clickToClear:(id)sender{
[self digitalSignatureCalled];
}
- (UIImage*)imageWithImage:(UIImage*)image
scaledToSize:(CGSize)newSize;
{
UIGraphicsBeginImageContext( newSize );
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}

how to create Start and end point straight line using objective c [duplicate]

I have a UIViewController. How do I draw a line in one of its programmatically created views?
There are two common techniques.
Using CAShapeLayer:
Create a UIBezierPath (replace the coordinates with whatever you want):
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path addLineToPoint:CGPointMake(100.0, 100.0)];
Create a CAShapeLayer that uses that UIBezierPath:
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
Add that CAShapeLayer to your view's layer:
[self.view.layer addSublayer:shapeLayer];
In previous versions of Xcode, you had to manually add QuartzCore.framework to your project's "Link Binary with Libraries" and import the <QuartzCore/QuartzCore.h> header in your .m file, but that's not necessary anymore (if you have the "Enable Modules" and "Link Frameworks Automatically" build settings turned on).
The other approach is to subclass UIView and then use CoreGraphics calls in the drawRect method:
Create a UIView subclass and define a drawRect that draws your line.
You can do this with Core Graphics:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [[UIColor blueColor] CGColor]);
CGContextSetLineWidth(context, 3.0);
CGContextMoveToPoint(context, 10.0, 10.0);
CGContextAddLineToPoint(context, 100.0, 100.0);
CGContextDrawPath(context, kCGPathStroke);
}
Or using UIKit:
- (void)drawRect:(CGRect)rect {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path addLineToPoint:CGPointMake(100.0, 100.0)];
path.lineWidth = 3;
[[UIColor blueColor] setStroke];
[path stroke];
}
Then you can either use this view class as the base class for your NIB/storyboard or view, or you can have your view controller programmatically add it as a subview:
PathView *pathView = [[PathView alloc] initWithFrame:self.view.bounds];
pathView.backgroundColor = [UIColor clearColor];
[self.view addSubview: pathView];
The Swift renditions of the two above approaches are as follows:
CAShapeLayer:
// create path
let path = UIBezierPath()
path.move(to: CGPoint(x: 10, y: 10))
path.addLine(to: CGPoint(x: 100, y: 100))
// Create a `CAShapeLayer` that uses that `UIBezierPath`:
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 3
// Add that `CAShapeLayer` to your view's layer:
view.layer.addSublayer(shapeLayer)
UIView subclass:
class PathView: UIView {
var path: UIBezierPath? { didSet { setNeedsDisplay() } }
var pathColor: UIColor = .blue { didSet { setNeedsDisplay() } }
override func draw(_ rect: CGRect) {
// stroke the path
pathColor.setStroke()
path?.stroke()
}
}
And add it to your view hierarchy:
let pathView = PathView()
pathView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(pathView)
NSLayoutConstraint.activate([
pathView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
pathView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
pathView.topAnchor.constraint(equalTo: view.topAnchor),
pathView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
pathView.backgroundColor = .clear
let path = UIBezierPath()
path.move(to: CGPoint(x: 10, y: 10))
path.addLine(to: CGPoint(x: 100, y: 100))
path.lineWidth = 3
pathView.path = path
Above, I'm adding PathView programmatically, but you can add it via IB, too, and just set its path programmatically.
Create a UIView and add it as a subview of your view controller's view. You can modify this subview's height or width to be very small so that it looks like a line. If you need to draw a diagonal line you can modify the subviews transform property.
e.g. draw black horizontal line. This is called from within your view controller's implementation
UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.view.frame.size.width, 1)];
lineView.backgroundColor = [UIColor blackColor];
[self.view addSubview:lineView];
Swift 3:
let path = UIBezierPath()
path.move(to: CGPoint(x: 10, y: 10))
path.addLine(to: CGPoint(x: 100, y: 100))
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.lineWidth = 3.0
view.layer.addSublayer(shapeLayer)
Here's a cool technique you might find useful: Using blocks for drawing to avoid subclassing in Objective-C
Include the article's general-purpose view subclass in your project, then this is the kind of code you can put in your view controller to create a view on the fly that draws a line:
DrawView* drawableView = [[[DrawView alloc] initWithFrame:CGRectMake(0,0,320,50)] autorelease];
drawableView.drawBlock = ^(UIView* v,CGContextRef context)
{
CGPoint startPoint = CGPointMake(0,v.bounds.size.height-1);
CGPoint endPoint = CGPointMake(v.bounds.size.width,v.bounds.size.height-1);
CGContextSetStrokeColorWithColor(context, [UIColor grayColor].CGColor);
CGContextSetLineWidth(context, 1);
CGContextMoveToPoint(context, startPoint.x + 0.5, startPoint.y + 0.5);
CGContextAddLineToPoint(context, endPoint.x + 0.5, endPoint.y + 0.5);
CGContextStrokePath(context);
};
[self.view addSubview:drawableView];
You can use UIImageView to draw lines on.
It however, allows to skip sub-classing. And as I am little inclined to Core Graphics still can use it. You can just put it in - ViewDidLoad
UIGraphicsBeginImageContext(self.view.frame.size);
[self.myImageView.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), 50, 50);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), 200, 200);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
self.myImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Addition to Rob's answer, For a quicke, the third approach is to use an UIImageView - cover up with it - the view of xib. (Thats the default UIImageView appearance when dragged on xib in xcode 5)
Cheers and +1!
To draw inside your view is very simple ,#Mr.ROB said 2 method i took the first method .
Just Copy paste the code where you guys want it.
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
startingPoint = [touch locationInView:self.view];
NSLog(#"Touch starting point = x : %f Touch Starting Point = y : %f", touchPoint.x, touchPoint.y);
}
-(void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
}
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
touchPoint = [touch locationInView:self.view];
NSLog(#"Touch end point =x : %f Touch end point =y : %f", touchPoint.x, touchPoint.y);
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
touchPoint = [touch locationInView:self.view];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(touchPoint.x,touchPoint.y)];
[path addLineToPoint:CGPointMake(startingPoint.x,startingPoint.y)];
startingPoint=touchPoint;
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor redColor] CGColor];
[self.view.layer addSublayer:shapeLayer];
NSLog(#"Touch moving point =x : %f Touch moving point =y : %f", touchPoint.x, touchPoint.y);
[self.view setNeedsDisplay];
}
- (void)tapGestureRecognizer:(UIGestureRecognizer *)recognizer {
CGPoint tappedPoint = [recognizer locationInView:self.view];
CGFloat xCoordinate = tappedPoint.x;
CGFloat yCoordinate = tappedPoint.y;
NSLog(#"Touch Using UITapGestureRecognizer x : %f y : %f", xCoordinate, yCoordinate);
}
It will draw like a line ,where the finger moves going
You shouldn't really, but if for some reason it makes sense to you, you could create a subclass of UIView, called DelegateDrawView for example, that takes a delegate which implements a method like
- (void)delegateDrawView:(DelegateDrawView *)aDelegateDrawView drawRect:(NSRect)dirtyRect
and then in the methods - [DelegateDrawView drawRect:] you should call your delegate method.
But why would you want to put view code in your controller.
You are better off creating a subclass of UIView, that draws a line between two of its corners, you can have a property to set which two and then position the view where you want it from you view controller.
Swift 5.4
Use a UIView with a 1 or 2 points height and add it as a subview of your view controller's view.
class Separator: UIView {
let line = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func configure() {
backgroundColor = .red
addSubview(line)
line.translatesAutoresizingMaskIntoConstraints = false
line.backgroundColor = .secondaryLabelColor
NSLayoutConstraint.activate([
line.centerYAnchor.constraint(equalTo: self.centerYAnchor),
line.centerXAnchor.constraint(equalTo: self.centerXAnchor),
line.heightAnchor.constraint(equalToConstant: Pad.separatorHeight),
line.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.8 )
])
}
}
Then add it in your view controller:
let separator = Separator()
view.addSubview(separator)
separator.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
separator.trailingAnchor.constraint(equalTo: view.trailingAnchor),
separator.topAnchor.constraint(equalTo: view.bottomAnchor),
separator.leadingAnchor.constraint(equalTo: view.leadingAnchor),
separator.heightAnchor.constraint(equalToConstant: 72.0)
])

Resources