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!




26 comments:

  1. Hey, could you maybe post the Xcode project files? This looks really useful, but you don't give much context, and it's hard to understand where these methods go.

    ReplyDelete
  2. Hi,

    Can you share project sample please.

    ReplyDelete
  3. Hey Can you please email me your sample project to kapilan1989@gmail.com ? It would be a great help.

    ReplyDelete
  4. Hi, i m looking for this kind of project from many days...
    Thanks you very much..
    Can you please upload xcode project or mail me at jrt814@gmail.com ...
    Thanks again!!!

    ReplyDelete
  5. Hello i follow your instruction but when i draw nothing happens...
    Can you tell me pls which kind of class is drawnCurve?
    I made drawnPoint class as nsobject to store cgpoints and it seems to work, but the app doesn't draw.. Pls help me! TY!

    ReplyDelete
  6. Hey Can you please send me your sample project to slavcopetkovski@yahoo.com ?
    Thank you.

    ReplyDelete
  7. Please send me this project at kishimotovn@gmail.com
    I would be very grateful, tks :D

    ReplyDelete
  8. Please upload project to github or send me to abbadoh@gmail.com

    ReplyDelete
  9. Please send me this project at amit.044012@gmail.com

    ReplyDelete
  10. Please send me this project at urja.leewayinfotech@gmail.com

    ReplyDelete
  11. Please send me this project at hangkimduyen@gmail.com, thank you very much!

    ReplyDelete
  12. Hello, please send me the source code at lamtran.tech@gmail.com, thank you.

    ReplyDelete
  13. Hello, please send me the source code at lamtran.tech@gmail.com, thank you.

    ReplyDelete
  14. Hello, could you please send me a copy of the project at patriciotinoco@gmail.com, thank you in advance :)

    ReplyDelete
  15. hey..can i get the whole code..beacuse there are some varibles that are not defined here..! please help..ASAP. Thanku

    P.S.: Mail=> rednimrah20@gmail.com

    ReplyDelete
  16. Hello, please send me the source code at sanjay.jogani.mit@gmail.com, thank you.

    ReplyDelete
  17. Hi, tks you very much. Can you send me the source code at boy.ice.tea@gmail.com. Tks

    ReplyDelete
  18. please send me the source code at brijesh.gurutechnolabs@gmail.com

    ReplyDelete
  19. please send me the source code: vominhtri1049@gmail.com. Thanks you very much!

    ReplyDelete
  20. Please send me source code: oxid_burn@ukr.net.
    Thank you very much!

    ReplyDelete
  21. Please send me the source code sakura20193@gmail.com
    Thank you very much!

    ReplyDelete
  22. Please send me the source code mubassher10@gmail.com
    Thank you very much!

    ReplyDelete
  23. (copy + paste ) => oguzhan.akbudak@hotmail.com.tr ( copy + paste ) :)

    ReplyDelete
  24. This comment has been removed by the author.

    ReplyDelete
  25. Please send me the source code gizingun@gmail.com
    Thank you very much!

    ReplyDelete
  26. Hi,please send me the source code at felixkongmr@gmail.com

    ReplyDelete