位图图像数据实际上一个像素阵列,其中每一个像素表明了图像中的一个点。位图实际上只支持矩形区域的渲染,可是使用透明技术能够实现任意形状图像的渲染。开发者也能够对要进行渲染的图像进行旋转、切割等操做。前端
CoreGraphics框架中提供了许多方法来建立位图数据引用CGImageRef对象,其中封装在CGImage.h文件中。在UIKit框架中也提供了方便的接口供开发者进行CGImageRef与UIImage对象的相互转换。算法
经过CoreGraphics框架中提供的图像裁剪方法,开发者能够截取一张大图片中的一部分做为新的图像进行渲染。在Web开发中,为了减小请求次数,经常会将许多小图片合成一张大图片返回给前端,同时还会给前端返回一个json文件,文件中存放着每一个独立小图的坐标位置,前端在使用时进行截取便可,这种图片经常被称做雪碧图。在iOS开发中游戏开发中,不少游戏引擎也提供了相似的方法,方便开发者对游戏素材进行管理。实际上,经过CoreGraphics框架,开发者也能够本身实现一套这样的图片加载逻辑,若是在本身的应用中,同时须要异步加载的小图片不少,也能够设计成下载一张大图后从中截取须要的图片。进行图像截取的示例代码以下:json
-(void)drawRect:(CGRect)rect{ CGContextRef contextRef = UIGraphicsGetCurrentContext(); //进行坐标系的翻转 CGContextTranslateCTM(contextRef, 0, rect.size.height); CGContextScaleCTM(contextRef, 1.0, -1.0); CGImageRef orignImage = [UIImage imageNamed:@"image"].CGImage; CGContextDrawImage(contextRef, CGRectMake(0, 0, 320, 200), orignImage); CGImageRef rectImage = CGImageCreateWithImageInRect(orignImage, CGRectMake(300, 400, 800, 400)); CGContextDrawImage(contextRef, CGRectMake(0, 220, 320, 200), rectImage); CGImageRelease(orignImage); CGImageRelease(rectImage); }
效果以下图所示:数组
须要注意,CGContextDrawImage()方法渲染的图像是上下翻转的,能够经过调整坐标系来将图片翻转回来。框架
经过Mask膜层能够实现炫酷的图像裁剪与风格重绘。膜层能够简单的理解为将一个图层追加到原图层上,但须要注意,图层中颜色为纯黑的部分,会按照原图绘制,纯白的部分会被彻底遮挡,这中间的颜色会以特定的算法进行alpha值的更改。例如将以下图片做为膜层绘制到原图像上:异步
代码以下:ide
-(void)drawRect:(CGRect)rect{ CGContextRef contextRef = UIGraphicsGetCurrentContext(); //进行坐标系的翻转 CGContextTranslateCTM(contextRef, 0, rect.size.height); CGContextScaleCTM(contextRef, 1.0, -1.0); CGImageRef orignImage = [UIImage imageNamed:@"image"].CGImage; CGImageRef maskRef = [UIImage imageNamed:@"maskImage"].CGImage; //经过图片数据建立膜层 CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef), CGImageGetHeight(maskRef), CGImageGetBitsPerComponent(maskRef), CGImageGetBitsPerPixel(maskRef), CGImageGetBytesPerRow(maskRef), CGImageGetDataProvider(maskRef), nil, YES); CGImageRef resultImage = CGImageCreateWithMask(orignImage, mask); CGContextDrawImage(contextRef, CGRectMake(0, 0, 320, 200), resultImage); CGImageRelease(orignImage); CGImageRelease(maskRef); CGImageRelease(mask); }
效果以下图所示:spa
除了使用图片膜层来对原图像数据进行裁剪处理外,还能够经过颜色数据定义膜层来进行裁剪。这个方法就能增强大了,其能够将图像中某个范围的颜色所对应的全部区域裁剪出来。示例代码以下:设计
-(void)drawRect:(CGRect)rect{ CGContextRef contextRef = UIGraphicsGetCurrentContext(); //进行坐标系的翻转 CGContextTranslateCTM(contextRef, 0, rect.size.height); CGContextScaleCTM(contextRef, 1.0, -1.0); CGImageRef orignImage = [UIImage imageNamed:@"image2"].CGImage; const CGFloat myMaskingColors[6] = {35, 154, 23, 194, 103, 214}; CGImageRef mask2 = CGImageCreateWithMaskingColors(orignImage, myMaskingColors); CGContextDrawImage(contextRef, CGRectMake(0, 0, 320, 200), mask2); CGImageRelease(orignImage); CGImageRelease(mask2); }
CGImageCreateWithMaskingColors()这个方法须要两个参数,第一个参数是要进行裁剪的图像,那二个参数须要设置为一个表示色彩的数组,须要注意,这个数组中元素的个数须要是当前色彩空间颜色原色数的两倍,例如RGB色彩空间对应这个数组须要有6个元素{min1,max1,min2,max2,min3,max3}。以后会对图像数据中的每个像素点进行遍历,假如此像素点的颜色值为{c1,c2,c3}。则当知足以下条件时,这个像素点会被裁剪:code
min1<c1<max1,min2<c2<max2,min3<c3<max3
须要注意,使用这种方式进行膜层裁剪,原图像不能够有alpha通道,色值的取值范围为0-255之间。上面示例代码会将原图像裁剪成以下效果:
对于被裁剪出来的部分,开发者可使用其余颜色进行填充,示例代码以下:
-(void)drawRect:(CGRect)rect{ CGContextRef contextRef = UIGraphicsGetCurrentContext(); //进行坐标系的翻转 CGContextTranslateCTM(contextRef, 0, rect.size.height); CGContextScaleCTM(contextRef, 1.0, -1.0); CGImageRef orignImage = [UIImage imageNamed:@"image2"].CGImage; //设置填充 [[UIColor redColor] setFill]; CGContextFillRect(contextRef, CGRectMake(0, 0, 320, 200)); const CGFloat myMaskingColors[6] = {35, 154, 23, 194, 103, 214}; CGImageRef mask2 = CGImageCreateWithMaskingColors(orignImage, myMaskingColors); CGContextDrawImage(contextRef, CGRectMake(0, 0, 320, 200), mask2); CGImageRelease(orignImage); }
效果以下图:
除了上面介绍了两种对图像进行裁剪的方法外,CoreGraphics框架中还提供了一种裁剪方式,示例代码以下:
-(void)drawRect:(CGRect)rect{ CGContextRef contextRef = UIGraphicsGetCurrentContext(); //进行坐标系的翻转 CGContextTranslateCTM(contextRef, 0, rect.size.height); CGContextScaleCTM(contextRef, 1.0, -1.0); CGImageRef orignImage = [UIImage imageNamed:@"image2"].CGImage; CGImageRef maskRef = [UIImage imageNamed:@"maskImage"].CGImage; CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef), CGImageGetHeight(maskRef), CGImageGetBitsPerComponent(maskRef), CGImageGetBitsPerPixel(maskRef), CGImageGetBytesPerRow(maskRef), CGImageGetDataProvider(maskRef), nil, YES); //进行膜层的裁剪 CGContextClipToMask(contextRef, CGRectMake(0, 0, 320, 200), mask); CGContextDrawImage(contextRef, CGRectMake(0, 0, 320, 200), orignImage); CGImageRelease(orignImage); }
使用CoreGraphics框架也能够绘制复杂的图像混合效果,在进行图像混合时,须要先绘制背景图像,以后设置图像混合模式,在绘制前景图像,CoreGraphics会根据混合模式来进行最后图像的绘制。例如使用以下背景图像来与前景图像来进行混合:
背景图像:
前景图像:
示例代码以下:
-(void)drawRect:(CGRect)rect{ CGContextRef contextRef = UIGraphicsGetCurrentContext(); //进行坐标系的翻转 CGContextTranslateCTM(contextRef, 0, rect.size.height); CGContextScaleCTM(contextRef, 1.0, -1.0); CGImageRef background = [UIImage imageNamed:@"background"].CGImage; CGContextDrawImage(contextRef, CGRectMake(60, 25, 200, 150), background); CGContextSetBlendMode(contextRef, kCGBlendModeNormal); CGImageRef orignImage = [UIImage imageNamed:@"image2"].CGImage; CGContextDrawImage(contextRef, CGRectMake(0, 0, 320, 200), orignImage); CGImageRelease(background); CGImageRelease(orignImage); }
kCGBlendModeNormal模式的混合就是简单覆盖,前景图像会彻底将背景图像覆盖,运行效果以下:
kCGBlendModeMultiply模式是叠加混合模式,其会将前景图alpha化,效果以下:
kCGBlendModeScreen模式会将前景图进行裁剪,最终的结果颜色将比原图轻,效果以下:
kCGBlendModeOverlay模式也会将前景图进行裁剪,会保持原图色彩,效果以下:
kCGBlendModeDarken混合模式会将原图色值加深,效果以下:
kCGBlendModeLighten在混合时则会选择色值较轻的图像进行混合,效果以下:
kCGBlendModeColorDodge混合模式效果以下:
kCGBlendModeColorBurn混合模式效果以下:
kCGBlendModeSoftLight为柔光混合模式,效果以下:
kCGBlendModeHardLight为重光混合模式,效果以下:
kCGBlendModeDifference差别混合模式会取颜色的逆向值,效果以下:
kCGBlendModeExclusion混合模式效果以下:
kCGBlendModeHue混合模式会改变色彩的饱和度,效果以下:
kCGBlendModeSaturation混合模式效果以下:
kCGBlendModeColor混合模式效果以下:
kCGBlendModeLuminosity光影混合模式会将前景图进行黑白化,效果以下:
专一技术,热爱生活,交流技术,也作朋友。
——珲少 QQ群:203317592