美文网首页
Core Graphics 五: 位图和遮罩

Core Graphics 五: 位图和遮罩

作者: Trigger_o | 来源:发表于2020-11-04 18:56 被阅读0次

计算机图形分为两类,矢量图形和位图图形
位图图形就是像素点阵,是由像素点按照特定阵列显示出来,当像素密度足够大时,位图图形可以还原真实的场景,但是当像素密度小的时候,就会出现锯齿,模糊等现象(Aliasing).
矢量图形是用更复杂的数学模型描述的图形,有点类似cgcontext的绘制,比如轮廓和填充策略,文件的大小由图像的复杂程度决定,放大和缩小不会对图形产生影响.

Core Graphics中提供了很多函数,越是灵活的函数复杂度越高,参数涉及的底层内容也更多.这里从常规的使用开始入手.

一.创建位图图像

1.创建图像 CGImageRef

  • 1.1通过资源创建图像
    创建图像有两种方法,第一种是加载图像资源,图像资源可以是文件,也可以是core graphics的数据结构.最简单的就是直接加载图片文件.
     CGImageSourceRef sourceRef = CGImageSourceCreateWithURL((__bridge CFURLRef)[[NSURL alloc]   initFileURLWithPath:[[NSBundle mainBundle] pathForResource:@"avatar" ofType:@"png"]], NULL);
     CGImageRef imgRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, NULL);

CGImageSourceRef CGImageSourceCreateWithURL(CFURLRef url, CFDictionaryRef options);
CGImageRef CGImageSourceCreateImageAtIndex(CGImageSourceRef isrc, size_t index, CFDictionaryRef options);
这两个函数都需要一个策略字典,这个字典如果没有特殊需求可以给NULL,字典的详情参照developer documentation.
CGImageSourceCreateImageAtIndex需要一个index,如果是png,jpeg之类的文件,使用0就可以了,因为图像只有一个,而gif可以有多个图像,配合CGImageSourceGetCount可以拿到文件包含的图像个数.
需要注意的是CGImageRef要调用CGImageRelease释放.

当然如果只是需要CGImageRef,UIKit中的UIImage还提供了更便捷的方法

@property(nonatomic, readonly) CGImageRef CGImage;
  • 1.2通过上下文创建图像
    最常用的函数是
    CGImageRef CGBitmapContextCreateImage(CGContextRef context);

绘制之后调用CGBitmapContextCreateImage生成CGImageRef,然后imageWithCGImage生成UIImage对象

CGImageRef imgref = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext());
    UIImage *image = [UIImage imageWithCGImage:imgref];

-1.3从图像上选择一部分创建新的图像
CGImageRef CGImageCreateWithImageInRect(CGImageRef image, CGRect rect);

这个函数需要注意像素和点的关系,也就是UIImage的size和UIImageView的size的差距.

CGImageRef imgref = CGImageCreateWithImageInRect(img.CGImage, CGRectMake(img.size.width/4,img.size.height/4,img.size.width/2, img.size.height/2));
    imgv.image = [UIImage imageWithCGImage:imgref];
image.png

这段代码中,img是前面CGBitmapContextCreateImage获取到的,取中间一部分放大然后显示,会发现线也粗了

    UIImageView *imgv = [[UIImageView alloc]init];
    [self.view addSubview:imgv];
    CGImageRef imgRef = [UIImage imageNamed:@"avatar"].CGImage;
    size_t height = CGImageGetHeight(imgRef);
    size_t width = CGImageGetWidth(imgRef);
    CGImageRef halfimgref = CGImageCreateWithImageInRect(imgRef, CGRectMake(width/4,height/4,width/2, height/2));
    imgv.frame = CGRectMake(0, 250, 200, 200.0/width*height);
    imgv.image = [UIImage imageWithCGImage:halfimgref];
    CGImageRelease(imgRef);
    CGImageRelease(halfimgref);

上面这段代码是剪切图片生成新的图片并显示
CGImageGetHeight和CGImageGetWidth可以获取CGImageRef的尺寸
如果imgRef不创建出来,直接把 [UIImage imageNamed:@"avatar"].CGImage作出参数传进去,也就少一次引用,CGImageCreateWithImageInRect使用之后会释放,如果自己没有引用的话,就不用再释放了.


右边是原图

二.创建图像蒙版(或者叫做遮罩)

1.颜色蒙版
通过屏蔽提供给函数的图像中的一种颜色或一系列颜色来创建图像.
CGImageRef CGImageCreateWithMaskingColors(CGImageRef image, const CGFloat *components);
这个函数是抠掉指定范围内的颜色,components是两组rbg值,不过顺序是R1,R2,G1,G2,B1,B2;
意思是将指定范围内的颜色除去

const CGFloat colors[6] = {9,80, 35, 130, 13, 140};
    CGImageRef maskref = CGImageCreateWithMaskingColors(imgRef, colors);
    imgv.image = [UIImage imageWithCGImage:maskref];

这个例子是先用取色器在图中绿色部分取一个深色取一个浅色,深色是9,35,13;浅色是80,130,140,在这个范围内的颜色被抠掉露出下面洋红色的背景.


image.png

2.上下文蒙版
在这之前,需要先了解一点,一些蒙版相关的函数中,叫做mask的参数,虽然都是CGImageRef类型,但是通过CGImageMaskCreate创建出来的CGImageRef是不一样的,叫做图形掩码,是用来作为蒙版的参数.
另外介绍一下CGImageMaskCreate函数

CGImageRef maskRef = [UIImage imageNamed:@"11"].CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                                            CGImageGetHeight(maskRef),
                                            CGImageGetBitsPerComponent(maskRef),
                                            CGImageGetBitsPerPixel(maskRef),
                                            CGImageGetBytesPerRow(maskRef),
                                            CGImageGetDataProvider(maskRef), NULL, false);

这个函数需要一大堆的参数,暂时先按照这么去写,具体参照developer documentation

接下来是使用上下文蒙版
void CGContextClipToMask(CGContextRef c, CGRect rect, CGImageRef mask);
这个函数需要一个rect,表示蒙版的范围,mask是一个CGImageRef;
mask是一个普通的CGImageRef,例如[UIImage imageNamed:@"11"].CGImage,(如图2-1)

mask是一个通过CGImageMaskCreate创建的CGImageRef,产生的结果是不一样的.(如图2-2)

    CGFloat x = rect.size.width/4;
    CGFloat y = rect.size.height/4;
    CGFloat w = rect.size.width/2;
    CGFloat h = rect.size.height/2;
    CGRect half = CGRectMake(x, y, w, h);
    
    CGImageRef maskRef = [UIImage imageNamed:@"11"].CGImage;
    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                                            CGImageGetHeight(maskRef),
                                            CGImageGetBitsPerComponent(maskRef),
                                            CGImageGetBitsPerPixel(maskRef),
                                            CGImageGetBytesPerRow(maskRef),
                                            CGImageGetDataProvider(maskRef), NULL, false);
    CGContextClipToMask(context, rect, mask);
//    CGContextClipToMask(context, rect, maskRef);
    [[UIImage imageNamed:@"22"] drawInRect:rect];

这段示例中,两个CGContextClipToMask效果完全相反.
另外CGContextClipToMask如果使用half,那么遮罩之外的图片"22",会被切掉.(如图2-3)


2-1
2-2
2-3

3.使用图片作为蒙版
实质是生成新的图像,并且效果与上下文蒙版相似
CGImageRef CGImageCreateWithMask(CGImageRef image, CGImageRef mask);

CGImageRef imgRef = [UIImage imageNamed:@"avatar"].CGImage;
    CGImageRef maskRef = [UIImage imageNamed:@"11"].CGImage;
    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                                            CGImageGetHeight(maskRef),
                                            CGImageGetBitsPerComponent(maskRef),
                                            CGImageGetBitsPerPixel(maskRef),
                                            CGImageGetBytesPerRow(maskRef),
                                            CGImageGetDataProvider(maskRef), NULL, false);
    
    CGImageRef maskimg = CGImageCreateWithMask(imgRef, mask);
    imgv.image = [UIImage imageWithCGImage:maskimg];

露出了下面的背景色


image.png

4.混合模式蒙版
void CGContextSetBlendMode(CGContextRef c, CGBlendMode mode);
设置上下文的混合模式,CGBlendMode有很多种,具体参照文档.

CGContextSetFillColorWithColor(context, [UIColor colorWithRed:200/255.0 green:110/255.0 blue:180/255.0 alpha:1].CGColor);
    CGContextAddRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height/5));
    CGContextDrawPath(context, kCGPathFill);
    
    CGContextSetFillColorWithColor(context, [UIColor colorWithRed:190/255.0 green:190/255.0 blue:190/255.0 alpha:1].CGColor);
    CGContextAddRect(context, CGRectMake(0, rect.size.height/5, rect.size.width, rect.size.height/5));
    CGContextDrawPath(context, kCGPathFill);
    
    CGContextSetFillColorWithColor(context, [UIColor colorWithRed:240/255.0 green:70/255.0 blue:150/255.0 alpha:1].CGColor);
    CGContextAddRect(context, CGRectMake(0, rect.size.height/5*2, rect.size.width, rect.size.height/5));
    CGContextDrawPath(context, kCGPathFill);
    
    CGContextSetFillColorWithColor(context, [UIColor colorWithRed:140/255.0 green:220/255.0 blue:70/255.0 alpha:1].CGColor);
    CGContextAddRect(context, CGRectMake(0, rect.size.height/5*3, rect.size.width, rect.size.height/5));
    CGContextDrawPath(context, kCGPathFill);
    
    CGContextSetFillColorWithColor(context, [UIColor colorWithRed:16/255.0 green:128/255.0 blue:216/255.0 alpha:1].CGColor);
    CGContextAddRect(context, CGRectMake(0, rect.size.height/5*4, rect.size.width, rect.size.height/5));
    CGContextDrawPath(context, kCGPathFill);
    
    
    CGContextSetBlendMode(context, kCGBlendModeDifference);
    
    CGContextTranslateCTM(context, 0, rect.size.height);
    CGContextScaleCTM(context, 1, -1);
    CGContextDrawImage(context, rect, [UIImage imageNamed:@"22"].CGImage);

过程就是先画背景,然后设置模式,最后绘图


背景
混合效果,这里使用的是kCGBlendModeDifference

相关文章

网友评论

      本文标题:Core Graphics 五: 位图和遮罩

      本文链接:https://www.haomeiwen.com/subject/xlxgvktx.html