平时生活和工作中的iOSiOS图形处理相关ios

Quartz2D 编程指南(三)渐变、透明层 、数据管理

2016-05-13  本文已影响946人  xuyafei86
  1. 概览
  2. 图形上下文
  3. 路径
  4. 颜色与颜色空间
  5. 变换
  6. 图案
  7. 阴影
  8. 渐变
  9. 透明层
  10. Quartz 2D 中的数据管理
  11. 位图与图像遮罩
  12. CoreGraphics 绘制 Layer

渐变

简介

效果展示


CGShading 和 CGGradient 对象的对比

CGGradient CGShading
可以使用相同的 CGGradient 创建轴向和径向渐变 需要使用不同的 CGShading 创建轴向和径向渐变
CGGradient 的几何形状(轴向或径向)是在 Quartz 绘制时指定的 CGShading 的几何形状(轴向或径向)是在创建时指定的
Quartz 来计算渐变梯度上每个点对应的颜色值 你必须提供使用 CGFunctionRef 提供回调函数来计算渐变梯度上每个点对应的颜色值
可以轻松的定义多个定位点和颜色 需要设计我们自己的回调函数来定义多个定位点和颜色,因此更多的工作需要我们手动处理

扩展渐变端点外部的颜色


使用 CGGradient 绘制径向和轴向渐变

  1. 创建一个 CGGradient 对象,提供一个颜色空间,一个饱含两个或更多颜色组件的数组,一个包含两个或多个位置的数组,和两个数组中元素的个数。
  2. 调用 CGContextDrawLinearGradient 或 CGContextDrawRadialGradient 函数并提供一个上下文、一个 CGGradient 对象、绘制选项和开始结束几何图形来绘制渐变。
  3. 当不再需要时释放CGGradient对象。
- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect clip = CGRectInset(CGContextGetClipBoundingBox(context), 20.0, 20.0);
    CGContextClipToRect(context, clip);
    
    CGFloat locations[2] = {0.0, 1.0};
    CGFloat components[8] = {1.0, 0.5, 0.4, 1.0,  // Start color
                             0.8, 0.8, 0.3, 1.0}; // End color
    CGColorSpaceRef myColorspace = CGColorSpaceCreateDeviceRGB();
    CGGradientRef myGradient = CGGradientCreateWithColorComponents(myColorspace,
                                                                   components,
                                                                   locations,
                                                                   sizeof(components)/sizeof(components[0]));
              
    //绘制轴向渐变                                                     
    CGPoint myStartPoint = CGPointMake(CGRectGetMinX(clip), CGRectGetMinY(clip));
    CGPoint myEndPoint = CGPointMake(CGRectGetMinX(clip), CGRectGetMaxY(clip));
    CGContextDrawLinearGradient(context, myGradient, myStartPoint, myEndPoint, 0);
    
//    //绘制径向渐变
//    CGPoint myStartPoint = CGPointMake(50, 50);
//    CGPoint myEndPoint = CGPointMake(200, 200);
//    CGFloat myStartRadius = 20, myEndRadius = 100;
//    CGContextDrawRadialGradient (context, myGradient, myStartPoint,
//                                 myStartRadius, myEndPoint, myEndRadius,
//                                 kCGGradientDrawsAfterEndLocation);

}
CGFloat locations[2] = {0.0, 1.0};
CGGradientRef myGradient = CGGradientCreateWithColorComponents(myColorspace,
                                                               components,
                                                               NULL, // 相当于 {0.0, 1.0}
                                                               sizeof(components)/sizeof(components[0]));
CGPoint myStartPoint = CGPointMake(50, 50);
CGPoint myEndPoint = CGPointMake(200, 200);
CGFloat myStartRadius = 20, myEndRadius = 100;
CGContextDrawRadialGradient (context, myGradient, myStartPoint,
                             myStartRadius, myEndPoint, myEndRadius,
                             kCGGradientDrawsBeforeStartLocation);

使用 CGShading 绘制轴向渐变

  1. 设置 CGFunction 对象来计算颜色值
  2. 创建轴向渐变的 CGShading 对象
  3. 裁减上下文
  4. 使用 CGShading 对象来绘制轴向渐变
  5. 释放对象

1.设置 CGFunction 对象来计算颜色值

typedef void (*CGFunctionEvaluateCallback)(void * __nullable info, const CGFloat *  in, CGFloat *  out);
  1. void *info:这个值可以为 NULL 或者是一个指向传递给 CGShading 创建函数的数据。
  2. const CGFloat *in:Quartz 传递 in 数组给回调。数组中的值必须在 CGFunction 对象定义的输入值范围内。
  3. CGFloat *out:我们的回调函数传递 out 数组给 Quartz。它包含用于颜色空间中每个颜色组件的元素及一个 alpha 值。输出值应该在 CGFunction 对象定义的输出值范围内。
static void myCalculateShadingValues(void *info, const CGFloat *in, CGFloat *out) {
    CGFloat v;
    size_t k, components;
    static const CGFloat c[] = {1, 0, .5, 0};
    components = (size_t)info;
    v = *in;
    for(k = 0; k < components -1; k++)
        *out++ = c[k] * v;
    *out = 1;
}
static CGFunctionRef myGetFunction (CGColorSpaceRef colorspace) {
    static const CGFloat input_value_range[2] = {0, 1};
    static const CGFloat output_value_ranges[8] = {0, 1, 0, 1, 0, 1, 0, 1};
    static const CGFunctionCallbacks callbacks = {0, &myCalculateShadingValues, NULL};
    size_t  numComponents = 1 + CGColorSpaceGetNumberOfComponents (colorspace);
    return CGFunctionCreate((void *)numComponents,
                            1, input_value_range,
                            numComponents, output_value_ranges,
                            &callbacks);
}

2.创建轴向渐变的 CGShading 对象

CGPoint startPoint = CGPointMake(50, 100);
CGPoint endPoint = CGPointMake(300, 100);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFunctionRef myFunctionObject = myGetFunction(colorspace);
CGShadingRef myShading = CGShadingCreateAxial(colorspace,
                                              startPoint, endPoint,
                                              myFunctionObject,
                                              false, false);

3.裁减上下文

CGContextAddArc(context, 175, 175, 100, M_PI, 0, 0);
CGContextClosePath(context);
CGContextClip(context);

4.使用 CGShading 对象来绘制轴向渐变

CGContextDrawShading(context, myShading);

5.释放对象

CGShadingRelease (myShading);
CGColorSpaceRelease (colorspace);
CGFunctionRelease (myFunctionObject);

完整示例

void myPaintAxialShading(CGContextRef myContext, CGRect bounds) {
    CGPoint startPoint, endPoint;
    CGAffineTransform myTransform;
    CGFloat width = bounds.size.width;
    CGFloat height = bounds.size.height;
    
    startPoint = CGPointMake(0,0.5);
    endPoint = CGPointMake(1,0.5);
    
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    CGFunctionRef myShadingFunction = myGetFunction(colorspace);
    
    CGShadingRef shading = CGShadingCreateAxial(colorspace,
                                                startPoint, endPoint,
                                                myShadingFunction,
                                                false, false);
    
    myTransform = CGAffineTransformMakeScale(width, height);
    CGContextConcatCTM(myContext, myTransform);
    CGContextSaveGState(myContext);
    
    CGContextClipToRect(myContext, CGRectMake(0, 0, 1, 1));
    CGContextSetRGBFillColor(myContext, 1, 1, 1, 1);
    CGContextFillRect(myContext, CGRectMake(0, 0, 1, 1));
    
    CGContextBeginPath(myContext);
    CGContextAddArc(myContext, .5, .5, .3, 0, M_PI, 0);
    CGContextClosePath(myContext);
    CGContextClip(myContext);
    
    CGContextDrawShading(myContext, shading);
    CGColorSpaceRelease(colorspace);
    CGShadingRelease(shading);
    CGFunctionRelease(myShadingFunction);
    
    CGContextRestoreGState(myContext);
}

使用 CGShading 绘制径向渐变

  1. 设置 CGFunction 对象来计算颜色值
  2. 创建径向渐变的 CGShading 对象
  3. 使用 CGShading 对象来绘制径向渐变
  4. 释放对象

1.设置 CGFunction 对象来计算颜色值

static void  myCalculateShadingValues(void *info, const CGFloat *in, CGFloat *out) {
    size_t k, components;
    double frequency[4] = {55, 220, 110, 0};
    components = (size_t)info;
    for(k = 0; k < components - 1; k++)
        *out++ = (1 + sin(*in * frequency[k])) / 2;
    *out = 1;
}

static CGFunctionRef myGetFunction(CGColorSpaceRef colorspace) {
    static const CGFloat input_value_range[2] = {0, 1};
    static const CGFloat output_value_ranges[8] = {0, 1, 0, 1, 0, 1, 0, 1};
    static const CGFunctionCallbacks callbacks = {0, &myCalculateShadingValues, NULL};
    size_t numComponents = 1 + CGColorSpaceGetNumberOfComponents(colorspace);
    return CGFunctionCreate((void *)numComponents,
                            1, input_value_range,
                            numComponents, output_value_ranges,
                            &callbacks);
}

2.创建径向渐变的 CGShading 对象

CGPoint startPoint = CGPointMake(50, 50);
CGPoint endPoint = CGPointMake(250, 250);
CGFloat startRadius = 20;
CGFloat endRadius = 100;
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFunctionRef myShadingFunction = myGetFunction(colorspace);
CGShadingRef myShading = CGShadingCreateRadial(colorspace,
                                               startPoint,
                                               startRadius,
                                               endPoint,
                                               endRadius,
                                               myShadingFunction,
                                               false,
                                               false);

3.使用 CGShading 对象来绘制径向渐变

CGContextDrawShading(context, myShading);

4.释放对象

CGShadingRelease(myShading);
CGColorSpaceRelease(colorspace);
CGFunctionRelease(myShadingFunction);

完整示例

void myPaintRadialShading(CGContextRef myContext, CGRect bounds) {
    CGPoint startPoint,
    endPoint;
    CGFloat startRadius,
    endRadius;
    CGAffineTransform myTransform;
    CGFloat width = bounds.size.width;
    CGFloat height = bounds.size.height;
    
    startPoint = CGPointMake(0.25,0.3);
    startRadius = .1;
    endPoint = CGPointMake(.7,0.7);
    endRadius = .25;
    
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    CGFunctionRef myShadingFunction = myGetFunction(colorspace);
    
    CGShadingRef shading = CGShadingCreateRadial(colorspace,
                                                 startPoint, startRadius,
                                                 endPoint, endRadius,
                                                 myShadingFunction,
                                                 false, false);
    
    myTransform = CGAffineTransformMakeScale(width, height);
    CGContextConcatCTM(myContext, myTransform);
    CGContextSaveGState(myContext);
    
    CGContextClipToRect(myContext, CGRectMake(0, 0, 1, 1));
    CGContextSetRGBFillColor(myContext, 1, 1, 1, 1);
    CGContextFillRect(myContext, CGRectMake(0, 0, 1, 1));
    
    CGContextDrawShading(myContext, shading);
    CGColorSpaceRelease(colorspace);
    CGShadingRelease(shading);
    CGFunctionRelease(myShadingFunction);
    
    CGContextRestoreGState(myContext);
}

透明层


  1. 调用函数 CGContextBeginTransparencyLayer
  2. 在透明层中绘制需要组合的对象
  3. 调用函数 CGContextEndTransparencyLayer
- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetShadow(context, CGSizeMake(10, -20), 10);
    
    CGContextBeginTransparencyLayer(context, NULL);
    
    CGFloat wd = 300;
    CGFloat ht = 300;
    CGContextSetRGBFillColor(context, 0, 1, 0, 1);
    CGContextFillRect(context, CGRectMake (wd/3 + 50, ht/2, wd/4, ht/4));
    CGContextSetRGBFillColor(context, 0, 0, 1, 1);
    CGContextFillRect(context, CGRectMake (wd/3 - 50, ht/2 - 100, wd/4, ht/4));
    CGContextSetRGBFillColor(context, 1, 0, 0, 1);
    CGContextFillRect(context, CGRectMake (wd/3, ht/2 - 50, wd/4, ht/4));
    
    CGContextEndTransparencyLayer(context);
    
}

Quartz 2D 中的数据管理

简介

  1. URL:通过 URL 指定的数据可以作为数据的提供者和接收者。我们使用 CFURLRef 作为参数传递给 Quartz 函数。
  2. CFData:CFDataRef 和 CFMutableDataRef 可简化 Core Foundation 对象的内存分配行为。
  3. 原始数据:我们可以提供一个指向任何类型数据的指针,连同处理这些数据基本内存管理的回调函数集合。

传输数据给 Quartz 2D

CGImageSourceCreateWithDataProvider(CGDataProviderRef  _Nonnull provider, CFDictionaryRef  _Nullable options)
// To create an image source from a data provider.

CGImageSourceCreateWithData(CFDataRef  _Nonnull data, CFDictionaryRef  _Nullable options)
// To create an image source from a CFData object.

CGImageSourceCreateWithURL(CFURLRef  _Nonnull url, CFDictionaryRef  _Nullable options)
// To create an image source from a URL that specifies the location of image data.

CGPDFDocumentCreateWithURL(CFURLRef  _Nullable url)
// To create a PDF document from data that resides at the specified URL.

CGDataProviderCreateSequential(void * _Nullable info, const CGDataProviderSequentialCallbacks * _Nullable callbacks)
// To read image or PDF data in a stream. You supply callbacks to handle the data.

CGDataProviderCreateWithData(void * _Nullable info, const void * _Nullable data, size_t size, CGDataProviderReleaseDataCallback  _Nullable releaseData)
// To read a buffer of image or PDF data supplied by your application. You provide a callback to release the memory you allocated for the data.

CGDataProviderCreateWithURL(CFURLRef  _Nullable url)
// Whenever you can supply a URL that specifies the target for data access to image or PDF data.

CGDataProviderCreateWithCFData(CFDataRef  _Nullable data)
// To read image or PDF data from a CFData object.
  1. 使用函数 CGImageSourceCreateImageAtIndex, CGImageSourceCreateThumbnailAtIndex,CGImageSourceCreateIncremental 创建图像(CGImageRef)。 一个 CGImageRef 数据类型表示一个单独的 Quartz 图像。
  2. 通过函数 CGImageSourceUpdateData 或 CGImageSourceUpdateDataProvider 来添加内容到图像源中。
  3. 使用函数 CGImageSourceGetCount,CGImageSourceCopyProperties 和 CGImageSourceCopyTypeIdentifiers 获取图像源的信息。
  1. 图像创建函数。如 CGImageCreate,CGImageCreateWithPNGDataProvider 或者 CGImageCreateWithJPEGDataProvider。
  2. PDF 文档的创建函数 CGPDFDocumentCreateWithProvider。
  3. 函数 CGImageSourceUpdateDataProvider 用于更新已存在的图像源。

获取 Quartz 2D 的数据

CGImageDestinationCreateWithDataConsumer(CGDataConsumerRef  _Nonnull consumer, CFStringRef  _Nonnull type, size_t count, CFDictionaryRef  _Nullable options)
// To write image data to a data consumer.
    
CGImageDestinationCreateWithData(CFMutableDataRef  _Nonnull data, CFStringRef  _Nonnull type, size_t count, CFDictionaryRef  _Nullable options)
// To write image data to a CFData object.
    
CGImageDestinationCreateWithURL(CFURLRef  _Nonnull url, CFStringRef  _Nonnull type, size_t count, CFDictionaryRef  _Nullable options)
// Whenever you can supply a URL that specifies where to write the image data.
    
CGPDFContextCreateWithURL(CFURLRef  _Nullable url, const CGRect * _Nullable mediaBox, CFDictionaryRef  _Nullable auxiliaryInfo)
// Whenever you can supply a URL that specifies where to write PDF data.
    
CGDataConsumerCreateWithURL(CFURLRef  _Nullable url)
// Whenever you can supply a URL that specifies where to write the image or PDF data.
    
CGDataConsumerCreateWithCFData(CFMutableDataRef  _Nullable data)
// To write image or PDF data to a CFData object.
    
CGDataConsumerCreate(void * _Nullable info, const CGDataConsumerCallbacks * _Nullable cbks)
// To write image or PDF data using callbacks you supply.
  1. 使用函数 CGImageDestinationAddImage 或者 CGImageDestinationAddImageFromSource 添加一个图像(CGImageRef)到目标中。一个 CGImageRef 表示一个图片。
  2. 使用函数 CGImageDestinationSetProperties 设置属性
  3. 使用函数 CGImageDestinationCopyTypeIdentifiers 和 CGImageDestinationGetTypeID 从图像目标中获取信息。
  1. PDF上下文创建函数CGPDFContextCreate。该函数返回一个图形上下文,用于记录一系列的PDF绘制命令。
  2. 函数CGImageDestinationCreateWithDataConsumer,用于从数据消费者中创建图像目标。

博客:xuyafei.cn
简书:jianshu.com/users/2555924d8c6e
微博:weibo.com/xuyafei86
Github:github.com/xiaofei86

参考资料

上一篇 下一篇

猜你喜欢

热点阅读