iOS笔记053- Quartz2D-练习

1、水印处理

给图片添加文字、图片水印 

    // 水印处理

    - (void)shuiyin

    {

        // 水印处理

        UIImage *image  = [UIImage imageNamed:@"4"];

        UIImage *image2  = [UIImage imageNamed:@"010"];

        

        CGFloat imageH = image.size.height;

        CGFloat imageW = image.size.width;

        // 获取位图上下文

        UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);

        

        // 绘制图形或者文字

        [image drawAtPoint:CGPointZero];

        NSString *str = @"@zhang@163.com";

        CGFloat strlenth = str.length * 8;

        // 文字水印

        [str drawAtPoint:CGPointMake(imageW - strlenth, imageH - 44) withAttributes:nil];

        // 图片水印

        [image2 drawAtPoint:CGPointMake(imageW - strlenth - 66, imageH - 66)];

        // 关闭位图上下文

        UIGraphicsEndPDFContext();

        // 获取位图

        _imageView.image = UIGraphicsGetImageFromCurrentImageContext();

        // 保存图片,需要转换成二进制数据

        NSData *data = UIImageJPEGRepresentation(_imageView.image, 1); // 参数2表示图片质量

        NSData *data1 = UIImagePNGRepresentation(_imageView.image); // png默认最高质量

        // 写入文件

        [data1 writeToFile:@"/Users/song/Desktop/me.png"atomically:YES];

    }

屏幕快照 2015 06 21 17 44 27

2、图形裁切

首先设置一个裁切区域,然后在裁切区域显示图片。 

    // 图形裁切

    - (void)clipImage

    {

        // 获取图片

        UIImage *image = [UIImage imageNamed:@"4"];

        

        // 获取位图上下文

        UIGraphicsBeginImageContextWithOptions(image.size,NO,0.0);

        // 设置圆形裁剪区域,正切与图片

        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, image.size.width, image.size.height)];

        // 添加裁切区域

        [path addClip];

        // 绘制图片

        [ima drawAtPoint:CGPointZero];

        // 从上下文获取图片

        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

        // 关闭位图上下文

        UIGraphicsEndImageContext();

        // 显示位图

        _imageView.image = image;

    }

屏幕快照 2015 06 21 18 22 15

带边框的圆形裁切

首先绘制一个红色的圆,然后在圆中心绘制图片,保留一定的边框。

    // 带边框的原型裁切

    - (void)cicleAroundImage

    {

        // 1、绘制一个大圆,设置背景色

        // 获取图片

        UIImage *ima = [UIImage imageNamed:@"4"];

        // 图片宽高

        CGFloat imageW = ima.size.width;

        // 边界宽度

        CGFloat boarder = 3;

        // 圆环宽高

        CGFloat cicleW = imageW + 2 * boarder;

        

        // 获取位图上下文

        UIGraphicsBeginImageContextWithOptions(CGSizeMake(cicleW, cicleW),NO,0.0);

        // 绘制圆形

        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, cicleW, cicleW)];

        // 填充红色

        [[UIColor redColor] set];

        [path fill];

        

        // 2、绘制图片,要比大圆小一点

        UIBezierPath *clipArea = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(boarder , boarder, imageW, imageW)];

        // 裁切

        [clipArea addClip];

        // 绘制图片

        [ima drawAtPoint:CGPointMake(boarder, boarder)];

        // 从上下文获取图片

         UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

         // 关闭位图上下文

         UIGraphicsEndImageContext();

         // 显示位图

         _imageView.image = image;

    }

屏幕快照 2015 06 21 20 03 00

带有边框的裁切可以使用一个分类 

    #import "UIImage+image.h"

 

    @implementation UIImage (image)

 

    + (instancetype) imageWithImage:(UIImage *)image withBoard:(CGFloat )board withColor:(UIColor *)color

    {

        // 1、绘制一个大圆,设置背景色

        // 获取图片

        UIImage *ima = image;

        // 图片宽高

        CGFloat imageW = ima.size.width;

        // 边界宽度

        CGFloat boarder = board;

        // 圆环宽高

        CGFloat cicleW = imageW + 2 * boarder;

        

        // 获取位图上下文

        UIGraphicsBeginImageContextWithOptions(CGSizeMake(cicleW, cicleW),NO,0.0);

        // 绘制圆形

        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, cicleW, cicleW)];

        // 填充红色

        [color set];

        [path fill];

        

        // 2、绘制图片,要比大圆小一点

        UIBezierPath *clipArea = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(boarder , boarder, imageW, imageW)];

        // 裁切

        [clipArea addClip];

        // 绘制图片

        [ima drawAtPoint:CGPointMake(boarder, boarder)];

        // 从上下文获取图片

        UIImage *clipImage = UIGraphicsGetImageFromCurrentImageContext();

        // 关闭位图上下文

        UIGraphicsEndImageContext();

        // 显示位图

        return clipImage;

    }

    @end

 

使用起来也方便,直接包含头文件即可使用

 

    #import "ViewController.h"

    #import "UIImage+image.h"

 

    @interfaceViewController ()

    @property (weak, nonatomic) IBOutletUIImageView *imageView;

 

    @end

 

    @implementation ViewController

 

    - (void)viewDidLoad {

        [super viewDidLoad];

        // 使用分类

        UIImage *ima = [UIImage imageWithImage:[UIImage imageNamed:@"4"] withBoard:3 withColor:[UIColor blueColor]];

        _imageView.image = ima;

    }

3、屏幕截图

主要是从控制器上获取图层。一定要使用 renderInContext: 进行渲染,不可使用draw...

    // 屏幕截图

    - (void)snipImage

    {

        //获取位图上下文

        UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);

        // 获取当前上下文

        CGContextRef ctx = UIGraphicsGetCurrentContext();

        // 渲染控制器图层到图形上下文,把控件上的图层渲染到上下文,layer只能渲染

        [self.view.layer renderInContext:ctx];

        // 获取图形上下文

        UIImage *snipImage = UIGraphicsGetImageFromCurrentImageContext();

        // 关闭位图上下文

        UIGraphicsEndImageContext();

        NSData *data = UIImagePNGRepresentation(snipImage);

        [data writeToFile:@"/Users/song/Desktop/snip.png"atomically:YES];

    }

Snip

4、手势解锁

效果

 

4.1、界面

在storyboard里添加一个view用来显示九宫格

屏幕快照 2015 06 21 22 37 35

4.2、新建一个类继承自UIView

添加按钮

    // 添加按钮

    - (void)awakeFromNib

    {

        [super awakeFromNib];

        // 创建按钮

        for (NSInteger i = 0;  i < 9; i ++)

        {

            UIButton *btn = [UIButtonbuttonWithType:UIButtonTypeCustom];

            

            [btn setBackgroundImage:[UIImageimageNamed:@"gesture_node_normal"] forState:UIControlStateNormal];

            [btn setBackgroundImage:[UIImageimageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected];

            btn.userInteractionEnabled = NO;

            btn.tag = i;

            [self addSubview:btn];

            

        }

    }

设置按钮frame

    // 九宫格按钮计算

    - (void)layoutSubviews

    {

        [super layoutSubviews];

        // 按钮个数

        NSInteger count = self.subviews.count;

        // 按钮宽度和高度

        CGFloat x = 0;

        CGFloat y = 0;

        CGFloat w = 74;

        CGFloat h = 74;

        //

        NSInteger cols = 3;

        //

        NSInteger rows = 3;

        // 间距

        CGFloat margin = (self.bounds.size.width - cols * w)/(cols + 1);

        // 设置frame

        for (NSInteger i = 0;  i < count; i ++)

        {

            UIButton *btn = (UIButton *)self.subviews[i];

            // 当前行

            NSInteger row = i / rows;

            // 当前列

            NSInteger col = i % cols;

            // x

            x = margin + col * (margin + w);

            // y

            y = row * (margin + h);

            btn.frame = CGRectMake(x, y, w, h);

        }

    }

定义一个可变数组用来保存选中按钮

@property (nonatomic,strong) NSMutableArray *selectedBtn;

 

- (NSMutableArray *)selectedBtn

{

    if (_selectedBtn == nil) {

        _selectedBtn = [NSMutableArray array];

    }

    return  _selectedBtn;

}

实现滑动手势方法 

- (IBAction)pan:(UIPanGestureRecognizer *)sender {

//    NSLog(@"pan");

    // 获取触摸点

    _curP = [sender locationInView:self];

    // 遍历按钮数组

    for (UIButton *btn in self.subviews) {

        // 判断点是否包含在按钮中

        if (CGRectContainsPoint(btn.frame, _curP) && !btn.selected ) {

            btn.selected = YES;

            [self.selectedBtn addObject:btn];

        }

    }

    // 重绘

    [self setNeedsDisplay];

    

    // 恢复原状

    if (sender.state == UIGestureRecognizerStateEnded ) {

        

        // 保存密码

        NSMutableString *str = [NSMutableStringstring];

        for (UIButton *btn in self.selectedBtn) {

           [ str appendFormat:@"%ld",btn.tag ];

        }

        NSLog(@"%@",str);

        // 删除选中状态

        [self.selectedBtn makeObjectsPerformSelector:@selector(setSelected:) withObject:@(NO)];

        // 情况选中数组

        [self.selectedBtn removeAllObjects];

    }

}

 然后在drawRect中进行连线

- (void)drawRect:(CGRect)rect

{

    // 没有选中按钮,直接退出

    if (self.selectedBtn.count == 0) {

        return;

    }

    

    // 把所有选中的按钮连线

    NSInteger count = self.selectedBtn.count;

    UIBezierPath *path = [UIBezierPathbezierPath];

    // 遍历选中按钮数组,对按钮连线

    for (int i = 0 ; i < count ; i ++)  {

        UIButton *btn = self.selectedBtn[i];

        if (i == 0) {

            // 设置起点

            [path moveToPoint:btn.center];

        }else

        {

            [path addLineToPoint:btn.center];

        }

    }

    

    // 连接到当前点

    [path addLineToPoint:_curP];

    // 设置连线样式

    [[UIColorgreenColor] set];

    path.lineWidth = 10;

    path.lineJoinStyle = kCGLineJoinRound;

    [path stroke];

}

5、画板

5.1、通过自动布局搭建界面

屏幕快照 2015 06 22 10 30 13

5.2、在自定义view中得实现

屏幕快照 2015 06 22 17 21 39

使用滑动手势进行画线

自定义一个继承自UIBezierPath 的类,用来改变线条的颜色,只需添加一个属性即可

#import <UIKit/UIKit.h>

 

@interface drawPath : UIBezierPath

@property (nonatomic,strong) UIColor *lineColor;

@end

自定义一个view封装画板的操作 DrawView

#import <UIKit/UIKit.h>

@classdrawPath;

 

@interface DrawView : UIView

 

@property (nonatomic, strong) UIColor *lineColor; // 线条颜色

@property (nonatomic,assign) CGFloat lineWidth; // 线条宽度

@property (nonatomic,strong) UIImage *image; // 保存加载的图片

 

- (void)eraseScreen; // 清屏

- (void)undo; // 撤销

@end

 

类扩展中添加两个属性

#import "DrawView.h"

#import "drawPath.h"

 

@interfaceDrawView ()

 

@property (nonatomic,strong) drawPath *path; // 绘图路径

 

@property (nonatomic,strong) NSMutableArray *drawLines; // 路径数组

@end

 

// 数组懒加载

- (NSMutableArray *)drawLines

{

    if (_drawLines == nil) {

        _drawLines = [NSMutableArray array];

    }

    return  _drawLines;

}

初始化方法

- (void)setUp

{

    // 设置手势

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];

    

    [selfaddGestureRecognizer:pan];

    

    _lineColor = [UIColor blackColor];

    _lineWidth = 1;

}

手势实现

- (void)pan:(UIPanGestureRecognizer *)pan

{

    // 获取当前点

    CGPoint curPoint = [pan locationInView:self];

    if (pan.state == UIGestureRecognizerStateBegan)

    {

        // 设置起点

        _path = [[drawPath alloc] init];

        _path.lineColor = _lineColor;

        _path.lineWidth = _lineWidth;

        

        [_path moveToPoint:curPoint];

        // 保存路径

        [self.drawLines addObject:_path];

    }

    // 绘制

    [_path addLineToPoint:curPoint];

    // 重绘

    [self setNeedsDisplay];

}

重写的构造方法

// xib调用

- (void)awakeFromNib

{

    [self setUp];

 

}

// 代码调用

- (instancetype)initWithFrame:(CGRect)frame

{

    if (self = [super initWithFrame:frame]) {

        [self setUp];

    }

    returnself;

}

drawRect 绘制图片

// 清空屏幕

- (void)drawRect:(CGRect)rect

{

    for (drawPath *path  in self.drawLines) {

        // 判断是不是图片

        if ([path isKindOfClass:[UIImage class]]) {

            // 绘制图片

            UIImage *image = (UIImage *)path;

            [image drawInRect:rect];

        }

        // 不是图片就画线

        else

        {

            [path.lineColor set];

            [path stroke];

        }

    }

}

 其他方法实现

// 清屏

- (void)eraseScreen

{

    [self.drawLines removeAllObjects];

    [self setNeedsDisplay];

}

// 撤销

- (void)undo

{

    [self.drawLines removeLastObject];

    [self setNeedsDisplay];

}

// setter 方法,传入照片时进行刷新

- (void)setImage:(UIImage *)image

{

    _image = image;

    // 添加图片到绘图数组

    [self.drawLinesaddObject:_image];

    

    [selfsetNeedsDisplay];

}

5.3、在控制器中实现

添加两个属性,imageView位于DrawView下面

屏幕快照 2015 06 22 17 51 33

@property (nonatomic,strong) IBOutlet DrawView *drawView; // 绘图面板

@property (weak, nonatomic) IBOutlet UIImageView *imageView; // 加载的图片显示面板

工具栏:通过拖线的方式创建一个方法

// 清屏

- (IBAction)eraseScreen:(UIBarButtonItem *)sender {

    [_drawView eraseScreen];

}

// 撤销

- (IBAction)undo:(id)sender {

    [_drawView undo];

}

// 橡皮擦

- (IBAction)eraser:(UIBarButtonItem *)sender {

    if ([sender.title isEqualToString:@"橡皮擦"]) {

        sender.title  = @"绘图";

        _drawView.lineColor = [UIColor whiteColor];

        _drawView.lineWidth = 5;

    }

    else if ([sender.title isEqualToString:@"绘图"]) {

        sender.title  = @"橡皮擦";

        _drawView.lineColor = [UIColor blackColor];

        _drawView.lineWidth = 1;

    }

 

}

 

// 保存图片到相册

- (IBAction)save:(id)sender {

    

     // 开启上下文

    UIGraphicsBeginImageContextWithOptions(self.drawView.bounds.size, NO, 0);

    // 获取上下文

    CGContextRef ref = UIGraphicsGetCurrentContext();

    // 渲染控制器到上下文

    [self.drawView.layerrenderInContext:ref];

    

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    

    // 关闭上下文

    UIGraphicsEndImageContext();

    

    

    // 保存画板的内容放入相册

    // image:写入的图片

    // completionTarget图片保存监听者

    // 注意:以后写入相册方法中,想要监听图片有没有保存完成,保存完成的方法不能随意乱写,必须传入这个方法didFinishSavingWithError

    UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);

    // 保存到桌面

//    NSData *data = UIImagePNGRepresentation(image);

//    [data writeToFile:@"/Users/song/Desktop/sss.png" atomically:YES];

    

}

// 监听保存完成,必须实现这个方法

- (void)image: (UIImage *) image didFinishSavingWithError: (NSError *) error contextInfo: (void *) contextInfo

{

    NSLog(@"图片保存成功");

}

加载图片:图片控制器

// 从相册加载一张图片

- (IBAction)photo:(id)sender {

    // 初始化图片控制器

    UIImagePickerController *pick = [[UIImagePickerController alloc] init];

    // 设置路径

    // 设置选择控制器的来源

    // UIImagePickerControllerSourceTypePhotoLibrary 相册集

    // UIImagePickerControllerSourceTypeSavedPhotosAlbum:照片库

    pick.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;

    

    // 设置代理

    pick.delegate = self;

    

    // modal 方式弹出图片控制器

    [selfpresentViewController:pick animated:YEScompletion:nil];

}

// 图片代理

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info

{

    // 获取选中的图片

    UIImage *image = info[@"UIImagePickerControllerOriginalImage"];

    NSLog(@"%@",image);

    self.imageView.alpha = 1; // 可见

    self.imageView.userInteractionEnabled = YES; // 设置交互

    self.imageView.image = image;

    [self addGestures]; // 添加手势

 

    // 退出控制器

    [self dismissViewControllerAnimated:YES completion: nil];

}

添加各种手势

- (void)addGestures

{

    // 滑动

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];

     pan.delegate = self;

    [self.imageViewaddGestureRecognizer:pan];

    // 旋转

    UIRotationGestureRecognizer *rotate = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotate:)];

    rotate.delegate = self;

    [self.imageViewaddGestureRecognizer:rotate];

    

    // 捏合

    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)];

    pinch.delegate = self;

    [self.imageViewaddGestureRecognizer:pinch];

    

    // 长按

    UILongPressGestureRecognizer *lPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(lPress:)];

    [self.imageViewaddGestureRecognizer:lPress];

    

    // 点按

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];

    [self.imageViewaddGestureRecognizer:tap];

}

 

// 同一时刻运行响应多个手势

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer

{

    return YES;

}

 

- (void)pan:(UIPanGestureRecognizer *)pan

{

    CGPoint curP = [pan translationInView:self.imageView];

    

    self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, curP.x, curP.y);

    // 复位

    [pan setTranslation:CGPointZeroinView:self.imageView];

}

- (void)pinch:(UIPinchGestureRecognizer *)pinch

{

    CGFloat scale = pinch.scale;

    self.imageView.transform = CGAffineTransformScale(self.imageView.transform, scale, scale);

    // 复位

    pinch.scale = 1;

}

- (void)tap:(UITapGestureRecognizer *)tap

{

    

}

- (void)lPress:(UILongPressGestureRecognizer *)lPress

{

    // 截取图片到绘图面板

    if (lPress.state == UIGestureRecognizerStateBegan)  {

        

         [UIViewanimateWithDuration:0.25animations:^{

             self.imageView.alpha = 0.5;

         } completion:^(BOOL finished) {

            [UIViewanimateWithDuration:0.25animations:^{

                self.imageView.alpha = 1;

            } completion:^(BOOL finished) {

                // 截屏,使用之前定义的分类,包含头文件即可使用

                UIImage *image = [UIImage imageWithSnipView:self.drawView];

                

                self.imageView.alpha = 0;

                _drawView.image = image; // 显示图片到绘图面板

                

            }];

         }];

    }

}

- (void)rotate:(UIRotationGestureRecognizer *)rotate

{

    CGFloat rotation = rotate.rotation;

    self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, rotation);

    // 复位

    rotate.rotation = 0;

}

线条颜色和宽度设置

- (IBAction)colorChange:(UIButton *)sender {

    _drawView.lineColor = sender.backgroundColor;

}

- (IBAction)valueChange:(UISlider *)sender {

    _drawView.lineWidth = sender.value * 10;

}

效果

 

原文地址:https://www.cnblogs.com/songliquan/p/4593601.html