how to draw airbrush on UIImageView? - iphone

I am a beginner working on paint application on iphone.
adding new tool for my iphone App called airbrush...
which will spray on UIImageView. can any one help me out how to work with it.

Logic for air brush.........
- (UIBezierPath *)pathFromPoint:(CGPoint)start toPoint:(CGPoint)end {
CGFloat lineWidth=10;
redrawRect = CGRectMake(end.x-lineWidth,end.y-lineWidth,lineWidth*2,lineWidth*2);
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
UIBezierPath *circle = [UIBezierPath bezierPathWithOvalInRect:redrawRect];
NSInteger i, x, y;
NSInteger modNumber =4*(int)lineWidth;
for (i = 0; i < (lineWidth*lineWidth)/2; i++) {
do {
x = (random() % modNumber)+end.x - 2*lineWidth;
y = (random() % modNumber)+end.y - 2*lineWidth;
} while (![circle containsPoint:CGPointMake(x,y)]);
[bezierPath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(x,y,0.5,0.5)]];
}
return bezierPath;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
currentPoint = [touch locationInView:self.view];
currentPoint.y -=20;
[self drawCircle];
}
-(void)drawCircle{
UIGraphicsBeginImageContext(self.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)];
CGContextSetLineWidth(UIGraphicsGetCurrentContext(),10);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
UIBezierPath *path=[self pathFromPoint:currentPoint
toPoint:currentPoint];
[path stroke];
lastPoint = currentPoint;
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}

I think you might be looking for CGContextBeginPath and its related functions. I am not quite sure how to define a new stroke but I imagine it can be handled with something like [UIColor colorFromImage:myImage]. You should look into Quartz 2D, try looking here.
/Thomas

Related

CGContextStrokePath scaling issue

I am working on a drawing App which have two UIImageViews. What I would like to do is erase the top UIImageView so that I can see the bottom UIImageView and vice versa. I have implemented all the functionality and its working perfect but the issue happens when I Pan/Zoom the UIImageView using UIGestureRecognizer and the I started to erase the Image so the LineWidth is also Zoomed e.g: initialy my eraser width set to 25.0f if I zoom my UIImageView 200% my eraser also zoomed out to 200% i.e from 25.0f to 50.0f which makes everything go crazy. So My question is How can I remain my eraser to its original width rather than zoomed out/in with Image Zooming?
Here is my Code:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if (selectedButton == self.Image1Btn)
currentPoint = [touch locationInView:self.ImageCaptureView];
if (selectedButton == self.Image2Btn)
currentPoint = [touch locationInView:self.ImageCaptureView];
if (bottomBarSelectedButton == 1)
{
if (selectedButton == self.Image1Btn)
{
UIGraphicsBeginImageContext(self.Image1.frame.size);
[self.Image1.image drawAtPoint:CGPointZero];
}
if (selectedButton == self.Image2Btn)
{
UIGraphicsBeginImageContext(self.Image2.image.size);
[self.Image2.image drawAtPoint:CGPointZero];
}
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextBeginPath(context);
CGContextMoveToPoint(context, previousPoint1.x, previousPoint1.y-36);
CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y-36);
CGContextStrokePath(context);
if (selectedButton == self.Image1Btn)
{
self.Image1.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
previousPoint1 = [touch locationInView:self.ImageCaptureView];
}
if (selectedButton == self.Image2Btn)
{
self.Image2.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
previousPoint1 = [touch locationInView:self.ImageCaptureView];
}
}
}
- (IBAction)handlePinch:(UIPinchGestureRecognizer *)recognizer {
CGAffineTransform t = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
recognizer.view.transform = t;
recognizer.scale = 1;
}

How to draw a straight line on an iOS map without moving the map using MKmapkit

I want to draw a straight line on an iOS map using MKmapkit without the map moving around.
For example, if the user draws a straight line between two places on the map without removing the finger off the map, I don't want the map view to move around while the user is drawing the line.
I've searched on google, but didn't find an answer/solution.
Please can somebody help me?
Disable the mapkit scroll
_mapView.scrollEnabled=NO;
And then draw line with the help of core graphics
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if (drawImage==nil) {
drawImage=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self.view addSubview:drawImage];
}
lastPoint = [touch locationInView:self.view];
lastPoint.y -= 20;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:drawImage];
currentPoint.y -= 20;
UIGraphicsBeginImageContext(drawImage.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width,drawImage.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.5, 0.6, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
}
You can draw poly line between two or more points/ coordinates.
Here is a question which is answered. Source: Draw a polyline between two coordinates in Xcode
You have to use MKOverlayView like below :
In Interface file
MKPolyline* _routeLine;
MKPolylineView* _routeLineView;
In Implementation file
Store all the coordinates in
NSMutablrArray *routeLatitudes
then
MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * [routeLatitudes count]);
for(int idx = 0; idx < [routeLatitudes count]; idx++)
{
CLLocationCoordinate2D workingCoordinate;
workingCoordinate.latitude=[[routeLatitudes objectAtIndex:idx] doubleValue];
workingCoordinate.longitude=[[routeLongitudes objectAtIndex:idx] doubleValue];
MKMapPoint point = MKMapPointForCoordinate(workingCoordinate);
pointArr[idx] = point;
}
// create the polyline based on the array of points.
routeLine = [MKPolyline polylineWithPoints:pointArr count:[routeLatitudes count]];
[mapViewHome addOverlay:self.routeLine];
free(pointArr);
and Overlay delegate
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKOverlayView* overlayView = nil;
if(overlay == routeLine)
{
routeLineView = [[[MKPolylineView alloc] initWithPolyline:self.routeLine] autorelease];
routeLineView.fillColor = [UIColor colorWithRed:0.945 green:0.027 blue:0.957 alpha:1];
routeLineView.strokeColor = [UIColor colorWithRed:0.945 green:0.027 blue:0.957 alpha:1];
routeLineView.lineWidth = 4;
overlayView = routeLineView;
}
return overlayView;
}

Clear a drawing in drawRect

How can I clear a drawing in a subview? What should I put in my (void)clearLine below?
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Setup subview to draw a line
CGRect subviewRect = CGRectMake(0, 0, 250, 300);
Draw* _draw = [[Draw alloc] initWithFrame:subviewRect];
_draw.exclusiveTouch = NO;
_draw.backgroundColor = [UIColor clearColor];
[self addSubview:_draw];
}
return self;
}
- (void) clearLine
{
// how can I clear the drawing in Draw
}
And below is the Draw.m file, that will draw a straight line by getting the first touch as the starting point and the second touch as the ending point.
#implementation Draw
- (void)drawRect:(CGRect)rect {
CGPoint fromPoint;
CGPoint toPoint;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextMoveToPoint(context, fromPoint.x, fromPoint.y);
CGContextAddLineToPoint(context, toPoint.x, toPoint.y);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
}
// Touch event
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touchPoint = [touches anyObject];
fromPoint = [touchPoint locationInView:self];
toPoint = [touchPoint locationInView:self];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
toPoint = [touch locationInView:self];
[self setNeedsDisplay];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
toPoint = [touch locationInView:self];
[self setNeedsDisplay];
}
In clear line you should remove Draw view and set it nil
Draw* _draw;
- (void) clearLine
{
[_draw removeFromSuperview];
_draw=nil;
}
and to again enable drawing use
-(void) initDrawView
{
CGRect subviewRect = CGRectMake(0, 0, 250, 300);
if(_draw!=nil)
{
[_draw removeFromSuperview];
_draw=nil;
}
_draw = [[Draw alloc] initWithFrame:subviewRect];
_draw.exclusiveTouch = NO;
_draw.backgroundColor = [UIColor clearColor];
[self addSubview:_draw];
}
Draw the background color on your view,
Like if you have white background then [UIColor whiteColor];
if you have black background then [UIColor blackColor];
Make a Bool variable in Draw class
And when you want to clear all like this
- (void) clearLine
{
// Here you can clearn lines
[_draw CleanAllLines]
}
And In Draw class make the method
-(void)CleanAllLines{
isNeedToClear = YES;
[self setNeedsLayout];
}
- (void)drawRect:(CGRect)rect {
if(isNeedToClear){
isNeedToClear = NO;
return;
}
CGPoint fromPoint;
CGPoint toPoint;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextMoveToPoint(context, fromPoint.x, fromPoint.y);
CGContextAddLineToPoint(context, toPoint.x, toPoint.y);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
}

Drawing a line between the previous end point to next start point

i'm stuck at this problem. I need to draw a line between the previous end point to next start point. My code for drawing a line between 2 points is
- (void)drawRect:(CGRect)rect
{
CGContextRef c=UIGraphicsGetCurrentContext();
CGContextSetLineWidth(c, 4.0);
CGFloat red[4]={0.0f, 0.0f, 0.0f, 1.0f};
CGContextSetStrokeColor(c, red);
CGContextBeginPath(c);
CGContextMoveToPoint(c, 50.0f, 50.0f);
CGContextAddLineToPoint(c, 100.0f, 100.0f);
CGContextStrokePath(c) ;
}
How can i give multiple points, so that i can it shows like a graph.
Thanks in advance
On a side note, Apple prefers that you use the higher UIKit methods instead of the Core Graphics calls for simple stuff like drawing lines and curves, so you could rewrite your method like this:
[[UIColor redColor] setStroke];
UIBezierPath *linePath = [UIBezierPath bezierPath];
[linePath moveToPoint:CGPointMake(50.0, 50.0)];
[linePath addLineToPoint:CGPointMake(100.0, 100.0)];
[linePath setLineWidth:4.0];
[linePath stroke];
Just add more CGContextAddLineToPoint calls
- (void)drawRect:(CGRect)rect
{
CGContextRef c=UIGraphicsGetCurrentContext();
CGContextSetLineWidth(c, 4.0);
CGFloat red[4]={0.0f, 0.0f, 0.0f, 1.0f};
CGContextSetStrokeColor(c, red);
CGContextBeginPath(c);
CGContextMoveToPoint(c, 50.0f, 50.0f);
CGContextAddLineToPoint(c, 100.0f, 100.0f);
CGContextAddLineToPoint(c, 120.0f, 80.0f);
CGContextAddLineToPoint(c, 140.0f, 120.0f);
CGContextAddLineToPoint(c, 160.0f, 80.0f);
...
CGContextStrokePath(c) ;
}
Jus a little correction to your code:
-(void)drawLineFromPoint:(CGPoint)startPoint toPoint:(CGPoint)endPoint{
UIGraphicsBeginImageContext(YOUR_IMAGEVIEW.image.size);
[YOUR_IMAGEVIEW.image drawInRect:CGRectMake(0, 0, YOUR_IMAGEVIEW.image.size.width, YOUR_IMAGEVIEW.image.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), startPoint.x, startPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), endPoint.x, endPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
[YOUR_IMAGEVIEW setImage:UIGraphicsGetImageFromCurrentImageContext()];
UIGraphicsEndImageContext();
}
YOUR_IMAGEVIEW is an outlet to your imageview you are drawing on.
As you can see - you just have to send to this method your start point and the end one! Easy as 1-2-3.
EDIT 1
How to use it? Declare a global CGPoint "startPoint";
Then say:
//___________________________________________________
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
startPoint = [touch locationInView:YOUR_IMAGEVIEW];
}
//___________________________________________________
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint nextPoint = [touch locationInView:YOUR_IMAGEVIEW];
[self drawLineFromPoint:startPoint toPoint:nextPoint];
startPoint = nextPoint;
}
EDIT 2
Here is another way to draw your points:
- (void)drawGraphMethod{
NSMutableArray *pointsArr = [[[NSMutableArray alloc]init]autorelease];
//now you should add the needed points to your array
//I have no idea what graph do you have, so I just
//put there some random points that will look like a graph
[pointsArr addObject:[NSValue valueWithCGPoint:CGPointMake(30.0, 10.0)]];
[pointsArr addObject:[NSValue valueWithCGPoint:CGPointMake(40.0, 26.0)]];
[pointsArr addObject:[NSValue valueWithCGPoint:CGPointMake(70.0, 55.0)]];
[pointsArr addObject:[NSValue valueWithCGPoint:CGPointMake(80.0, 88.0)]];
[pointsArr addObject:[NSValue valueWithCGPoint:CGPointMake(90.0, 33.0)]];
[pointsArr addObject:[NSValue valueWithCGPoint:CGPointMake(130.0, 100.0)]];
//well, you can store only objects, that's why I used NSValue.
//it's not hard to cenvert it back
//now parse the array
for (int i = 0; i < pointsArr.count-1; i++) {
CGPoint startPoint = [[pointsArr objectAtIndex:i] CGPointValue];
CGPoint nextPoint = [[pointsArr objectAtIndex:i+1] CGPointValue];
[self drawLineFromPoint:startPoint toPoint:nextPoint];
}
}

draw only straight line not smooth

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:scrollView];
//[self drawLine:lastPoint.x :lastPoint.y :currentPoint.x :currentPoint.y];
tempShapeLayer = nil;
CGMutablePathRef linePath = nil;
linePath = CGPathCreateMutable();
tempShapeLayer = [CAShapeLayer layer];
tempShapeLayer.lineWidth = 4.0f;
tempShapeLayer.lineCap = kCALineJoinMiter;
tempShapeLayer.strokeColor = [[UIColor redColor] CGColor];
CGPathMoveToPoint(linePath, NULL, lastPoint.x, lastPoint.y);
CGPathAddLineToPoint(linePath, NULL, currentPoint.x, currentPoint.y);
tempShapeLayer.path = linePath;
CGPathRelease(linePath);
[scrollView.layer addSublayer:tempShapeLayer];
lastPoint = currentPoint;
}
i am drawing line by this code . but i want this line remain straight. means when i move my touch the line should not become smooth.line will be remain straight.
i think i have to do something like
if (currentPoint.x > lastPoint.x){
currentPoint.y = lastPoint.y;
}
else if (currentPoint.x < lastPoint.x) {
currentPoint.x = lastPoint.x;
}
if you are moving subpixels you will get unwanted antialiasing. I suggest floor/ceil to a non float. This obviously gets more complicated when working with retina vs non retina.