最近要实现一个手写签名功能,要求是,在一定区域绘制文字签名,签名完成后,添加新的水印,并且将图片仅保留签字区域剪切,并且宽度不能大于128,经多方努力,终于完成了,现在上代码,总结一下:
首先,新建单视图项目,然后新建一个继承view的类signatureView,绘制功能和图片的处理就是在该类实现的,该类代码如下:
.h文件
#import <UIKit/UIKit.h>
@protocol GetSignatureImageDele <NSObject>
-(void)getSignatureImg:(UIImage*)image;
@end
@interface signatureView : UIView
{
CGFloat min;
CGFloat max;
CGRect origRect;
CGFloat origionX;
CGFloat totalWidth;
BOOL isSure;
}
//签名完成后的水印文字
@property (strong,nonatomic) NSString *showMessage;
@property(nonatomic,assign)id<GetSignatureImageDele> delegate;
- (void)clear;
- (void)sure;
@end
.m文件
#import "signatureView.h"
#import <QuartzCore/QuartzCore.h>
#define StrWidth 150
#define StrHeight 20
staticCGPoint midpoint(CGPoint p0,CGPoint p1) {
return (CGPoint) {
(p0.x + p1.x) /2.0,
(p0.y + p1.y) /2.0
};
}
@interface signatureView () {
UIBezierPath *path;
CGPoint previousPoint;
}
@end
@implementation signatureView
- (void)commonInit {
path = [UIBezierPathbezierPath];
[pathsetLineWidth:2];
max = 0;
min = 0;
// Capture touches
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizeralloc] initWithTarget:selfaction:@selector(pan:)];
pan.maximumNumberOfTouches = pan.minimumNumberOfTouches =1;
[selfaddGestureRecognizer:pan];
}
-(void)clearPan
{
path = [UIBezierPathbezierPath];
[pathsetLineWidth:3];
[selfsetNeedsDisplay];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [superinitWithCoder:aDecoder]) [selfcommonInit];
return self;
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [superinitWithFrame:frame]) [selfcommonInit];
return self;
}
void ProviderReleaseData (void *info,const void *data,size_t size)
{
free((void*)data);
}
- (UIImage*) imageBlackToTransparent:(UIImage*) image
{
// 分配内存
const int imageWidth = image.size.width;
const int imageHeight = image.size.height;
size_t bytesPerRow = imageWidth * 4;
uint32_t* rgbImageBuf = (uint32_t*)malloc(bytesPerRow * imageHeight);
// 创建context
CGColorSpaceRef colorSpace =CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(rgbImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpace,
kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), image.CGImage);
// 遍历像素
int pixelNum = imageWidth * imageHeight;
uint32_t* pCurPtr = rgbImageBuf;
for (int i =0; i < pixelNum; i++, pCurPtr++)
{
// if ((*pCurPtr & 0xFFFFFF00) == 0) //将黑色变成透明
if (*pCurPtr == 0xffffff)
{
uint8_t* ptr = (uint8_t*)pCurPtr;
ptr[0] =0;
}
//改成下面的代码,会将图片转成灰度
/*uint8_t* ptr = (uint8_t*)pCurPtr;
// gray = red * 0.11 + green * 0.59 + blue * 0.30
uint8_t gray = ptr[3] * 0.11 + ptr[2] * 0.59 + ptr[1] * 0.30;
ptr[3] = gray;
ptr[2] = gray;
ptr[1] = gray;*/
}
// 将内存转成image
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow * imageHeight,ProviderReleaseData);
CGImageRef imageRef = CGImageCreate(imageWidth, imageHeight, 8,32, bytesPerRow, colorSpace,
kCGImageAlphaLast | kCGBitmapByteOrder32Little, dataProvider,
NULL, true,kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);
UIImage* resultUIImage = [UIImageimageWithCGImage:imageRef];
// 释放
CGImageRelease(imageRef);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
// free(rgbImageBuf) 创建dataProvider时已提供释放函数,这里不用free
return resultUIImage;
}
-(void)handelSingleTap:(UITapGestureRecognizer*)tap
{
return [selfimageRepresentation];
}
-(void) imageRepresentation {
if(UIGraphicsBeginImageContextWithOptions !=NULL)
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size,NO, [UIScreenmainScreen].scale);
}else {
UIGraphicsBeginImageContext(self.bounds.size);
}
[self.layerrenderInContext:UIGraphicsGetCurrentContext()];
UIImage *image =UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
image = [selfimageBlackToTransparent:image];
NSLog(@"width:%f,height:%f",image.size.width,image.size.height);
UIImage *img = [selfcutImage:image];
[self.delegategetSignatureImg:[selfscaleToSize:img]];
}
//压缩图片,最长边为128
- (UIImage *)scaleToSize:(UIImage *)img {
CGRect rect ;
CGFloat imageWidth = img.size.width;
//判断图片宽度
if(imageWidth >= 128)
{
rect =CGRectMake(0,0, 128, self.frame.size.height);
}
else
{
rect =CGRectMake(0,0, img.size.width,self.frame.size.height);
}
CGSize size = rect.size;
UIGraphicsBeginImageContext(size);
[imgdrawInRect:rect];
UIImage* scaledImage =UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(scaledImage,nil, nil, nil);
[selfsetNeedsDisplay];
return scaledImage;
}
//只截取签名部分图片
- (UIImage *)cutImage:(UIImage *)image
{
CGRect rect ;
//签名事件没有发生
if(min == 0&&max == 0)
{
rect =CGRectMake(0,0, 0, 0);
}
else//签名发生
{
rect =CGRectMake(min-3,0, max-min+6,self.frame.size.height);
}
CGImageRef imageRef =CGImageCreateWithImageInRect([image CGImage], rect);
UIImage * img = [UIImageimageWithCGImage:imageRef];
UIImage *lastImage = [selfaddText:img text:self.showMessage];
[selfsetNeedsDisplay];
return lastImage;
}
//签名完成,给签名照添加新的水印
- (UIImage *) addText:(UIImage *)img text:(NSString *)mark {
int w = img.size.width;
int h = img.size.height;
//根据截取图片大小改变文字大小
CGFloat size = 20;
UIFont *textFont = [UIFontsystemFontOfSize:size];
CGSize sizeOfTxt = [mark sizeWithFont:textFont constrainedToSize:CGSizeMake(128,30)];
if(w<sizeOfTxt.width)
{
while (sizeOfTxt.width>w) {
size --;
textFont = [UIFontsystemFontOfSize:size];
sizeOfTxt = [marksizeWithFont:textFont constrainedToSize:CGSizeMake(128,30)];
}
}
else
{
size =45;
textFont = [UIFontsystemFontOfSize:size];
sizeOfTxt = [marksizeWithFont:textFont constrainedToSize:CGSizeMake(self.frame.size.width,30)];
while (sizeOfTxt.width>w) {
size ++;
textFont = [UIFontsystemFontOfSize:size];
sizeOfTxt = [marksizeWithFont:textFont constrainedToSize:CGSizeMake(self.frame.size.width,30)];
}
}
UIGraphicsBeginImageContext(img.size);
[[UIColorredColor] set];
[imgdrawInRect:CGRectMake(0,0, w, h)];
[markdrawInRect:CGRectMake((w-sizeOfTxt.width)/2,(h-sizeOfTxt.height)/2, sizeOfTxt.width, sizeOfTxt.height)withFont:textFont];
UIImage *aimg =UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return aimg;
}
- (void)pan:(UIPanGestureRecognizer *)pan {
CGPoint currentPoint = [pan locationInView:self];
CGPoint midPoint = midpoint(previousPoint, currentPoint);
NSLog(@"获取到的触摸点的位置为--currentPoint:%@",NSStringFromCGPoint(currentPoint));
CGFloat viewHeight = self.frame.size.height;
CGFloat currentY = currentPoint.y;
if (pan.state ==UIGestureRecognizerStateBegan) {
[pathmoveToPoint:currentPoint];
} elseif (pan.state ==UIGestureRecognizerStateChanged) {
[pathaddQuadCurveToPoint:midPoint controlPoint:previousPoint];
}
if(0 <= currentY && currentY <= viewHeight)
{
if(max == 0&&min == 0)
{
max = currentPoint.x;
min = currentPoint.x;
}
else
{
if(max <= currentPoint.x)
{
max = currentPoint.x;
}
if(min>=currentPoint.x)
{
min = currentPoint.x;
}
}
}
previousPoint = currentPoint;
[selfsetNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
self.backgroundColor = [UIColorwhiteColor];
[[UIColorblackColor] setStroke];
[pathstroke];
self.layer.cornerRadius =5.0;
self.clipsToBounds =YES;
self.layer.borderWidth =0.5;
self.layer.borderColor = [[UIColorgrayColor] CGColor];
CGContextRef context =UIGraphicsGetCurrentContext();
if(!isSure)
{
NSString *str = @"请绘制签名";
CGContextSetRGBFillColor (context, 108/255, 108/255,108/255, 0.3);//设置填充颜色
CGRect rect1 = CGRectMake((rect.size.width -StrWidth)/2, (rect.size.height -StrHeight)/2-5,StrWidth, StrHeight);
origionX = rect1.origin.x;
totalWidth = rect1.origin.x+StrWidth;
UIFont *font = [UIFontsystemFontOfSize:25];//设置字体
[strdrawInRect:rect1 withFont:font];
}
else
{
isSure = NO;
}
}
- (void)clear
{
max = 0;
min = 0;
path = [UIBezierPathbezierPath];
[pathsetLineWidth:2];
[selfsetNeedsDisplay];
}
- (void)sure
{
//没有签名发生时
if(min == 0&&max == 0)
{
min = 0;
max = 0;
}
isSure = YES;
[selfsetNeedsDisplay];
return [selfimageRepresentation];
}
@end
其中有两个方法过期了
替换方法:
1:
NSDictionary *attribute = @{NSFontAttributeName:textFont};
CGSize sizeOfTxt = [str boundingRectWithSize:size options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attribute context:nil].size;
2:
[mark drawInRect:CGRectMake((w-sizeOfTxt.width)/2,(h-sizeOfTxt.height)/2, sizeOfTxt.width, sizeOfTxt.height) withAttributes:@{NSFontAttributeName:textFont}];
在根视图viewController里面代码如下:
.h文件
#import <UIKit/UIKit.h>
#import "signatureView.h"
@interface ViewController :UIViewController<GetSignatureImageDele>
{
UIImage *saveImage;
UIView *saveView;
}
@property (strong,nonatomic) signatureView *signatureView;
@end
.m文件
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
self.view.backgroundColor = [UIColorgrayColor];
self.signatureView = [[signatureViewalloc] initWithFrame:CGRectMake(10,70, 300, 100)];
self.signatureView.backgroundColor = [UIColorwhiteColor];
self.signatureView.delegate =self;
self.signatureView.showMessage =@"完成";
[self.viewaddSubview:self.signatureView];
UIButton *button = [UIButtonbuttonWithType:UIButtonTypeCustom];
[button setTitle:@"重签"forState:UIControlStateNormal];
[button setTitleColor:[UIColorcolorWithHue:72saturation:106brightness:123alpha:0.7]forState:UIControlStateNormal];
[buttonsetFrame:CGRectMake(20,self.signatureView.frame.origin.y+120,130, 40)];
button.layer.cornerRadius =5.0;
button.clipsToBounds =YES;
button.layer.borderWidth =1.0;
button.titleLabel.font = [UIFontsystemFontOfSize:17];
button.layer.borderColor = [[UIColorblackColor]CGColor];
[button addTarget:selfaction:@selector(clear:)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:button];
UIButton *button2 = [UIButtonbuttonWithType:UIButtonTypeCustom];
[button2 setTitle:@"确认"forState:UIControlStateNormal];
[button2 setTitleColor:[UIColorwhiteColor] forState:UIControlStateNormal];
button2.titleLabel.font = [UIFontsystemFontOfSize:17];
button2.backgroundColor = [UIColorblueColor];
[button2setFrame:CGRectMake(170,self.signatureView.frame.origin.y+120,130, 40)];
button2.layer.cornerRadius =5.0;
button2.clipsToBounds =YES;
[button2 addTarget:selfaction:@selector(add:)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:button2];
saveView = [[UIViewalloc] initWithFrame:CGRectMake(10, button2.frame
.origin.y+60,300, 140)];
saveView.backgroundColor = [UIColorlightGrayColor];
[self.viewaddSubview:saveView];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)add:(UIButton *)sender
{
[self.signatureViewsure];
}
- (void)clear:(UIButton *)sender
{
NSLog(@"重签");
[self.signatureViewclear];
for(UIView *viewin saveView.subviews)
{
[view removeFromSuperview];
}
}
-(void)getSignatureImg:(UIImage*)image
{
if(image)
{
NSLog(@"haveImage");
UIImageView *image1 = [[UIImageViewalloc] initWithImage:image];
image1.frame =CGRectMake((saveView.frame.size.width-image.size.width)/2, (saveView.frame.size.height-image.size.height)/2, image.size.width, image.size.height) ;
[saveViewaddSubview:image1];
saveImage = image;
[selfsaveImage:saveImage];
//[self makeUpLoad];
}
else
{
NSLog(@"NoImage");
}
}
//图片保存到本地
- (void)saveImage:(UIImage *)image
{
//设置图片名
NSDateFormatter *dateFormatter = [[NSDateFormatteralloc] init];
[dateFormattersetDateFormat:@"yyyyMMdd"];
NSString *currentDateStr = [dateFormatter stringFromDate:[NSDate date]];
NSString *dateStr = [NSStringstringWithFormat:@"%@.png",currentDateStr];
NSString *path = [NSTemporaryDirectory()stringByAppendingFormat:@"%@",dateStr];
BOOL existed = [[NSFileManagerdefaultManager] fileExistsAtPath:pathisDirectory:nil];
if ( existed )
{
[[NSFileManagerdefaultManager] removeItemAtPath:patherror:nil];
}
//NSData *imgData = UIImageJPEGRepresentation(image, 1);
NSData *imgData = UIImagePNGRepresentation(image);
[imgDatawriteToFile:path atomically:YES];
}
- (void)didReceiveMemoryWarning {
[superdidReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
效果图: