Drawing line on iPhone X - ios

I have drawing functionality in my app over photo. It's working on every device except iPhone X. On iPhone X the lines become fade and move upwards with each finger movement. The upper 10-20 percent area of view works fine. Following is the code to draw line.
- (void)drawLineNew{
UIGraphicsBeginImageContext(self.bounds.size);
[self.viewImage drawInRect:self.bounds];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetStrokeColorWithColor(UIGraphicsGetCurrentContext(), self.selectedColor.CGColor);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), _lineWidth);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), previousPoint.x, previousPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self setNeedsDisplay];}
Following is the sample drawing screenshot

After hours of hit and trial I made it work. The code I wrote is correct and should be working. The only issue was the frame size of that drawingView (self).
The height of view was in float and that was making it to go upwards with each pixel. I applied lroundf function and its working.
Happy coding.

Related

UIImage masking with gesture

I'm trying to achieve selective color feature in iOS. I personally think that first draw shape using finger gesture and convert that into mask, But at the same time it should be real time, It should work as i move my finger across the grayscale image. Can anyone direct me to correct path.
Sample app : https://itunes.apple.com/us/app/color-splash/id304871603?mt=8
Thanks.
You can position two UIImageViews over each other, the color version in the background and the black&white version in the foreground.
Then you can use touchesBegan, touchesMoved and so on events to track user input. In touches moved you can "erase" a path that the user moved the finger along like this (self.foregroundDrawView is the black&white UIImageView):
UIGraphicsBeginImageContext(self.foregroundDrawView.frame.size);
[self.foregroundDrawView.image drawInRect:CGRectMake(0, 0, self.foregroundDrawView.frame.size.width, self.foregroundDrawView.frame.size.height)];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextSetAllowsAntialiasing(context, TRUE);
CGContextSetLineWidth(context, 85);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetRGBStrokeColor(context, 1, 0, 0, 1.0);
// Soft edge ... 5.0 works ok, but we try some more
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 0.0), 13.0, [UIColor redColor].CGColor);
CGContextBeginPath(context);
CGContextMoveToPoint(context, touchLocation.x, touchLocation.y);
CGContextAddLineToPoint(context, currentLocation.x, currentLocation.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.foregroundDrawView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
The important part is CGContextSetBlendMode(context, kCGBlendModeClear);. This erases the traced part from the image, afterwards the image is set back as the image of the foreground image view.
When the user is done you should be able to combine the two images or use the black&white image as a mask.

Create Scalable Path CGContextPath

I'm new to developing in iOS.
I have problem when draw with Core Graphics/UIKit.
I want to implement a function like shape of paint in Window.
I use this source: https://github.com/JagCesar/Simple-Paint-App-iOS, and add new function.
When touchesMoved, I draw a shape, based on the point when touchesBegan, and the current touch point. It draws all the shape.
- (void)drawInRectModeAtPoint:(CGPoint)currentPoint
{
UIGraphicsBeginImageContext(self.imageViewDrawing.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.currentColor setFill];
[self.imageViewDrawing.image drawInRect:CGRectMake(0, 0, self.imageViewDrawing.frame.size.width, self.imageViewDrawing.frame.size.height)];
CGContextMoveToPoint(context, self.beginPoint.x, self.beginPoint.y);
CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y);
CGContextAddLineToPoint(context, self.beginPoint.x * 2 - currentPoint.x, currentPoint.y);
CGContextAddLineToPoint(context, self.beginPoint.x, self.beginPoint.y);
CGContextFillPath(context);
self.currentImage = UIGraphicsGetImageFromCurrentImageContext();
self.imageViewDrawing.image = self.currentImage;
UIGraphicsEndImageContext();
}
I mean, I want to create only one shape, when touchesBegan, the app record the point, when touchesMoved, the shape is scaled by touches, and when touchesEnd, draw the shape to the ImageContex
Hope you can give me some tips to do that.
Thank you.
You probably want to extract this functionality away from the context. As you are using an image, use an image view. At the start of the touches, create the image and the image view. Set the image view frame to the touch point with a size of {1, 1}. As the touch moves, move / scale the image view by changing its frame. When the touches end, use the start and end points to render the image into the context (which should be the same as the final frame of the image view).
Doing it this way means you don't add anything to the context which would need to be removed again when the next touch update is received. The above method would work similarly with a CALayer instead of an image view. You could also look at a solution using a transform on the view.

IOS line on an image - invert color possible?

I am drawing a line on top of an UIImage in my app. I want the line to be a "distinct" color from the background it is drawing. If the image has white area in it, if the line is drawn on top of it it should not be white. Is this achievable easilyt?
Now I am using white color for the line. Code below:
[myImage drawInRect:CGRectMake(0,0,200,200)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 1.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(),1,1,1, 1.0);//RGB all 1)
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), pt1.x, pt1.y); // pt1 -start point
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), pt2.x, pt2.y); // pt2 - end point
As you can see I have used 1,1,1 to get white line on top of the image from point pt1 to pt2. When this is drawn on a white area of 'myImage' the line becomes invisible. I want to make it visible somehow on top of white as well. How can I achieve this?
Not sure whether there is already an answer to this on this forum. But couldn't find anything like this.
Thanks in advance for your help
EDIT
#rob mayoff's answer wroked perfect for me.
Here is my final code for the benefit of anyone looking here:
[myImage drawInRect:CGRectMake(0,0,200,200)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 1.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(),1,1,1, 1.0);//RGB all 1)
CGContextSetShadowWithColor(UIGraphicsGetCurrentContext(), CGSizeMake(2.0f, 2.0f), 1.0f,
[[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:.6] CGColor]);
//CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeExclusion);
//CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeDifference);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), pt1.x, pt1.y); // pt1 -start point
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), pt2.x, pt2.y); // pt2 - end point
Here are two suggestions:
Use a black shadow around your white line. Take a look at CGContextSetShadowWithColor. You will also probably want to use CGContextSaveGState and CGContextRestoreGState, if you want to draw more things after drawing the line.
Set the blend mode to kCGBlendModeDifference or kCGBlendModeExclusion. See CGContextSetBlendMode.

How can I smooth the line between 2 points in iOS?

I already know how to draw a line between 2 points, but the line seems not so smooth. What can I do to make it smoother? Thanks you.
- (void)drawLineFrom:(CGPoint)start To:(CGPoint)end {
// begin image context
UIGraphicsBeginImageContext(self.imageLineView.frame.size);
// define image rect for drawing
[self.imageLineView.image drawInRect:CGRectMake(0, 0, imageLineView.frame.size.width, imageLineView.frame.size.height)];
// set line properties
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 2.0f);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0f, .0f, .0f, 1.0);
// move context to start point
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), start.x, start.y);
// define path to end point
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), end.x, end.y);
// stroke path
CGContextStrokePath(UIGraphicsGetCurrentContext());
// flush context to be sure all drawing operations were processed
CGContextFlush(UIGraphicsGetCurrentContext());
// get UIImage from context and pass it to our image view
imageLineView.image = UIGraphicsGetImageFromCurrentImageContext();
// end image context
UIGraphicsEndImageContext();
}
You can draw smooth line using Bezier Path.
You can have some more information here.
Bézier Paths
Try to enable Anti-Aliasing. you'll need to set the UIViewEdgeAntialiasing key to YES in your Info.plist.

IOS: draw an image in a view

I have this code to color in a view:
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:drawImage];
UIGraphicsBeginImageContext(drawImage.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width, drawImage.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), size);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), r, g, b, a);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
my problem is that I want to color not with a point, but I want to use a particular image that is repeated (as a png image)
Is it possible?
It's easy to load a single UIImage and draw it:
UIImage *brushImage = [UIImage imageNamed:#"brush.png"];
[brushImage drawAtPoint:CGPointMake(currentPoint.x-brushImage.size.width/2, currentPoint.y-brushImage.size.height/2)];
This will draw the image just once per cycle, not a continuous line. If you want solid lines of your brush picture, see Objective C: Using UIImage for Stroking.
This could end up loading the image file every time this method is called, making it slow. While the results of [UIImage imageNamed:] are often cached, my code above could be improved by storing the brush for later reuse.
Speaking of performance, test this on older devices. As written, it worked on my second generation iPod touch, but any additions could make it stutter on second and third generation devices. Apple's GLPaint example, recommended by #Armaan, uses OpenGL for fast drawing, but much more code is involved.
Also, you seem to be doing your interaction (touchesBegan:, touchesMoved:, touchesEnded:) in a view that then draws its contents to drawImage, presumably a UIImageView. It is possible to store the painting image, then set this view's layer contents to be that image. This will not alter performance, but the code will be cleaner. If you continue using drawImage, access it through a property instead using its ivar.
You can start with APPLE's sample code:Sample code:GLPaint

Resources