IOS:手写签名的实现(实现了手势绘制字体,添加文字水印,图片剪切、图片压缩)

    最近要实现一个手写签名功能,要求是,在一定区域绘制文字签名,签名完成后,添加新的水印,并且将图片仅保留签字区域剪切,并且宽度不能大于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


在根视图viewController里面代码如下:

 .h文件 

#import <UIKit/UIKit.h>

#import "signatureView.h"

@interface ViewController :UIViewController<GetSignatureImageDele>

{

   UIImage *saveImage;

   UIView *saveView;

}

@property (strong,nonatomic) signatureView *signatureView;

@end


.h文件 

@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);

    [imgDatawriteToFile:path atomically:YES];

    

}


- (void)didReceiveMemoryWarning {

    [superdidReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}



效果图:







  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
引用\[2\]中提到,使用std::ios::ate打开文件时,文件指针会定位到文件末尾。然而,如果不配合std::ios::in模式,即只使用std::ios::ate和std::ios::out模式打开文件,会清空原文件。所以,std::ios::ate并不能实现追加写入的功能。如果想要实现追加写入,可以使用std::ios::app模式打开文件,这样写入的内容会被追加到文件末尾。 #### 引用[.reference_title] - *1* [C++ 文件读写操作std::ofstream和std::ifstream](https://blog.csdn.net/block999123/article/details/121869208)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [ofstream之ios::ate,ios::app,ios::in,ios::out](https://blog.csdn.net/cabbage2008/article/details/53307409)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [std::ifstream是C++标准库中的一个输入文件流类,它提供了一组函数来读取文件中的数据](https://blog.csdn.net/m0_46661183/article/details/130769483)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值