iOS 2D绘图详解(Quartz 2D)之Bitmap
什么是Bitmap?
Bitmap叫做位图,每一个像素点由1-32bit组成。每个像素点包括多个颜色组件和一个Alpha组件(例如:RGBA)。
iOS中指出如下格式的图片 JPEG, GIF, PNG, TIF, ICO, GMP, XBM,和 CUR。其他格式的图片要给Quartz2D传入图片的数据分布信息。
数据类型CGImageRef
在Quartz中,Bitmap的数据由CGImageRef封装。由以下几个函数可以创建CGImageRef对象
- CGImageCreate - 最灵活,但也是最复杂的一种方式,要传入11个参数,这个方法最后讲解。
- CGImageSourceCreate-ImageAtIndex-通过已经存在的Image对象来创建
- CGImageSourceCreate-ThumbnailAtIndex- 和上一个函数类似,不过这个是创建缩略图
- CGBitmapContextCreateImage - 通过Copy Bitmap Graphics来创建
- CGImageCreateWith-ImageInRect -通过在某一个矩形内数据来创建
例子一,在一个bitmap context绘制,并且重新生成一张图片
先看看一个方法,创建bitmap context-CGBitmapContextCreate
函数体
CGContextRef _Nullable CGBitmapContextCreate (
void * _Nullable data,
size_t width,
size_t height,
size_t bitsPerComponent,
size_t bytesPerRow,
CGColorSpaceRef _Nullable space,
uint32_t bitmapInfo
);
参数
- data 是一个指针,指向存储绘制的bitmap context的实际数据的地址,最少大小为bytesPerRow* height.可以传入null,让quartz自动分配计算
- width/height bitmap的宽度,高度,以像素为单位
- bytesPerRow 每一行的byte数目。如果data传入null,这里传入0,则会自动计算
- 一个component占据多少位。对于32bit的RGBA空间,则是8(8*4=32)。
- space 颜色空间,一般就是DeviceRGB
- bitmapInfo,一个常量,指定了是否具有alpha通道,alpha通道的位置,像素点存储的数据类型是float还是Integer等信息。
其中bitmapInfo可以传入的参数如下,通过名字就能看出来,这里不加注释了
enum CGImageAlphaInfo {
kCGImageAlphaNone,
kCGImageAlphaPremultipliedLast,
kCGImageAlphaPremultipliedFirst,
kCGImageAlphaLast,
kCGImageAlphaFirst,
kCGImageAlphaNoneSkipLast,
kCGImageAlphaNoneSkipFirst,
kCGImageAlphaOnly
};
原图(1280*800)
效果
重新绘制成200*100,并在图片中间加上我们自定义的绘制
代码
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
CGSize targetSize = CGSizeMake(200, 100);
CGContextRef bitmapContext = CGBitmapContextCreate(NULL,
targetSize.width,
targetSize.height,
8,
targetSize.width * 4,
rgb,
kCGImageAlphaPremultipliedFirst);
CGRect imageRect;
imageRect.origin = CGPointMake(0, 0);
imageRect.size = targetSize;
UIImage * imageToDraw = [UIImage imageNamed:@"image.jpg"];
CGContextDrawImage(bitmapContext,imageRect,imageToDraw.CGImage);
CGContextAddArc(bitmapContext,100,40, 20,M_PI_4, M_PI_2, true);
CGContextSetLineWidth(bitmapContext, 4.0);
CGContextStrokePath(bitmapContext);
CGImageRef imageRef = CGBitmapContextCreateImage(bitmapContext);
UIImage * image = [[UIImage alloc] initWithCGImage:imageRef];
CGImageRelease(imageRef);
CGContextRelease(bitmapContext);
CGColorSpaceRelease(rgb);
UIImageView * imageView = [[UIImageView alloc] initWithImage:image];
imageView.center = self.view.center;
[self.view addSubview:imageView];
例子二,截取图片的一部分
效果
代码
UIImage * imageToDraw = [UIImage imageNamed:@"image.jpg"];
CGImageRef partImageRef = CGImageCreateWithImageInRect(imageToDraw.CGImage, CGRectMake(0, 0,300, 200));
UIImage * partImage = [[UIImage alloc] initWithCGImage:partImageRef];
UIImageView * imageView = [[UIImageView alloc] initWithImage:partImage];
imageView.center = self.view.center;
[self.view addSubview:imageView];
看看CGImageCreate这个方法
CGImageRef _Nullable CGImageCreate (
size_t width,
size_t height,
size_t bitsPerComponent,
size_t bitsPerPixel,
size_t bytesPerRow,
CGColorSpaceRef _Nullable space,
CGBitmapInfo bitmapInfo,
CGDataProviderRef _Nullable provider,
const CGFloat * _Nullable decode,
bool shouldInterpolate,
CGColorRenderingIntent intent
);
参数
- width/height 图片的像素宽度,高度
- bitsPerComponent 每个component的占用bit个数,和上文提到的一样
- bitsPerPixel 每个像素点占用的bit个数。例如32bit RGBA中,就是32
- bytesPerRow 每一行占用的byte个数
- colorspace 颜色空间
- bitmapInfo 和上文提到的那个函数一样
- provider bitmap的数据源
- decode 解码array,传入null,则保持原始数据
- interpolation 是否要像素差值来平滑图像
- intent 指定了从一个颜色空间map到另一个颜色空间的方式
UIKit中的Bitmap
成对使用来创建bitmap context,进行绘制
UIGraphicsBeginImageContext
UIGraphicsEndImageContext
通过一下方法来获取当前context就可以绘制了。
UIGraphicsGetCurrentContext
然后通过,UIGraphicsGetImageFromCurrentImageContext
来生成图片
例如
调整图片的大小
+ (UIImage*)imageWithImage:(UIImage*)image
scaledToSize:(CGSize)newSize;
{
UIGraphicsBeginImageContext( newSize );
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
截屏
UIWindow * keyWindow = [UIApplication sharedApplication].keyWindow;
UIGraphicsBeginImageContextWithOptions(keyWindow.bounds.size, NO, [UIScreen mainScreen].scale);
CGContextRef context = UIGraphicsGetCurrentContext();
[keyWindow.layer renderInContext:context];
UIImage * screenShot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
2015-10-11 Swift之贪婪的UIButton
2015-10-11 Swift学习之UI开发初探