前言
上一篇文章简单的介绍了Core Graphics的概念,这篇文章来介绍一下Core Graphics在实际开发中的使用
图形绘制
线段
- (void)drawRect:(CGRect)rect {
// 获取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 设置线宽
CGContextSetLineWidth(ctx, 2);
// 设置起点
CGContextMoveToPoint(ctx, 10, 10);
// 第二个点
CGContextAddLineToPoint(ctx, 250, 250);
// 设置颜色
[[UIColor redColor]set];
// 渲染
CGContextStrokePath(ctx);
}
矩形
- (void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 线宽
CGContextSetLineWidth(ctx, 2);
// 矩形
CGContextAddRect(ctx, CGRectMake(0, 0, 200, 200));
// 设置颜色
[[UIColor redColor]set];
// 渲染
CGContextStrokePath(ctx);
}
圆
- (void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 线宽
CGContextSetLineWidth(ctx, 2);
/*
参数1:目标上下文
参数2:圆心x
参数3:圆心y
参数4:半径
参数5:开始弧度
参数6:结束弧度
参数7:绘制方向,NO:顺时针; YES:逆时针
*/
// 圆
CGContextAddArc(ctx, 40, 200, 40, 0, 2*M_PI, YES);
// 设置颜色
[[UIColor redColor]set];
// 渲染
CGContextStrokePath(ctx);
}
贝塞尔曲线
二阶贝塞尔
- (void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 线宽
CGContextSetLineWidth(ctx, 2);
// 虚线
CGContextSetLineDash(ctx, 0, (CGFloat[]){10,5}, 2);
// 起点
CGContextMoveToPoint(ctx, 100, 100);
/*
参数1:目标上下文
参数2:控制点 x坐标
参数3:控制点 y坐标
参数4:结束点 x坐标
参数5:结束点 y坐标
*/
// 二阶贝塞尔
CGContextAddQuadCurveToPoint(ctx, 300, 300, 100, 500);
// 设置颜色
[[UIColor redColor]set];
// 渲染
CGContextStrokePath(ctx);
}
三阶贝塞尔
- (void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 线宽
CGContextSetLineWidth(ctx, 2);
/*
参数1:目标上下文
参数2:控制点1 x坐标
参数3:控制点1 y坐标
参数4:控制点2 x坐标
参数5:控制点2 y坐标
参数6:结束点 x坐标
参数7:结束点 y坐标
*/
// 三阶贝塞尔曲线
CGContextAddCurveToPoint(ctx, 40, 200, 300, 300, 100, 500);
// 设置颜色
[[UIColor redColor]set];
// 渲染
CGContextStrokePath(ctx);
}
图片处理
图片处理不再是在drawRect:方法处理,而是调用CGBitmapContextCreate()去创建一个图片的上下文,通过处理这个上下文达到我们想要的效果后输出UIImage对象
灰度图
- (UIImage *)grayImage:(UIImage *)image {
// 创建灰度色彩空间的对象
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
/*
参数1:指向要渲染的绘制内存的地址
参数2:高度
参数3:宽度
参数4:表示内存中像素的每个组件的位数
参数5:每一行在内存所占的比特数
参数6:表示上下文使用的颜色空间
参数7:表示是否包含透明通道
*/
// 创建一个图片上下文
CGContextRef context = CGBitmapContextCreate(nil, image.size.width, image.size.height, 8, 0, colorSpace, kCGImageAlphaNone);
// 释放色彩空间的对象
CGColorSpaceRelease(colorSpace);
if (!context) {
return nil;
}
// 绘制
CGContextDrawImage(context, CGRectMake(0, 0, image.size.width, image.size.height), image.CGImage);
// 创建UIImage对象
UIImage *grayImage = [UIImage imageWithCGImage:CGBitmapContextCreateImage(context)];
// 释放上下文
CGContextRelease(context);
return grayImage;
}
二值化
- (UIImage *)binarizationImage:(UIImage *)image {
int width = image.size.width;
int height = image.size.height;
// 创建一个等于图片大小像素的数组
uint32_t *pixels = (uint32_t *)malloc(width * height * sizeof(uint32_t));
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
// 数组清零
memset(pixels, 0, width*height * sizeof(uint32_t));
/*
参数1:指向要渲染的绘制内存的地址
参数2:高度
参数3:宽度
参数4:表示内存中像素的每个组件的位数
参数5:每一行在内存所占的比特数
参数6:表示上下文使用的颜色空间
参数7:表示是否包含透明通道
*/
CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width*sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.CGImage);
int tt =1;
CGFloat intensity;
int bw;
//
for (int y = 0; y <height; y++) {
for (int x =0; x <width; x ++) {
uint8_t *rgbaPixel = (uint8_t *)&pixels[y*width+x];
intensity = (rgbaPixel[tt] + rgbaPixel[tt + 1] + rgbaPixel[tt + 2]) / 3. / 255.;
bw = intensity > 0.45?255:0;
rgbaPixel[tt] = bw;
rgbaPixel[tt + 1] = bw;
rgbaPixel[tt + 2] = bw;
}
}
// 通过上下文 创建一个CGImageRef
CGImageRef imageRef = CGBitmapContextCreateImage(context);
// 上下文释放
CGContextRelease(context);
// 颜色对象释放
CGColorSpaceRelease(colorSpace);
// 释放数组
free(pixels);
// 通过CGImage创建UIImage
UIImage *resImage = [UIImage imageWithCGImage:imageRef];
// 释放CGImage
CGImageRelease(imageRef);
return resImage;
}
图片分割
- (UIImage *)CutImageWithImage:(UIImage *)image withRect:(CGRect)rect
{
/*
参数1:CGImage类型
参数2:要切割的CGRect
*/
CGImageRef cutImage = CGImageCreateWithImageInRect(image.CGImage, rect);
// 将切割出得图片转换为UIImage
UIImage *result = [UIImage imageWithCGImage:cutImage];
return result;
}
图片拼接
- (UIImage *)spliceImage:(UIImage *)image1 toImage:(UIImage *)image2 {
CGSize size = CGSizeMake(image1.size.width, image1.size.height);
// 创建一个基于位图的上下文(context),并将其设置为当前上下文(context)
UIGraphicsBeginImageContext(size);
// Draw image2
[image2 drawInRect:CGRectMake(4.5, 6, 77, 77)];
// Draw image1
[image1 drawInRect:CGRectMake(0, 0, image1.size.width, image1.size.height)];
// 获取拼接好的图片
UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
// 关闭图形上下文
UIGraphicsEndImageContext();
return resultingImage;
}
页面截图
- (UIImage *)captureView:(UIImageView *)view {
/*
参数1:绘制的尺寸大小
参数2:透明开关,如果图形完全不用透明,设置为YES以优化位图的存储。
参数3:设为0后,系统就会自动设置正确的比例
*/
// 创建一个基于位图的上下文(context),并将其设置为当前上下文(context)。
UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, 0.0);
// 渲染view.layer到当前context
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
// 通过context获取UIImage
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 关闭图形上下文
UIGraphicsEndImageContext();
return image;
}
实战
分页控制器自定义形状
项目中要自定义一个不规则的tabar,如图。上网找到的方法都是iOS 13以下才能用,iOS 13以上就失效。分析一下这个需求,是往下凹而不是往上凸,所以目前这个办法是可以解决这个需求的。
思路:
1.先自定义一个view,然后绘制我们需要的形状,通过mask属性去设置遮罩。
2.完成后截图生成一张图片,把这种图片设置成tabar的背景图
// .h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface BaseTabBar : UITabBar
@end
NS_ASSUME_NONNULL_END
// .m
- (void)setCurveBG {
UIView *back = [UIView new];{
back.backgroundColor = YELLOW_COLOR;
[self setShadowImage:[UIImage new]];
back.frame = self.bounds;
// 绘制中间的曲线部分
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(ViewWidth(back) /5, 0.f)];
[path addCurveToPoint:CGPointMake(ViewWidth(back)/2, 35) controlPoint1:CGPointMake(ViewWidth(back) *3/7, 0) controlPoint2:CGPointMake(ViewWidth(back)/2-35, 35)];
[path addCurveToPoint:CGPointMake(ViewWidth(back) *4/5, 0.f) controlPoint1:CGPointMake(ViewWidth(back)/2+35, 35) controlPoint2:CGPointMake(ViewWidth(back) *4/7, 0)];
[path closePath];
// 矩形部分
UIBezierPath *path2 = [UIBezierPath bezierPath];
[path2 moveToPoint:CGPointMake(0.f, 0.f)];
[path2 addLineToPoint:CGPointMake(ViewWidth(back), 0.f)];
[path2 addLineToPoint:CGPointMake(ViewWidth(back), ViewHeight(back))];
[path2 addLineToPoint:CGPointMake(0.f, ViewHeight(back))];
[path2 closePath];
// 将曲线部分路径添加到矩形部分
[path2 appendPath:path];
// 设置遮罩路径
CAShapeLayer *shapLayer = [CAShapeLayer layer];
shapLayer.path = path2.CGPath;
back.layer.mask = shapLayer;
self.translucent = YES;
// 截图
UIImage *image = [self convertViewToImage:back];
self.backgroundImage = image;
}
}