在iOS开发中,会接触不同的绘制框架。Core Graphics、Quartz、以及更底层的OpenGL ES。
坐标系
UIKit坐标系是原点位于左上角,y轴向下。
Core Graphics 和Quartz 原点位于左下角,y轴向上。
OpenGL ES坐标系原点位于中心,y轴向上。
在使用Core Graphics 绘制时,需要翻转坐标系。注意后面的矩阵(缩放矩阵)先生效。
CGContextTranslateCTM(context, 0, height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), uiImage.CGImage);
OpenGL ES中通过照片创建纹理,然后展示到屏幕时,需要翻转照片。
UIImage *image = [UIImage imageNamed:@"scene.jpg"];
CGImageRef imageRef = image.CGImage;
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
GLubyte *bytes = (GLubyte *)malloc(width * height * 4);
CGColorSpaceRef color = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(bytes, width, height, 8, width * 4, color, kCGImageAlphaPremultipliedLast);
//翻转坐标系
CGContextTranslateCTM(context, 0, height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGColorSpaceRelease(color);
if(imageRef) {
CFRelease(imageRef);
}
通过bytes创建纹理,然后通过OpenGL ES的颜色缓存渲染到屏幕时,照片才能正常显示。
Core Graphics 是以左上角为原点,y轴向下的方式保存照片的。OpenGL ES是Y轴向上的。绘制的时候,会将照片数据的原点放到左下角,因此需要翻转坐标系。
OpenGL ES 获取图像数据
直接从帧缓存读取颜色数据,核心glReadPixel
函数。
- (void)readPixel
{
NSInteger width = self.frame.size.width * [UIScreen mainScreen].scale;;
NSInteger height = self.frame.size.height * [UIScreen mainScreen].scale;;
GLvoid *pixels = malloc(width * height * 4);
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
//刷新,保证不是展示缓存,也可以获取颜色数据
glFlush();
glReadPixels(0, 0, (int)width, (int)height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, width * height * 4, NULL);
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGImageRef imageRef = CGImageCreate(width, height, 8, 8 * 4, width * 4, colorSpace, bitmapInfo, provider, NULL, NO, renderingIntent);
//此处的照片数据是y轴翻转的,需要翻转y轴
UIImage *tempImage = [UIImage imageWithCGImage:imageRef];
CGColorSpaceRelease(colorSpace);
CGDataProviderRelease(provider);
//此处的size是以点为单位,如果获取的是像素需要 通过 w / [UIScreen mainScreen].scale
UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), YES, [UIScreen mainScreen].scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
//获取最终的照片
UIImage *flipImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if(imageRef) {
CFRelease(imageRef);
}
free(pixels);
}
总结
:
- CGImageCreate·创建照片的速度比较快,底层不会复制照片数据。
- CGBitmapContextCreate会复制照片数据。
GLubyte *bytes = (GLubyte *)malloc(width * height * 4);
CGColorSpaceRef color = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(bytes, width,
height, 8, width * 4, color, kCGImageAlphaPremultipliedLast);
具体使用哪个根据情况,如果需要复制,获取直接对照片数据进行其他操作,则使用CGBitmapContextCreate
。