Quartz 2D实现简易画图工具
2018-01-31 本文已影响82人
倪大头
import "DrawView.h"//自定义的类,继承自UIView,作为“画板”界面
DrawView.h:
#import <UIKit/UIKit.h>
@class DrawView;
@protocol drawViewDelegate <NSObject>
- (void)drawViewTouchBegan;
@end
@interface DrawView : UIView
{
CGMutablePathRef path;
NSMutableArray *pathModelArray;//路径保存数组
}
@property (nonatomic,strong)UIColor *lineColor;//线条颜色
@property (nonatomic,assign)CGFloat lineWidth;//线条粗细
@property (nonatomic,assign)BOOL isErase;//是否是橡皮擦模式
@property id<drawViewDelegate>myDelegate;
- (void)undoAction;
- (void)clearAction;
@end
DrawView.m:
#import "DrawView.h"
#import "PathModel.h"//自定义Model类,继承自NSObject,用来存放“画”出的线条
@implementation DrawView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
pathModelArray = [NSMutableArray array];
self.lineColor = [UIColor blackColor];
self.lineWidth = 5.0;
self.backgroundColor = [UIColor clearColor];
self.userInteractionEnabled = YES;
}
return self;
}
- (void)drawRect:(CGRect)rect {
for (PathModel *model in pathModelArray) {//先把数组里的线条画上
//获取图形上下文
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddPath(context, model.path);
if (model.isErase) {//橡皮擦模式
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
[[UIColor clearColor] setStroke];//设置线条颜色
CGContextSetLineWidth(context, 15.0);//设置线条宽度
}else {
[model.color setStroke];
CGContextSetLineWidth(context, model.width);
}
CGContextDrawPath(context, kCGPathStroke);
}
if (path) {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddPath(context, path);
if (self.isErase) {//橡皮擦模式
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
[[UIColor clearColor] setStroke];
CGContextSetLineWidth(context, 15.0);//设置橡皮粗细
}else {
[self.lineColor setStroke];//设置画笔颜色
CGContextSetLineWidth(context, self.lineWidth);//设置画笔粗细
}
CGContextDrawPath(context, kCGPathStroke);
}
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self.myDelegate drawViewTouchBegan];
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self];
//添加初始的点
path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, currentPoint.x, currentPoint.y);
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self];
//添加新的点
CGPathAddLineToPoint(path, NULL, currentPoint.x, currentPoint.y);
//重新绘图
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//保存每一笔线条
PathModel *model = [[PathModel alloc]init];
model.color = self.lineColor;
model.width = self.lineWidth;
model.path = path;
model.isErase = _isErase;
[pathModelArray addObject:model];
CGPathRelease(path);
path = nil;
}
- (void)undoAction {//撤销
[pathModelArray removeLastObject];
[self setNeedsDisplay];
}
- (void)clearAction {//清屏
[pathModelArray removeAllObjects];
[self setNeedsDisplay];
}
@end
PathModel.h:
#import <Foundation/Foundation.h>
@interface PathModel : NSObject
@property (nonatomic,strong)UIColor *color;
@property (nonatomic,assign)CGFloat width;
@property (nonatomic,assign)CGMutablePathRef path;
@property (nonatomic,assign)BOOL isErase;//是否是橡皮擦模式
@end
PathModel.m:
#import "PathModel.h"
@implementation PathModel
- (void)setPath:(CGMutablePathRef)path {
if (_path != path) {
_path = (CGMutablePathRef)CGPathRetain(path);
}
}
- (void)dealloc {
CGPathRelease(self.path);
}
@end
两个自定义类写完了,下面实现画图功能:
#import "DrawView.h"
遵守<drawViewDelegate,UIGestureRecognizerDelegate>协议,drawViewDelegate这个协议只是做一个简单的监听,触发TouchBegan时调用代理方法
- (void)createView {
drawView = [[DrawView alloc]initWithFrame:CGRectMake(0, 64, UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT-64-44)];
drawView.myDelegate = self;
[self.view addSubview:drawView];
//toolbar
[self.navigationController setToolbarHidden:NO animated:YES];
[self.navigationController.toolbar setBarStyle:UIBarStyleDefault];
self.navigationController.toolbar.frame = CGRectMake(0, UI_SCREEN_HEIGHT-44, UI_SCREEN_WIDTH, 44);
UIBarButtonItem *spaceItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *colorItem = [[UIBarButtonItem alloc]initWithTitle:@"颜色" style:UIBarButtonItemStyleDone target:self action:@selector(colorAction)];
UIBarButtonItem *eraseItem = [[UIBarButtonItem alloc]initWithTitle:@"橡皮" style:UIBarButtonItemStyleDone target:self action:@selector(eraserAction)];
UIBarButtonItem *undoItem = [[UIBarButtonItem alloc]initWithTitle:@"撤销" style:UIBarButtonItemStyleDone target:self action:@selector(undoAction)];
UIBarButtonItem *clearItem = [[UIBarButtonItem alloc]initWithTitle:@"清屏" style:UIBarButtonItemStyleDone target:self action:@selector(clearAction)];
self.toolbarItems = @[colorItem,spaceItem,eraseItem,spaceItem,undoItem,spaceItem,clearItem];
}
调色板功能
- (void)colorAction {//调色板
if (!paletteView) {
paletteView = [[UIImageView alloc]initWithFrame:CGRectMake(kScaleX*5, UI_SCREEN_HEIGHT-44-kScaleY*5-kScaleY*296, kScaleX*300, kScaleY*296)];
paletteView.image = [UIImage imageNamed:@"palette"];
[self.view addSubview:paletteView];
UITapGestureRecognizer *paletteViewTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(chooseColor:)];
paletteViewTap.delegate = self;
paletteView.userInteractionEnabled = YES;
[paletteView addGestureRecognizer:paletteViewTap];
}else {
[paletteView removeFromSuperview];
paletteView = nil;
}
}
- (void)chooseColor:(UITapGestureRecognizer *)tap {//选择颜色
CGPoint point = [tap locationInView:paletteView];
if (CGRectContainsPoint(CGRectMake(0.0f, 0.0f, paletteView.image.size.width, paletteView.image.size.height), point)) {
NSInteger pointX = trunc(point.x);
NSInteger pointY = trunc(point.y);
CGImageRef cgImage = paletteView.image.CGImage;
NSUInteger width = paletteView.image.size.width;
NSUInteger height = paletteView.image.size.height;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
int bytesPerPixel = 4;
int bytesPerRow = bytesPerPixel * 1;
NSUInteger bitsPerComponent = 8;
unsigned char pixelData[4] = { 0, 0, 0, 0 };
CGContextRef context = CGBitmapContextCreate(pixelData,
1,
1,
bitsPerComponent,
bytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextTranslateCTM(context, -pointX, pointY-(CGFloat)height);
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), cgImage);
CGContextRelease(context);
CGFloat red = (CGFloat)pixelData[0] / 255.0f;
CGFloat green = (CGFloat)pixelData[1] / 255.0f;
CGFloat blue = (CGFloat)pixelData[2] / 255.0f;
CGFloat alpha = (CGFloat)pixelData[3] / 255.0f;
drawView.isErase = NO;
drawView.lineColor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
NSLog(@"%lf %lf %@",point.x,point.y,drawView.lineColor);
}
}
- (void)drawViewTouchBegan {//DrawView代理方法,关闭调色板
if (paletteView) {
[paletteView removeFromSuperview];
paletteView = nil;
}
}
橡皮、撤销、清屏,都是DrawView类方法:
原理是对存放在PathModel中线条的数组进行修改
- (void)eraserAction {//橡皮
drawView.isErase = YES;
}
- (void)undoAction {//撤销
[drawView undoAction];
}
- (void)clearAction {//清屏
[drawView clearAction];
}