在上一篇文章中我介绍了 UIBezierPath类 介绍 ,下面这篇文章介绍一下如何通过这个类实现一个简单的随手画画板的简单程序demo,功能包括:划线(可以调整线条粗细,颜色),撤销笔画,回撤笔画,清除画布,橡皮擦。当然也可以扩展其他的功能。

一、首先看看实现划线部分的关键代码吧!

- (void) drawRect: (CGRect) rect
{//绘制图片int width = self.pickedImage.size.width;int height = self.pickedImage.size.height;CGRect rectForImage = CGRectMake(0,0, width, height);[self.pickedImage drawInRect:rectForImage];if (self.arrayStrokes){int arraynum = 0;// each iteration draw a stroke// line segments within a single stroke (path) has the same color and line widthfor (NSDictionary *dictStroke in self.arrayStrokes){NSArray *arrayPointsInstroke = [dictStroke objectForKey:@"points"];UIColor *color = [dictStroke objectForKey:@"color"];float size = [[dictStroke objectForKey:@"size"] floatValue];[color set];     // Sets the color of subsequent stroke and fill operations to the color that the receiver represents.// draw the stroke, line by line, with rounded jointsUIBezierPath* pathLines = [UIBezierPath bezierPath];CGPoint pointStart = CGPointFromString([arrayPointsInstroke objectAtIndex:0]);[pathLines moveToPoint:pointStart];for (int i = 0; i < (arrayPointsInstroke.count - 1); i++){CGPoint pointNext = CGPointFromString([arrayPointsInstroke objectAtIndex:i+1]);[pathLines addLineToPoint:pointNext];}pathLines.lineWidth = size;pathLines.lineJoinStyle = kCGLineJoinRound; //拐角的处理pathLines.lineCapStyle = kCGLineCapRound; //最后点的处理[pathLines stroke];arraynum++;//统计笔画数量}}
}
// Start new dictionary for each touch, with points and color
- (void) touchesBegan:(NSSet *) touches withEvent:(UIEvent *) event
{NSMutableArray *arrayPointsInStroke = [NSMutableArray array]; //点数组,相当于一个笔画NSMutableDictionary *dictStroke = [NSMutableDictionary dictionary];[dictStroke setObject:arrayPointsInStroke forKey:@"points"];[dictStroke setObject:self.currentColor forKey:@"color"];[dictStroke setObject:[NSNumber numberWithFloat:self.currentSize] forKey:@"size"];CGPoint point = [[touches anyObject] locationInView:self];[arrayPointsInStroke addObject:NSStringFromCGPoint(point)];[self.arrayStrokes addObject:dictStroke];//添加的是一个字典:点数组,颜色,粗细
}// Add each point to points array
- (void) touchesMoved:(NSSet *) touches withEvent:(UIEvent *) event
{CGPoint point = [[touches anyObject] locationInView:self];CGPoint prevPoint = [[touches anyObject] previousLocationInView:self];NSMutableArray *arrayPointsInStroke = [[self.arrayStrokes lastObject] objectForKey:@"points"];[arrayPointsInStroke addObject:NSStringFromCGPoint(point)];CGRect rectToRedraw = CGRectMake(\((prevPoint.x>point.x)?point.x:prevPoint.x)-currentSize,\((prevPoint.y>point.y)?point.y:prevPoint.y)-currentSize,\fabs(point.x-prevPoint.x)+2*currentSize,\fabs(point.y-prevPoint.y)+2*currentSize\);//Marks the specified rectangle of the receiver as needing to be redrawn.//在指定的rect范围进行重绘[self setNeedsDisplayInRect:rectToRedraw];//   [self setNeedsDisplay];
}

这里简单的说明介绍吧!

1、使用一个数组 arrayStrokes(称之为笔画数组) 来记录整一幅画,这个数组中保存的是一个个的字典,而这些字典就是这幅画中的每一笔画(而且是有顺序的),字典中有三项内容:包括笔画的size,color还有一个数组arrayPointsInStroke,注意:这个数组保存的touch  begin和move过程中经过的点的坐标(这些点统统用直线连接起来,就可以形成一个笔画了。当然,这个数组中是保存了好多个点的!所以连接起来笔画还是很逼真的!)。

2、那么在绘制的时候,就要用到 arrayStrokes 这个关键的数组了,从里面拿出每一个字典(一个字典就是代表一个笔画),根据字典中笔画的size,color和笔画所经过的点坐标,那么让UIBezierPath这个类来完成笔画的绘制就很简单了。

这样应该可以理解吧!

二、笔画的撤销和回撤的实现

我们知道每一个笔画都是通过一个字典来保存的,那么我们在画线的过程中对笔画的撤销和回撤那也就很简单了吧!

我们可以使用另一个数组 arrayAbandonedStrokes (称之为废弃数组)来保存我们所撤销的笔画,而撤销,肯定是我们所有笔画中的最后一划,所以我们在arrayAbandonedStrokes 废弃数组保存 arrayStrokes 笔画数组中的最后一个元素,同时将 arrayStrokes 笔画数组中的最后一个元素删除。这样就可以实现笔画的撤销。

反之,就是实现回撤了。即将废弃数组中的最后一个元素添加到笔画数组中,同时将废弃数组中的最后一个元素删除。

实现的代码如下:

//撤销
-(IBAction) undo {if ([arrayStrokes count]>0) {NSMutableDictionary* dictAbandonedStroke = [arrayStrokes lastObject];[self.arrayAbandonedStrokes addObject:dictAbandonedStroke];[self.arrayStrokes removeLastObject];[self setNeedsDisplay];}
}//回撤
-(IBAction) redo {if ([arrayAbandonedStrokes count]>0) {NSMutableDictionary* dictReusedStroke = [arrayAbandonedStrokes lastObject];[self.arrayStrokes addObject:dictReusedStroke];[self.arrayAbandonedStrokes removeLastObject];[self setNeedsDisplay];}
}

三、清楚画布的功能实现

//清除画布
-(IBAction) clearCanvas {self.pickedImage = nil;[self.arrayStrokes removeAllObjects];[self.arrayAbandonedStrokes removeAllObjects];[self setNeedsDisplay];
}

四、笔画颜色的选择

这里的处理是用到一个弹出框,点击可以选择颜色。

下面讲一下如何实现这个颜色选择器。其中参考自:点击打开链接

实现原理:弹出框中显示的是一张图片,我们通过一个函数处理,获取到这个图片的所有像素点的透明度和RGB(每一个值占1Byte)数据(是一个数组),然后通过点击获取到点的坐标,就可以获取到这个像素点的透明度和RGB值了。

实现的有关代码如下:

- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {UITouch* touch = [touches anyObject];CGPoint point = [touch locationInView:self.imgView]; //where image was tappedlastColor = [self getPixelColorAtLocation:point];[pickedColorDelegate pickedColor:(UIColor*)lastColor];
}// Please refer to iOS Developer Library for more details regarding the following two methods
- (UIColor*) getPixelColorAtLocation:(CGPoint)point {UIColor* color = nil;CGImageRef inImage = self.imgView.image.CGImage;// Create off screen bitmap context to draw the image into. Format ARGB is 4 bytes for each pixel: Alpa, Red, Green, BlueCGContextRef contexRef = [self createARGBBitmapContext:inImage];if (contexRef == NULL) { return nil; /* error */ }size_t w = CGImageGetWidth(inImage);     // problem!size_t h = CGImageGetHeight(inImage);CGRect rect = {{0,0},{w,h}};// Draw the image to the bitmap context. Once we draw, the memory// allocated for the context for rendering will then contain the// raw image data in the specified color space.CGContextDrawImage(contexRef, rect, inImage);// Now we can get a pointer to the image data associated with the bitmap// context.unsigned char* data = CGBitmapContextGetData (contexRef);if (data != NULL) {//offset locates the pixel in the data from x,y.//4 for 4 bytes of data per pixel, w is width of one row of data.int offset = 4*((w*round(point.y))+round(point.x)); //这是一个二维数组,offset是确定数组下标int alpha =  data[offset];int red = data[offset+1];int green = data[offset+2];int blue = data[offset+3];NSLog(@"offset: %i colors: RGB A %i %i %i  %i",offset,red,green,blue,alpha);color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:(alpha/255.0f)];}// When finished, release the contextCGContextRelease(contexRef);// Free image data memory for the contextif (data) { free(data); }return color;
}- (CGContextRef)  createARGBBitmapContext:(CGImageRef) inImage {CGContextRef    context = NULL;CGColorSpaceRef colorSpace;void *          bitmapData;int             bitmapByteCount;int             bitmapBytesPerRow;// Get image width, height. We'll use the entire image.size_t pixelsWide = CGImageGetWidth(inImage);size_t pixelsHigh = CGImageGetHeight(inImage);// 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 * 4);bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);// Use the generic RGB color space.//colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);  //deprecatedcolorSpace = CGColorSpaceCreateDeviceRGB();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 componentbitmapBytesPerRow,colorSpace,kCGImageAlphaPremultipliedFirst);if (context == NULL){free (bitmapData);fprintf (stderr, "Context not created!");}// Make sure and release colorspace before returningCGColorSpaceRelease( colorSpace );return context;
}

iOS 使用UIBezierPath类实现随手画画板相关推荐

  1. iOS 使用UIBezierPath类实现随手画画板

    在上一篇文章中我介绍了 UIBezierPath类 介绍 ,下面这篇文章介绍一下如何通过这个类实现一个简单的随手画画板的简单程序demo,功能包括:划线(可以调整线条粗细,颜色),撤销笔画,回撤笔画, ...

  2. iOS_24_画画板(含取色板)

    终于效果例如以下: 一.简单说明1.使用一个数组 strokesArr(笔画数组)记录全部笔画.数组中保存的是一个个的笔画字典,一个字典就是一个笔画.笔画字典中有三项:笔画的大小.颜色.pointsA ...

  3. android实现简单的画画板

    画画板实现起来其实很简单,我们只需要利用android给我们提供的Canvas类来操作就可以实现简单的画画功能 直接看代码,注释都写清楚了 public class MainActivity exte ...

  4. ImageView实现画画板的功能

    1,使用虚拟机加载的图片是只读的,不能对其进行其他的操作.这在上一篇文章中已介绍,要想对其进行其他操作,还是同一个方法,就是创建其副本,对副本进行操作. 2,下面通过此知识点,再介绍一个通过Image ...

  5. 学习android 画板源代码,Android实现画画板案例

    郑州app开发画画板案例.布局代码是三个button和一个imagesview下面是图片. 布局代码就不展示了.下面是java代码. package cn.xhhkj.image; import an ...

  6. java线程画动图闪,Android中利用画图类和线程画出闪烁的心形,android心形,package com....

    Android中利用画图类和线程画出闪烁的心形,android心形,package com.package com.tt.view;import android.content.Context;imp ...

  7. Android 实现图片画画板

    本文主要讲述了Android 实现图片画画板 设计项目布局: <RelativeLayout xmlns:android="http://schemas.android.com/apk ...

  8. 电脑PHP动画制作画板,涂鸦板简单实现 Html5编写属于自己的画画板

    这篇文章主要教大家如何使用Html5编写属于自己的画画板,进行绘画.调整颜色等操作,感兴趣的小伙伴们可以参考一下 最近了解到html5强大的绘图功能让我惊奇,于是,写了个小玩意---涂鸦板,能实现功能 ...

  9. 设计模式(二)——UML类图怎么画

    UML类图怎么画 一.注释(comment) 注释就是对类图的补充说明,可以附加在任何元素上,用右上角有折角的矩形来表示,其内放置说明文字,通过虚线连接被注释的元素. 二.类(Class) 在面向对象 ...

最新文章

  1. 腾讯广告广点通API接入文档(Android)
  2. OI模板大全(普及~省选NOI)
  3. 药企信息化项目必经的三步走
  4. 牛客题霸 [括号序列] C++题解/答案
  5. getexternalfilesdir 相册_音乐相册(电子相册制作)V5.2 安卓最新版
  6. 全字符微信名 php,PHP方法处理微信昵称特殊符号过滤
  7. 美甲帮:数加平台打造大数据架构
  8. python中list函数_list()函数以及Python中的示例
  9. ESlint全局安装(安装教程) - cmd篇
  10. java 多线程合并结果集_多线程计算数据,然后合并数据
  11. java 同步块原理_Java同步代码块和同步方法原理与应用案例详解
  12. python︱写markdown一样写网页,代码快速生成web工具:streamlit 展示组件(三)
  13. BZOJ1222: [HNOI2001]产品加工(诡异背包dp)
  14. 如何设置论文目录左对齐?
  15. 图像质量评价(IQA)综述
  16. Poisson方程的五点差分格式例题求解-Matlab实现
  17. 闪耀DTCC | 合作伙伴北京中亦安图倾情加盟 DTCC2018!
  18. 白细胞膜囊泡包裹在金纳米粒表面|DNA纳米结构的细胞膜囊泡|靶向细胞膜的多肽药物外泌体纳米载药
  19. 国内外语音识别行业最全盘点及技术分析和预测
  20. 民航上的第一课和最后一课

热门文章

  1. java文件名特殊符号_linux命令行下文件名中包含特殊符号如何的处理方法
  2. Cifar-10 数据格式分析
  3. VHDL编写8-3线优先编码器
  4. IDEA加速启动配置
  5. Enemy AI Unity2D-小怪在固定范围类进行巡逻
  6. wss和ws协议转换
  7. cnBeta 07年终特稿:年度精彩评论(TOP20)
  8. 【python算法练习】
  9. php 校验 邮政编码,php – 动态邮政编码验证
  10. 神器来袭,手把手教你使用 Milvus_cli