/*------------------------------------------------------------------------ * (The MIT License) * * Copyright (c) 2008-2011 Rhomobile, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * http://rhomobile.com *------------------------------------------------------------------------*/ #import "SignatureView.h" @implementation SignatureView -(CGContextRef)CreateRGBABitmapContext:(int)width height:(int)height { CGContextRef context = NULL; CGColorSpaceRef colorSpace; void * bitmapData; int bitmapByteCount; int bitmapBytesPerRow; // Get image width, height. We'll use the entire image. size_t pixelsWide = width; size_t pixelsHigh = height; // Declare the number of bytes per row. Each pixel in the bitmap in this // example is represented by 4 bytes; 8 bits each of red, green, blue, and // alpha. bitmapBytesPerRow = (pixelsWide) << 2; bitmapByteCount = (bitmapBytesPerRow * pixelsHigh); // Use the generic RGB color space. colorSpace = CGColorSpaceCreateDeviceRGB();//CGColorSpaceCreateDeviceGray();//(kCGColorSpaceGenericRGB); if (colorSpace == NULL) { fprintf(stderr, "Error allocating color space\n"); return NULL; } // Allocate memory for image data. This is the destination in memory // where any drawing to the bitmap context will be rendered. bitmapData = malloc( bitmapByteCount ); if (bitmapData == NULL) { fprintf (stderr, "Memory not allocated!"); CGColorSpaceRelease( colorSpace ); return NULL; } // Create the bitmap context. We want pre-multiplied ARGB, 8-bits // per component. Regardless of what the source image format is // (CMYK, Grayscale, and so on) it will be converted over to the format // specified here by CGBitmapContextCreate. context = CGBitmapContextCreate (bitmapData, pixelsWide, pixelsHigh, 8, // bits per component bitmapBytesPerRow, colorSpace, kCGImageAlphaNoneSkipLast); if (context == NULL) { free (bitmapData); fprintf (stderr, "Context not created!"); } // Make sure and release colorspace before returning CGColorSpaceRelease( colorSpace ); return context; } -(void)setPenColor:(unsigned int)value { penColor = value; [self setNeedsDisplay]; } -(void)setPenWidth:(float)value { penWidth = value; [self setNeedsDisplay]; } -(void)setBgColor:(unsigned int)value { bgColor = value; [self setNeedsDisplay]; } - (id)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { // Initialization code //self.backgroundColor = [UIColor groupTableViewBackgroundColor]; self.backgroundColor = [UIColor whiteColor]; self.opaque = YES; self.multipleTouchEnabled = NO; penColor = 0xFF66009A; penWidth = 3.0; bgColor = 0xFFFFFFFF; } mPath = nil; [self doClear]; return self; } // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code CGContextRef context = UIGraphicsGetCurrentContext(); // draw backgound CGContextSetRGBFillColor(context, ((float)((bgColor & 0xFF0000) >> 16))/255.0, ((float)((bgColor & 0xFF00) >> 8))/255.0, ((float)((bgColor & 0xFF)))/255.0, 1); CGContextSetRGBStrokeColor(context, ((float)((penColor & 0xFF0000) >> 16))/255.0, ((float)((penColor & 0xFF00) >> 8))/255.0, ((float)((penColor & 0xFF)))/255.0, 1); CGContextFillRect(context, rect); // draw signature CGContextSetLineWidth(context, penWidth); CGContextBeginPath(context); CGContextClipToRect(context, rect); //CGContextClip(context); CGContextAddPath(context,mPath); CGContextDrawPath(context, kCGPathStroke); } - (UIImage*)makeUIImage { CGRect bound_box = self.bounds; if (!CGPathIsEmpty(mPath)) { bound_box = CGPathGetBoundingBox(mPath); } CGRect rect = self.bounds; if (rect.size.width < (bound_box.origin.x+bound_box.size.width)) { rect.size.width = (bound_box.origin.x+bound_box.size.width)+2; } if (rect.size.height < (bound_box.origin.y+bound_box.size.height)) { rect.size.height = (bound_box.origin.y+bound_box.size.height)+2; } CGContextRef context = [self CreateRGBABitmapContext:rect.size.width height:rect.size.height]; rect.origin.x = 0; rect.origin.y = 0; // draw backgound CGContextSetRGBFillColor(context, ((float)((bgColor & 0xFF0000) >> 16))/255.0, ((float)((bgColor & 0xFF00) >> 8))/255.0, ((float)((bgColor & 0xFF)))/255.0, 1); CGContextSetRGBStrokeColor(context, ((float)((penColor & 0xFF0000) >> 16))/255.0, ((float)((penColor & 0xFF00) >> 8))/255.0, ((float)((penColor & 0xFF)))/255.0, 1); CGContextFillRect(context, rect); // draw signature if (!CGPathIsEmpty(mPath)) { CGContextSetLineWidth(context, penWidth); CGContextTranslateCTM (context, 0, rect.size.height); CGContextScaleCTM(context, 1, -1); CGContextBeginPath(context); CGContextAddPath(context,mPath); CGContextDrawPath(context, kCGPathStroke); } CGImageRef cg_image = CGBitmapContextCreateImage(context); UIImage* ui_image = [[UIImage alloc] initWithCGImage:cg_image];// scale:1 orientation:UIImageOrientationDownMirrored]; CGImageRelease(cg_image); CGContextRelease(context); return ui_image; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSArray *t = [[event allTouches] allObjects]; if ([t count] > 0) { CGPoint cur_point; cur_point.x = [[t objectAtIndex:0] locationInView:self].x; cur_point.y = [[t objectAtIndex:0] locationInView:self].y; CGPathMoveToPoint(mPath, nil, cur_point.x, cur_point.y); mLastPoint = cur_point; } } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { NSArray *t = [[event allTouches] allObjects]; if ([t count] > 0) { CGPoint cur_point; cur_point.x = [[t objectAtIndex:0] locationInView:self].x; cur_point.y = [[t objectAtIndex:0] locationInView:self].y; CGPathAddLineToPoint(mPath, nil, cur_point.x, cur_point.y); CGRect rect; if (cur_point.x < mLastPoint.x) { rect.origin.x = cur_point.x - 2; rect.size.width = mLastPoint.x - cur_point.x + 4; } else { rect.origin.x = mLastPoint.x - 2; rect.size.width = cur_point.x - mLastPoint.x + 4; } if (cur_point.y < mLastPoint.y) { rect.origin.y = cur_point.y - 2; rect.size.height = mLastPoint.y - cur_point.y + 4; } else { rect.origin.y = mLastPoint.y - 2; rect.size.height = cur_point.y - mLastPoint.y + 4; } [self setNeedsDisplayInRect:rect]; mLastPoint = cur_point; } } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [self touchesMoved:touches withEvent:event]; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { } - (void)doClear { if (mPath != nil) [mPath release]; mPath = CGPathCreateMutable(); [self setNeedsDisplay]; } - (void)dealloc { [mPath release]; [super dealloc]; } @end