Get Signature in iPad App

Get Signature in iPad App

Author: Ghanshyam Maliwal

One of the basic requirement for filling any Technical forms needs attached signature. Following code describes how to add Signature functionality in your project.


SignatureViewController:

This ViewController opens in UIPopOverViewController and holds user Signature. User sketches here on UIView using CALayer ,
CGContext classes ( Core-Data framework API) . While making Signature, if any Correction is required, than tap three times
continuously enables incorrect signature disappear and can make new one signature . After so, tap outside UIPopOverViewController
that displays Signature in UIImageView that appears on MainViewController.

SignatureViewController.h file includes :

@interface SignatureViewController : UIViewController{
CALayer *canvasLayer;
CALayer *backgroundLayer;
UIImage *cacheImage;
CGMutablePathRef path;
CGPoint pathPoint;
BOOL touching;
}

SignatureViewController.m file includes :


1) put this below code in viewDidLoad

//Set Up drawing Layer
canvasLayer = [[CALayer layer] retain];
canvasLayer.bounds = CGRectMake(0,0,768, 600);
canvasLayer.position = CGPointMake(canvasLayer.bounds.size.width/2, canvasLayer.bounds.size.height/2);
[canvasLayer setDelegate:self];
[self.view.layer addSublayer:canvasLayer];
//Set up storage Layer
backgroundLayer = [[CALayer layer] retain];
backgroundLayer.bounds = CGRectMake(0,0,768, 600);
backgroundLayer.position = CGPointMake(backgroundLayer.bounds.size.width/2, backgroundLayer.bounds.size.height/2);
[backgroundLayer setDelegate:self];
[self.view.layer addSublayer:backgroundLayer];
//Initialize some other Variable
cacheImage = nil;
touching = NO;
NOTE: we are taking two Layer
a) Canvaslayer is used to hold signature temporarily
b) background layer is used to hold signature permanently.


2) Implement Touches Delegate in your ViewController

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(@"touch moving is calling");
if(touching){
//get the Current location of touch event
UITouch *touch = [touches anyObject];
pathPoint = [touch locationInView:self.view];
CGPathAddLineToPoint(path, NULL, pathPoint.x, pathPoint.y);
[canvasLayer setNeedsDisplay];
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if ([touch tapCount]==3) {
NSLog(@"calling to hide ");
[self resetSignature];
}else{
NSLog(@"touch begin is calling");
if (touching) return;
//Start a new Path
path = CGPathCreateMutable();
//set the path's starting point
UITouch *touch = [touches anyObject];
CGPathMoveToPoint(path, NULL, [touch locationInView:self.view].x, [touch locationInView:self.view].y);
touching = YES;
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(@"touch end is calling");
UITouch *touch = [touches anyObject];
if ([touch tapCount]==3) {
NSLog(@"calling to hide in end ");
[self resetSignature];
}else{
if (!touching) return;
//create a new image context (Bitmap based graphic context and make it current context)
UIGraphicsBeginImageContext(CGSizeMake(backgroundLayer.bounds.size.width, backgroundLayer.bounds.size.height));
//grab a reference to the new image context
CGContextRef ctx = UIGraphicsGetCurrentContext();
//push the image context to the top of the drawing stack
UIGraphicsPushContext(ctx);
//set the blend mode to prevent white pixels from
//covering up the lines that have already been drawn
CGContextSetBlendMode(ctx, kCGBlendModeDarken);
if (cacheImage != nil) {
//draw the cached state of the image to the image context and release it
[cacheImage drawInRect:CGRectMake(0,0,backgroundLayer.bounds.size.width,backgroundLayer.bounds.size.height)];
[cacheImage release];
}
//blend the drawing layer into the image context
[canvasLayer drawInContext:ctx];

//we're done drawing to the image context
UIGraphicsPopContext();
//store the image context so we can add to it again later (this is refresh Image)
cacheImage = UIGraphicsGetImageFromCurrentImageContext();
[cacheImage retain];
//we're finished with the image context altogether
UIGraphicsEndImageContext();
touching = NO;
//release the path
CGPathRelease(path);
//update the background layer (we'll need to draw the cached image to the background)
[backgroundLayer setNeedsDisplay];
}
}


3) This drawLayer is called when either canvas layer or background layer is going to send setNeedsDisplay message

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {

NSLog(@"calling drawing line ");
//this method is handling multiple layers, so first
//determine which layer we're drawing to
if (layer == canvasLayer) {
//we don't want this to fire after the background layer update
//and after the path has been released
if (!touching) return;
//add the path to the context
CGContextAddPath(ctx, path);
//set a line width and draw the path
CGContextSetLineWidth(ctx, 2.0f);
//CGContextSetStrokeColorWithColor(ctx, [[UIColor greenColor] CGColor]);
CGContextStrokePath(ctx);
//CGContextRelease(ctx);
}
else if (layer == backgroundLayer) {
//remember the current state of the context
CGContextSaveGState(ctx);
//the cached image coordinate system is upside down, so do a backflip
CGContextTranslateCTM(ctx, 0, backgroundLayer.bounds.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
//draw the image
CGImageRef ref = cacheImage.CGImage;
CGContextDrawImage(ctx, backgroundLayer.bounds, ref);
//restore the context to its pre-flipped state
CGContextRestoreGState(ctx);
}
}


4) We use below resetSingnature function to remover signature and create platform to get new Signature

-(void)resetSignature{
path =nil;
cacheImage = nil;
canvasLayer.contents = nil;
backgroundLayer.contents = nil;
}


0 comments:

Post a Comment