终于效果例如以下:
一、简单说明
1、使用一个数组 strokesArr(笔画数组)记录全部笔画。数组中保存的是一个个的笔画字典,一个字典就是一个笔画。笔画字典中有三项:笔画的大小、颜色、pointsArrInOneStroke数组,(保存的是touch begin时的落笔点和touch move过程中经过的点) 2、绘制的时候,从strokesArr(笔画数组)里取出每个字典(一个字典就是一个笔画)。依据字典中笔画的大小、颜色、笔画所经过的点坐标(pointsArrInOneStroke数组)。使用UIBezierPath类完毕笔画绘制 二、撤销和回撤
一个笔画就是一个字典。
撤销:
使用abandonedStrokesArr (被丢弃的笔画数组)保存要撤销的笔画,即全部笔画数组中的最后一划,
同一时候将 strokesArr 笔画数组中的最后一个元素删除。
反之,重做:
即将abandonedStrokesArr (被丢弃的笔画数组)中最后一个元素加入到全部笔画数组中,同一时候将(被丢弃的笔画数组)中的最后一个元素删除。
Main.storyboard
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJlX2VtaW5lbnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
主控制器
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJlX2VtaW5lbnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
Canvas类封装了画画的全部核心代码
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJlX2VtaW5lbnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
方法列表
//
// Canvas.h
// 24_Canvas画画板
//
// Created by beyond on 14-8-26.
// Copyright (c) 2014年 com.beyond. All rights reserved.
/*
一、简单说明
1、使用一个数组 strokesArr(笔画数组)记录全部笔画。数组中保存的是一个个的笔画字典,一个字典就是一个笔画,笔画字典中有三项:笔画的大小、颜色、pointsArrInOneStroke数组。(保存的是touch begin时的落笔点和touch move过程中经过的点) 2、绘制的时候,从strokesArr(笔画数组)里取出每个字典(一个字典就是一个笔画)。依据字典中笔画的大小、颜色、笔画所经过的点坐标(pointsArrInOneStroke数组)。使用UIBezierPath类完毕笔画绘制 二、撤销和回撤
一个笔画就是一个字典。 撤销:
使用abandonedStrokesArr (被丢弃的笔画数组)保存要撤销的笔画。即全部笔画数组中的最后一划,
同一时候将 strokesArr 笔画数组中的最后一个元素删除。
反之。重做:
即将abandonedStrokesArr (被丢弃的笔画数组)中最后一个元素加入到全部笔画数组中,同一时候将(被丢弃的笔画数组)中的最后一个元素删除。
*/ #import <UIKit/UIKit.h>
// 自己定义的颜色选择控制器,点击之后,它会告诉代理,选中了什么颜色
@class ColorPickerController; @interface Canvas : UIView
#pragma mark - 属性列表
// 标签,显示笔刷大小
@property (nonatomic,retain) IBOutlet UILabel *labelSize;
// 滑块 笔刷大小
@property (nonatomic,retain) IBOutlet UISlider *sliderSize;
// 三个button,各自是撤销、重做、清除
@property (nonatomic,retain) IBOutlet UIBarButtonItem *undoBtn;
@property (nonatomic,retain) IBOutlet UIBarButtonItem *redoBtn;
@property (nonatomic,retain) IBOutlet UIBarButtonItem *clearBtn;
// toolBar,目的是截图的时候,隐藏掉toolBar
@property (nonatomic,retain) IBOutlet UIToolbar *toolBar; #pragma mark - 方法列表
// 初始化全部的准备工作
-(void) viewJustLoaded;
// 选择相冊 被点击
-(IBAction) didClickChoosePhoto;
// 滑块滑动,设置笔刷大小
-(IBAction) setBrushSize:(UISlider*)sender;
// 撤销 被点击
-(IBAction) undo;
// 重做 被点击
-(IBAction) redo;
// 清除画布 被点击
-(IBAction) clearCanvas;
// 保存图片 被点击
-(IBAction) savePic;
// 颜色选择 被点击
- (IBAction) didClickColorButton;
// 重要~~开放给还有一个控制器调用,它在调用代理时,会传入參数:即选择好的颜色
- (void) pickedColor:(UIColor*)color;
@end
核心代码
//
// Canvas.h
// 24_Canvas画画板
//
// Created by beyond on 14-8-26.
// Copyright (c) 2014年 com.beyond. All rights reserved.
/* 这儿仅仅是做演示demo。直接让Canvas与控制器绑定,開始画画,监听事件 假设,要更好的抽取出来,则须要创建一个模型类(model)来提供数据源(比方_strokesArr,_abandonedStrokesArr),供CanvasView显示 UIView的setNeedsDisplay和setNeedsLayout方法
首先两个方法都是异步运行的。 而setNeedsDisplay会调用自己主动调用drawRect方法,这样能够拿到 UIGraphicsGetCurrentContext。就能够画画了。 UIUserInterfaceIdiomPad iPad上专用
*/ #import "Canvas.h"
#import "ColorPickerController.h"
#import "BeyondViewController.h" @interface Canvas ()<UIImagePickerControllerDelegate,UINavigationControllerDelegate>
{
// 全部笔画
NSMutableArray *_strokesArr;
// 丢弃(撤销)的笔画
NSMutableArray *_abandonedStrokesArr;
// 当前笔刷颜色
UIColor *_currentColor;
// 当前的笔刷大小
float currentSize;
// 选中的图片
UIImage *_pickedImg;
// 截屏图片
UIImage *_screenImg;
// 自己定义的 颜色选择控制器
ColorPickerController *_colorPickerCtrl;
// 相片选择器
UIImagePickerController *_imagePickerCtrl;
} @end @implementation Canvas
#pragma mark - 生命周期方法
// 禁止多点触摸
-(BOOL)isMultipleTouchEnabled {
return NO;
}
// 最重要的绘图方法
- (void) drawRect: (CGRect) rect
{
// 1.先把获取的图片,画到画布上
[self drawPickedImgToCanvas]; // 2.假设【笔画数组】有笔画字典,则按顺序将笔画取出,画到画布上
[self drawStrokesArrToCanvas]; } // 1.先把获取的图片,画到画布上
- (void)drawPickedImgToCanvas
{
int width = _pickedImg.size.width;
int height = _pickedImg.size.height;
CGRect rectForImage = CGRectMake(0, 0, width, height);
[_pickedImg drawInRect:rectForImage];
}
// 2.假设【笔画数组】有笔画字典,则按顺序将笔画取出,画到画布上
- (void)drawStrokesArrToCanvas
{
// 假设【笔画数组】为空,则直接返回
if (_strokesArr.count == 0) return; // 遍历【笔画数组】,取出每个笔画字典,每一次迭代,画一个stroke
for (NSDictionary *oneStrokeDict in _strokesArr)
{
// 取出点数组
NSArray *pointsArr = [oneStrokeDict objectForKey:@"points"];
// 取出颜色
UIColor *color = [oneStrokeDict objectForKey:@"color"];
// 取出笔刷尺寸
float size = [[oneStrokeDict objectForKey:@"size"] floatValue];
// 设置颜色
[color set];
// line segments within a single stroke (path) has the same color and line width
// 画一个stroke, 一条接着一条,使用圆接头 round joint
// 创建一个贝塞尔路径
UIBezierPath* bezierPath = [UIBezierPath bezierPath];
// 点数组 中的第一个,就是 起点
CGPoint startPoint = CGPointFromString([pointsArr objectAtIndex:0]);
// 将路径移动到 起点
[bezierPath moveToPoint:startPoint];
// 遍历点数组,将每个点,依次加入到 bezierPath
for (int i = 0; i < (pointsArr.count - 1); i++)
{
// 依次取出下一个点
CGPoint pointNext = CGPointFromString([pointsArr objectAtIndex:i+1]);
// 加入到路径
[bezierPath addLineToPoint:pointNext];
}
// 设置线宽
bezierPath.lineWidth = size;
// 线连接处为 圆结头
bezierPath.lineJoinStyle = kCGLineJoinRound;
// 线两端为 圆角
bezierPath.lineCapStyle = kCGLineCapRound;
// 调用路径的方法 画出一条线
[bezierPath stroke];
}
}
// 重要~~~初始化全部东东
-(void) viewJustLoaded {
// 1.初始化颜色选择控制器
[self addColorPickerCtrl]; // 2.初始化【相片选择器】
[self addUIImagePickerCtrl]; // 3.其它成员初始化
// 【笔画数组】
_strokesArr = [NSMutableArray array];
// 【被丢弃的笔画数组】
_abandonedStrokesArr = [NSMutableArray array];
// 笔画大小
currentSize = 5.0;
// toolBar上笔画标签显示文字
self.labelSize.text = @"Size: 5";
// 设置笔刷 黑色
[self setStrokeColor:[UIColor blackColor]]; // 4.设置重做、撤销、清空三个button的状态
[self updateToolBarBtnStatus];
} // 1.初始化颜色选择控制器
- (void)addColorPickerCtrl
{
// 1.加入【颜色选择控制器】ColorPickerController。由于要加入到主控制器中
BeyondViewController *mainVC = [BeyondViewController sharedBeyondViewController];
// 初始化自己封装的颜色选择控制器,并设置好代理,目的是颜色设置好了之后,回调告诉当前的canvas画布
_colorPickerCtrl = [[ColorPickerController alloc] init];
_colorPickerCtrl.pickedColorDelegate = self;
// 控制器成为父子关系,视图也成为父子关系
[mainVC addChildViewController:_colorPickerCtrl];
[mainVC.view addSubview:_colorPickerCtrl.view];
// 临时隐藏【颜色选择控制器】,仅仅有在点击了ToolBar上面的button时候,才显示出来
_colorPickerCtrl.view.hidden = YES;
}
// 2.初始化【相片选择器】
- (void)addUIImagePickerCtrl
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
_imagePickerCtrl = [[UIImagePickerController alloc] init];
_imagePickerCtrl.delegate = self;
_imagePickerCtrl.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
// 2) 设置同意改动
// [_imagePickerCtrl setAllowsEditing:YES];
}
}
// 3.自己定义方法,设置 撤销、重做、清空三个button的可点击状态
- (void)updateToolBarBtnStatus
{ _redoBtn.enabled = _abandonedStrokesArr.count > 0;
_undoBtn.enabled = _strokesArr.count > 0;
_clearBtn.enabled = _strokesArr.count > 0; }
#pragma mark - 控件连线方法
// 滑块滑动
- (IBAction)setBrushSize:(UISlider*)sender
{
currentSize = sender.value;
self.labelSize.text = [NSString stringWithFormat:@"Size: %.0f",sender.value];
}
// 撤销button点击事件
-(IBAction) undo {
// 假设笔画数组中有笔画字典
if ([_strokesArr count]>0) {
// 最后一个笔画字典,即,被丢弃的笔画字典
NSMutableDictionary* abandonedStrokeDict = [_strokesArr lastObject];
// 将最后一个笔画字典,加入到被丢弃的笔画字典数组里面保存,以供drawRect
[_abandonedStrokesArr addObject:abandonedStrokeDict];
// 从全部笔画数组中移除掉最后一笔
[_strokesArr removeLastObject];
// 又一次调用drawRect进行绘制
[self setNeedsDisplay];
} // 2.设置重做、撤销、清空三个button的状态
[self updateToolBarBtnStatus];
}
// 重做
-(IBAction) redo {
// 假设 被丢弃的笔画数组,里面有值
if ([_abandonedStrokesArr count]>0) {
// 取出最后一个被仍进来的 笔画字典,(即最先书写的,并且是在撤销的操作里面,最后被加入到【被丢弃的笔画数组】)
NSMutableDictionary* redoStrokeDict = [_abandonedStrokesArr lastObject];
// 将须要重画的笔画字典,加入到【全部笔画数组】中
[_strokesArr addObject:redoStrokeDict];
// 并且,从【被丢弃的笔画数组】中移除,该笔画字典
[_abandonedStrokesArr removeLastObject];
// 又一次调用drawRect进行绘制
[self setNeedsDisplay];
} // 2.设置重做、撤销、清空三个button的状态
[self updateToolBarBtnStatus];
}
// 清空画布,仅仅需清空【全部笔画数组】和【被丢弃的笔画数组】
-(IBAction) clearCanvas {
// 建议不要将选择出来的背景图片清空,仅仅清空没写好的笔画算了
// _pickedImg = nil;
[_strokesArr removeAllObjects];
[_abandonedStrokesArr removeAllObjects];
// 又一次调用drawRect进行绘制
[self setNeedsDisplay]; // 2.设置重做、撤销、清空三个button的状态
[self updateToolBarBtnStatus];
}
// 保存图片
-(IBAction) savePic {
// 临时移除 工具条
//[_toolBar removeFromSuperview]; // 截图代码
// 1,开启上下文
UIGraphicsBeginImageContext(self.bounds.size);
// 2.将图层渲染到上下文
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
// 开启上下文,使用參数之后,截出来的是原图(YES 0.0 质量高)
//UIGraphicsBeginImageContextWithOptions(self.frame.size, YES, 0.0);
// 3.从上下文中取出图片
_screenImg = UIGraphicsGetImageFromCurrentImageContext();
// 4.关闭上下文
UIGraphicsEndImageContext(); // 又一次加入 工具条,并置最上方
//[self addSubview:_toolBar];
//[self bringSubviewToFront:self.labelSize]; // 调用自己定义方法,保存截屏到相冊
[self performSelector:@selector(saveToPhoto) withObject:nil afterDelay:0.0];
}
// 自己定义方法,保存截屏到相冊
-(void) saveToPhoto {
// 一句话,写到相冊
UIImageWriteToSavedPhotosAlbum(_screenImg, nil, nil, nil); // UIAlertView 提示成功
UIAlertView* alertView= [[UIAlertView alloc] initWithTitle:nil message:@"Image Saved" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show]; } // 点击选择颜色button
- (IBAction) didClickColorButton {
// 显示或隐藏 自己的【颜色选择控制器】
_colorPickerCtrl.view.hidden = !_colorPickerCtrl.view.hidden; }
// 当_colorPickerCtrl选择颜色完成,会调用代理 的本方法
- (void) pickedColor:(UIColor*)color {
// 将【颜色选择控制器】,回调的颜色,设置到控件上,并隐藏 【颜色选择控制器】
[self setStrokeColor:color];
_colorPickerCtrl.view.hidden = !_colorPickerCtrl.view.hidden; }
// 重要,设置笔刷 新的颜色
-(void) setStrokeColor:(UIColor*)newColor
{
_currentColor = newColor;
} // 点击,选择相片button
-(IBAction) didClickChoosePhoto {
// 展现,相片选择控制器
[self addSubview:_imagePickerCtrl.view];
}
#pragma mark - imagePicker代理方法
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// 必须手动,关闭照片选择器
[picker.view removeFromSuperview];
// 从info字典得到编辑后的照片【UIImagePickerControllerEditedImage】
_pickedImg = [info valueForKey:@"UIImagePickerControllerOriginalImage"];
// 将图片画到画板上去
[self setNeedsDisplay];
} // 【相片选择器】的代理方法,点击取消时,也要隐藏相片选择器
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[_imagePickerCtrl.view removeFromSuperview];
} #pragma mark - 核心代码,重要~~~画布上手势处理
// 手势開始(画笔落下)
// 開始一个新的字典,为每一笔,包含点 和 颜色
// Start new dictionary for each touch, with points and color
- (void) touchesBegan:(NSSet *) touches withEvent:(UIEvent *) event
{ // 一个笔画中的全部点,触摸開始时的【起点】
NSMutableArray *pointsArrInOneStroke = [NSMutableArray array];
NSMutableDictionary *strokeDict = [NSMutableDictionary dictionary];
[strokeDict setObject:pointsArrInOneStroke forKey:@"points"];
// 笔的颜色
[strokeDict setObject:_currentColor forKey:@"color"];
// 笔的大小
[strokeDict setObject:[NSNumber numberWithFloat:currentSize] forKey:@"size"]; // 落笔点
CGPoint point = [[touches anyObject] locationInView:self];
[pointsArrInOneStroke addObject:NSStringFromCGPoint(point)]; [_strokesArr addObject:strokeDict];
} // 将每个点加入到 点数组
// 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 *pointsArrInOneStroke = [[_strokesArr lastObject] objectForKey:@"points"];
// 在后面追加 新的点
[pointsArrInOneStroke 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\
);
[self setNeedsDisplayInRect:rectToRedraw];
} // 手势结束(画笔抬起)
// Send over new trace when the touch ends
- (void) touchesEnded:(NSSet *) touches withEvent:(UIEvent *) event
{
[_abandonedStrokesArr removeAllObjects]; // 2.设置重做、撤销、清空三个button的状态
[self updateToolBarBtnStatus]; } @end
颜色选择控制器
ColorPickerController
//
// ColorPickerController.h
// 24_Canvas画画板
//
// Created by beyond on 14-8-26.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// #import <UIKit/UIKit.h> @interface ColorPickerController : UIViewController #pragma mark - 属性列表
// xib上的imgView
@property (nonatomic,retain) IBOutlet UIImageView *imgView;
// 代理用weak
@property (weak) id pickedColorDelegate; #pragma mark - 方法列表
// 核心,依据位图引用 创建基于该位图的上下文对象
- (CGContextRef) createARGBBitmapContextFromImage:(CGImageRef)inImage;
// 核心,依据触摸点,从上下文中取出相应位置像素点的颜色值
- (UIColor*) getPixelColorAtLocation:(CGPoint)point; @end
核心代码
//
// ColorPickerController.m
// 24_Canvas画画板
//
// Created by beyond on 14-8-26.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// #import "ColorPickerController.h"
#import "Canvas.h"
@implementation ColorPickerController #pragma mark - 点击结束
- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { UITouch* touch = [touches anyObject];
// tap点击的位置
CGPoint point = [touch locationInView:self.imgView]; // 1.调用自己定义方法,从【点】中取颜色
UIColor *selectedColor = [self getPixelColorAtLocation:point];
// 2.告诉代理,解析出来的颜色
[_pickedColorDelegate pickedColor:selectedColor];
} // 核心代码:关于以下两个方法很多其它的具体资料,敬请查阅【iOS Developer Library 】
#pragma mark - 核心代码,将图片写入内存,再依据【点】中取颜色
- (UIColor *) getPixelColorAtLocation:(CGPoint)point
{
UIColor *color = nil;
// 得到取色图片的引用
CGImageRef colorImage = _imgView.image.CGImage; // Create off screen bitmap context to draw the image into. Format ARGB is 4 bytes for each pixel: Alpa, Red, Green, Blue // 调用自己定义方法:从_imgView里面的image的引用,创建并返回相应的上下文
CGContextRef contexRef = [self createARGBBitmapContextFromImage:colorImage];
// 假设创建该图片相应的上下文失败
if (contexRef == NULL){
NSLog(@"取色图片--创建相应的上下文失败~");
return nil;
}
// 准备将【取色图片】写入刚才创建出来的上下文
size_t w = CGImageGetWidth(colorImage); // problem!
size_t h = CGImageGetHeight(colorImage);
CGRect rect = {{0,0},{w,h}};
log_rect(rect)
// 调试输出rect:--{{0, 0}, {225, 250}} int bytesPerRow = CGBitmapContextGetBytesPerRow(contexRef);
log_int(bytesPerRow) //调试输出int:--900 // 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, colorImage); // 得到位图上下文 内存数据块的首地址,用指针记住,作为基地址
unsigned char* dataPoint = CGBitmapContextGetData (contexRef);
NSLog(@"----首地址,指针%p",dataPoint);
// ----首地址,指针0x8b3f000 if (dataPoint != NULL) {
//offset 即:依据触摸点的xy,定位到位图内存空间中的一个特定像素
//4 的意思是每个像素点,占4个字节
// w是每一行全部点的总数
// 依据所在行,所在列,算出在内存块中的偏移地址,然后乘以4,由于每个点在内存中占四个字节
int offset = 4*((w*round(point.y))+round(point.x));
// alpha 为内存基地址+偏移地址
int alpha = dataPoint[offset];
// red 为内存基地址+偏移地址+1 其它相似
int red = dataPoint[offset+1];
int green = dataPoint[offset+2];
int blue = dataPoint[offset+3]; NSLog(@"偏移地址: %i colors: RGBA %i %i %i %i",offset,red,green,blue,alpha);
// offset: 150908 colors: RGB A 255 0 254 255 // 依据RGBA 生成颜色对象
color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:(alpha/255.0f)];
} // 操作完毕后,释放上下文对象
CGContextRelease(contexRef);
// 从内存中释放掉 载入到内存的图像数据
if (dataPoint) {
free(dataPoint);
} return color;
}
// 自己定义方法2:通过_imgView里面的image的引用,创建并返回相应的上下文
- (CGContextRef) createARGBBitmapContextFromImage:(CGImageRef) inImage
{ // 要创建的上下文
CGContextRef context = NULL;
// 色彩空间
CGColorSpaceRef colorSpace;
// 位图数据在内存空间的首地址
void * bitmapData;
// 每一行的字节数
int bitmapBytesPerRow;
// 图片总的占的字节数
int bitmapByteCount; // 得到图片的宽度和高度,将要使用整个图片,创建上下文
size_t pixelsWide = CGImageGetWidth(inImage);
size_t pixelsHigh = CGImageGetHeight(inImage); // 每一行占多少字节. 本取色图片中的每个像素点占4个字节;
// 红 绿 蓝 透明度 各占一个字节(8位 取值范围0~255)
// 每一行的字节数,由于每个像素点占4个字节(包括RGBA)(当中一个R就是一个字节,占8位,取值是2的8次方 0~255)
bitmapBytesPerRow = (pixelsWide * 4);
// 图片总的占的字节数
bitmapByteCount = (bitmapBytesPerRow * pixelsHigh); // 使用指定的 色彩空间(RGB)
colorSpace = CGColorSpaceCreateDeviceRGB();
if (colorSpace == NULL)
{
fprintf(stderr, "创建并分配色彩空间 出错\n");
return NULL;
} // This is the destination in memory
// where any drawing to the bitmap context will be rendered.
// 为取色图片数据 分配全部的内存空间
// 全部画到取色图片上下文的操作,都将被渲染到此内存空间
bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL)
{
fprintf (stderr, "内存空间分配失败~");
CGColorSpaceRelease( colorSpace );
return NULL;
} // 创建位图上下文. 使用 pre-multiplied ARGB, ARGB中的每个成员都占8个bit位,即一字节,一个像素共占4个字节
// 不管原取色图片的格式是什么(CMYK或Grayscale),都将通过CGBitmapContextCreate方法,转成指定的ARGB格式
context = CGBitmapContextCreate (bitmapData,
pixelsWide,
pixelsHigh,
8, // bits per component
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedFirst);
if (context == NULL)
{
free (bitmapData);
fprintf (stderr, "位图上下文创建失败~");
} // 在返回上下文之前 必须记得释放 色彩空间
CGColorSpaceRelease( colorSpace ); return context;
} @end
iOS_24_画画板(含取色板)的更多相关文章
-
pyqt5 通过QLinearGradient 绘制取色板
要绘制HSV取色板,一般通过绘制前景色和背景色的方式实现,先绘制前景,然后绘制背景,前景是HSV颜色空间,从左到右,背景是亮度,从上到下,xs和ys是鼠标的当前的位置. def graphicsVie ...
-
Android 实现图片画画板
本文主要讲述了Android 实现图片画画板 设计项目布局: <RelativeLayout xmlns:android="http://schemas.android.com/apk ...
-
android96 内存创建图片副本,画画板
package com.itheima.copy; import android.os.Bundle; import android.app.Activity; import android.grap ...
-
iOS 使用UIBezierPath类实现随手画画板
在上一篇文章中我介绍了 UIBezierPath类 介绍 ,下面这篇文章介绍一下如何通过这个类实现一个简单的随手画画板的简单程序demo,功能包括:划线(可以调整线条粗细,颜色),撤销笔画,回撤笔画, ...
-
Android简单开发的画画板
Android开发画画板要考虑得几个问题如下: 1 屏幕画板.画笔如何绘制问题 2 用户手指触摸屏幕画板监听事件,以及对应的几种状态处理问题 3 保存图片到SD卡,以及在系统相册打开时自动加载刚才的 ...
-
Android简易实战教程--第二十四话《画画板》
今天完成一个画画板. 首先来个布局: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android ...
-
Android -- 图片处理, 画画板,缩放,旋转,平移,镜面,倒影,图片合成,颜色处理
1. 画画板 示例代码 public class MainActivity extends Activity { private ImageView iv; private Bitmap baseBi ...
-
canvas画画板,canvas画五角星,canvas制作钟表、Konva写钟表
制作一个画画板,有清屏有橡皮擦有画笔可以换颜色 style样式 <head> <meta charset="UTF-8"> <title>画画板 ...
-
IOS 绘制画画板(封装上下文)
封装上下文 UIImage (CaptureView).h / .m @interface UIImage (CaptureView) + (UIImage *)captureImageWithVie ...
随机推荐
-
在Pycharm中使用GitHub
Pycharm是当前进行python开发,尤其是Django开发最好的IDE.GitHub是程序员的圣地,几乎人人都在用. 本文假设你对pycharm和github都有一定的了解,并且希望在pycha ...
-
重拾Blog
上个月是我入职现在的公司三周年的月份,所以又续订了五年的合同,最近有一些思考,也不知道这个五年能否还会一直在这个公司工作. 一切随缘吧. 闲适有毒,忙碌的时光总是过的很快,自从加入这个公司以来,日常的 ...
-
java泛型中<;?>;和<;T>;有什么区别?
public static void printColl(ArrayList<?> al){ Iterator<?> it = al.iter ...
-
解决Idea创建maven-archetype-webapp项目无java目录的问题
一.背景 在适用IDEA创建maven-archetype-webapp项目的时候,创建完成后发现在main文件夹下没有java源文件夹,不少小伙伴也遇到该问题,但不知道怎么解决,下面我就来分享解决步 ...
-
2015年第11本:代码整洁之道Clean Code
前一段时间一直在看英文小说,在读到<Before I fall>这本书时,读了40%多实在看不下去了,受不了美国人啰啰嗦嗦的写作风格,还是读IT专业书吧. 从5月9日开始看<代码整洁 ...
-
linux服务器git pull/push时提示输入账号密码之免除设置
1.先cd到根目录,执行git config --global credential.helper store命令 [root@iZ25mi9h7ayZ ~]# git config --global ...
-
[小程序] 微信小程序 picker 中range-key中必须带单引号
原文地址:http://blog.csdn.net/u012329294/article/details/74906504 <view class="section"> ...
-
window下为kibana安装x-pack时候出现Plugin installation was unsuccessful due to error ";No valid url specified.";错误的解决方案
在Windows环境下为kibana安装x-pack plugin的时候,按照官网提示的安装步骤执行命令: kibana-plugin install file:///E:/software/ELK/ ...
-
tcp那个孤独的小包到底怎么回事?
内核3.10,接<tcp的发送端一个小包就能打破对端的delay_ack么?> 我们继续来分析这个没满mss的小包, 可以看到,由于受到syn ack这端是发包端,所以该发送链路协商的ms ...
-
ABAP知识点笔记
1,获取光标所在行 READ TABLE TD_ALV_DATA INTO TH_ALV_DATA INDEX RS_SELFIELD-TABINDEX. 2,获取alv可编辑单元格内容 DATA: ...