Thursday, 30 August 2012

How to make a brush for drawing app?


Hello!
I've started to learn Objective-c with making drawing app. Many people ask how to make a brush like in Photoshop, so I am posting here my solution.

Step-by-step instruction.

1) You need to store points of the curve that user has drawn by touch (its easy - you need to create NSMutableArray and add CGPoints created with location of touch to it in touchesMoved event)
2) Now lets create brush
 This is how we are going to make it: 
  1) paint image that we are going to use as brush in appropriate color and scale it
  2) draw this image along the path we created in 1st part

Create extension of UIImage class
and add following method
+(UIImage*)imageNamed:(NSString *)name withColor:(UIColor*)color Scale:(float)scale
    UIImage* img=[UIImage imageNamed:name];
    UIGraphicsBeginImageContext(img.size);
    CGContextRef context=UIGraphicsGetCurrentContext();
    [color setFill];
    CGContextTranslateCTM(context, 0, img.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextSetBlendMode(context, kCGBlendModeNormal);
    CGRect rect =CGRectMake(0, 0, img.size.width, img.size.height);
    CGContextDrawImage(context, rect, img.CGImage);
    CGContextClipToMask(context, rect, img.CGImage);
    CGContextAddRect(context, rect);
    CGContextDrawPath(context, kCGPathFill);
    UIImage*coloredImage=UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    UIImage*ret=[UIImage imageWithCGImage:coloredImage.CGImage scale:1/scale orientation:coloredImage.imageOrientation];
    return ret;
}

Thats how we change color and scale image.

Now lets draw it
I've made my own classes to store curve and points: drawnCurve and drawnPoint, drawnCurve has NSMutableArray of drawnPoints-drawnCurve.points.
This method is called in drawnCurve class. shouldFar tells if we should draw images far from each other like in spray,or not-like in pencil.

-(void)primitiveDrawAtContext:(CGContextRef)context withBrush:(UIImage*)brush shouldFar:(BOOL)f1
CGFloat hyp;    
hyp=sqrtf(brush.size.width*brush.size.width+brush.size.height*brush.size.height);
drawnPoint*beg=[self.points objectAtIndex:0];
CGContextMoveToPoint(context, beg.x, beg.y);
CGPoint t=CGPointMake(beg.x, beg.y);
CGLayerRef layer=CGLayerCreateWithContext(context, CGSizeMake(brush.size.width,brush.size.height), NULL);
CGContextRef tmp=CGLayerGetContext(layer);
CGContextDrawImage(tmp,CGRectMake(0, 0, brush.size.width, brush.size.height), brush.CGImage);
CGContextBeginTransparencyLayer(context, NULL);
CGContextDrawLayerAtPoint(context, CGPointMake(t.x-brush.size.width/2, t.y-brush.size.height/2), layer);
    
for(int i=0;i<self.points.count-1;i++)
{
    drawnPoint* cur=[points objectAtIndex:i];
    drawnPoint* next=[points objectAtIndex:i+1];
   
  
    if(f1)
     count=(int)sqrt((cur.x-next.x)*(cur.x-next.x)+(cur.y-next.y)*(cur.y-next.y))/(hyp);
    else {
        count=(int)sqrt((cur.x-next.x)*(cur.x-next.x)+(cur.y-next.y)*(cur.y-next.y))/(0.25*hyp);
    }
    double stepX=(next.x-cur.x)/count;
    double stepY=(next.y-cur.y)/count;    
    for(int j=0;j<count+1;j++)
    {
        
        CGContextDrawLayerAtPoint(context,CGPointMake(cur.x+j*stepX-brush.size.width/2, (cur.y+j*stepY-brush.size.height/2)) , layer); }
           
    if(f1==YES) {
       if((count==0)  && (sqrt(pow((cur.x-t.x),2)+pow((cur.y-t.y),2))> max(0.5*hyp,3)))

        {  
            
            CGContextDrawLayerAtPoint(context, CGPointMake(cur.x-brush.size.width/2, cur.y-brush.size.height/2), layer);
            
            t.x=cur.x;
            t.y=cur.y;
        }
    }
    else {
        if((count==0)  && (sqrt(pow((cur.x-t.x),2)+pow((cur.y-t.y),2))>min(3,0.5*hyp)))
           
        {  
            
            CGContextDrawLayerAtPoint(context, CGPointMake(cur.x-brush.size.width/2, cur.y-brush.size.height/2), layer);
            
            t.x=cur.x;
            t.y=cur.y;
            
        }
    }
}


Here is the result

If you have any questions or you need some code - you are welcome to ask!




Intro

Hello everyone interested in iOS developing!
I've started learning Objective-C 3 months ago and soon I'll post my 1st app on App Store.
I'll tell about some  tricks I used, my new projects, about getting to App Store and how to make your application popular. I hope you will find it interesting!