封装CIImage实现实时渲染

封装CIImage实现实时渲染

CIImage属于CoreImage里面的东东,用来渲染图片的,为什么要封装它呢?其实很简单,封装好之后使用更加方便.

如果直接使用CIImage渲染图片,使用的流程如下:

只要你仔细研究一下CIImage,你会发现,filter部分与context部分是彼此分离的,context只接受一个CIImage,其他的都不管,所以,这个地方,我们就把它拆分成两部分,一部分是filter,一部分是context.

注:context部分执行了CIImage的渲染工作,CIImage的outputImage方法只是封装了要被渲染的步骤而已.

@property(readonly, nonatomic) CIImage *outputImage
Description    
Returns a CIImage object that encapsulates the operations configured in the filter. (read-only)

ImageFilter.h + ImageFilter.m

//
//  ImageFilter.h
//  CoreImageWapper
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreImage/CoreImage.h>

#pragma mark - 辅助内联函数
NS_INLINE CIImage* CIImageFromImage(UIImage *image)
{
    return [[CIImage alloc] initWithImage:image];
}

#pragma mark - 定义的block
typedef void(^ImageFilterConfigBlock_t)(CIFilter *filter);

@interface ImageFilter : NSObject

#pragma mark - 可读写属性
@property (nonatomic, strong, readwrite) CIImage   *inputCIImage;    // 输入CIImage
@property (nonatomic, strong, readwrite) NSString  *filterName;      // 滤镜名字

#pragma mark - 重写了getter方法,注意
@property (nonatomic, strong, readonly)  CIImage   *outputCIImage;   // 输出CIImage
@property (nonatomic, assign, readonly)  BOOL       filterNameValid; // 滤镜名合法性

#pragma mark - 初始化方法
- (instancetype)init;
- (instancetype)initWithFilterName:(NSString *)filterName;
- (instancetype)initWithFilterName:(NSString *)filterName inputCIImage:(CIImage *)inputCIImage;

#pragma mark - 配置
- (void)configFilter:(ImageFilterConfigBlock_t)block;

@end
//
//  ImageFilter.m
//  CoreImageWapper
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "ImageFilter.h"

NSArray *filterNameArray = nil;

@interface ImageFilter ()

@property (nonatomic, strong) CIFilter   *filter;

@end

@implementation ImageFilter

@synthesize outputCIImage   = _outputCIImage;
@synthesize filterNameValid = _filterNameValid;

+ (void)initialize
{
    if (self == [ImageFilter class])
    {
        filterNameArray = [CIFilter filterNamesInCategory:kCICategoryBuiltIn];;
    }
}

- (instancetype)init
{
    return [self initWithFilterName:nil inputCIImage:nil];
}

- (instancetype)initWithFilterName:(NSString *)filterName
{
    return [self initWithFilterName:filterName inputCIImage:nil];
}

- (instancetype)initWithFilterName:(NSString *)filterName inputCIImage:(CIImage *)inputCIImage
{
    self = [super init];
    if (self)
    {
        self.filterName   = filterName;
        self.inputCIImage = inputCIImage;
    }
    return self;
}

-(CIImage *)outputCIImage
{
    if (_filter)
    {
        return [_filter outputImage];
    }
    else
    {
        return nil;
    }
}

- (void)configFilter:(ImageFilterConfigBlock_t)block
{
    if (_filterName && _inputCIImage)
    {
        // 创建滤镜
        _filter = [CIFilter filterWithName:_filterName
                             keysAndValues:kCIInputImageKey, _inputCIImage, nil];

        // 设置滤镜
        block(_filter);
    }

    block(nil);
}

- (BOOL)filterNameValid
{
    BOOL flag = NO;

    if (_filterName)
    {
        for (NSString *name in filterNameArray)
        {
            if ([_filterName isEqualToString:name] == YES)
            {
                flag = YES;
                break;
            }
        }
    }

    return flag;
}

@end

ImageRender.h + ImageRender.m

//
//  ImageRender.h
//  CoreImageWapper
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "ImageFilter.h"

@interface ImageRender : NSObject

@property (nonatomic, strong) ImageFilter  *imageFilter;
@property (nonatomic, strong) UIImage      *outputImage;

- (instancetype)init;
- (instancetype)initWithImageFilter:(ImageFilter *)imageFilter;
- (UIImage *)render;

@end
//
//  ImageRender.m
//  CoreImageWapper
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "ImageRender.h"

@interface ImageRender ()

@property (nonatomic, strong) CIContext    *context;

@end

@implementation ImageRender

- (instancetype)init
{
    return [self initWithImageFilter:nil];
}

- (instancetype)initWithImageFilter:(ImageFilter *)imageFilter
{
    self = [super init];
    if (self)
    {
        // 基于GPU渲染
        self.context     = [CIContext contextWithOptions:nil];
        self.imageFilter = imageFilter;
    }
    return self;
}

- (UIImage *)render
{
    if (_imageFilter)
    {
        CIImage *outputCIImage = [_imageFilter outputCIImage];

        CGImageRef cgImage = [_context createCGImage:outputCIImage
                                            fromRect:[outputCIImage extent]];

        self.outputImage = [UIImage imageWithCGImage:cgImage];

        CGImageRelease(cgImage);
    }

    return self.outputImage;
}

@end

现在,你可以这么使用了:)

好吧,来一个复杂的看看,即时渲染:

- (void)viewDidLoad
{
    [super viewDidLoad];

    ImageFilter *filter = [ImageFilter new];
    ImageRender *render = [ImageRender new];

    filter.filterName = @"CIPixellate";
    filter.inputCIImage = CIImageFromImage([UIImage imageNamed:@"demo"]);
    [filter configFilter:^(CIFilter *filter) {
        [filter setValue:@1
                  forKey:@"inputScale"];
    }];
    render.imageFilter = filter;

    UIImageView *imageView = [[UIImageView alloc] initWithImage:[render render]];
    [self.view addSubview:imageView];
    imageView.center = self.view.center;

    _timer = [[GCDTimer alloc] initInQueue:[GCDQueue globalQueue]];
    [_timer event:^{

        static int i = 1;

        [filter configFilter:^(CIFilter *filter) {
            [filter setValue:[NSNumber numberWithInt:(i++)%10 + 1]
                      forKey:@"inputScale"];
        }];
        render.imageFilter = filter;

        [[GCDQueue mainQueue] execute:^{
            imageView.image = [render render];
        }];

    } timeInterval:NSEC_PER_SEC/10.f];
    [_timer start];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    ImageFilter *filter = [ImageFilter new];
    ImageRender *render = [ImageRender new];

    filter.filterName = @"CIHueAdjust";
    filter.inputCIImage = CIImageFromImage([UIImage imageNamed:@"demo"]);
    [filter configFilter:^(CIFilter *filter) {
        [filter setValue:@(3.14f)
                  forKey:@"inputAngle"];
    }];
    render.imageFilter = filter;

    UIImageView *imageView = [[UIImageView alloc] initWithImage:[render render]];
    [self.view addSubview:imageView];
    imageView.center = self.view.center;

    _timer = [[GCDTimer alloc] initInQueue:[GCDQueue globalQueue]];
    [_timer event:^{
        static int i = 0;
        [filter configFilter:^(CIFilter *filter) {
            [filter setValue:[NSNumber numberWithFloat:(i+=1)%314/100.f]
                      forKey:@"inputAngle"];
        }];
        render.imageFilter = filter;
        [[GCDQueue mainQueue] execute:^{
            imageView.image = [render render];
        }];
    } timeInterval:NSEC_PER_SEC/60.f];
    [_timer start];
}

附录:

https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CoreImageFilterReference/Reference/reference.html#//apple_ref/doc/uid/TP40004346

https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/CoreImageFilterReference/Reference/reference.html

https://developer.apple.com/library/ios/documentation/GraphicsImaging/Conceptual/CoreImaging/CoreImage.pdf

http://www.rapidsnail.com/Tutorial/t/2012/112/30/22766/the-coreimage-ios.aspx

http://www.raywenderlich.com/zh-hans/24773/%E5%88%9D%E5%AD%A6ios6-%E4%B8%AD%E7%9A%84core-image%E6%8A%80%E6%9C%AF

http://my.safaribooksonline.com/book/video/9780321637031/chapter-15dot-secret-patches-core-image-filters-and-glsl-pushing-the-boundaries/ch15sec1lev5

http://stackoverflow.com/questions/17041669/creating-a-blurring-overlay-view/17041983#17041983

 

 

 

时间: 2025-01-27 21:18:18

封装CIImage实现实时渲染的相关文章

多谢各位大哥了-使用Camera2实时渲染图像中图片转码的问题

问题描述 使用Camera2实时渲染图像中图片转码的问题 各位大神,现在有一个问题,懂的帮帮忙. 我现在在做Camera2实时渲染图片的项目 问题是这样的: 我已经实现了5.0以下的Camera数据转码及实时渲染,是使用的RS. 因为设备不支持NV21,所以采用JPEG的格式输出,但最后想要转到RGB的格式. 在网上找了找,并没有合适的解决方法,还有我使用JPEG的格式保存到本地是可以正常显示出图片,但使用YUV420_888则看到的是黑色的图像(不知道这是不是图像没有处理的原因),我想问的是J

Weex 实时渲染插件

强大的Weex已开源, 截止现在 Star 的数量已经达到了3576, 简直赞到不行呀~~~~ 为了方便大家更加便捷的开发 Weex 页面, 小弟写了一款 Intellij 的插件, 目前亲测可用的几款IDE 有 Intellij Idea, Android Studio, Web Storm, 下面简单的为大家介绍一些这款插件的功能以及使用方法 功能介绍: 支持自动实时将Weex编译成JavaScript bundle. 能够在插件运行时启动本地服务,实时的将修改的内容渲染成HTML5,并显示

在 Android 下进行实时模糊渲染

本文讲的是在 Android 下进行实时模糊渲染, 模糊渲染 模糊渲染能生动地表达内容间的层次感.当专注于当前特定内容的时候,它允许用户维持相对的上下文,即使模糊层下面的内容发生了视差移动或者动态变化. 在IOS开发中,我们首先可以通过构造UIVisualEffectView获得这种模糊效果: UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; UIVisualEffectView

OpenGLES渲染

OpenGLES渲染 OpenGLES使用GPU渲染图片,不占用CPU,但其使用还是挺复杂的. 先用OpenGLES显示一张图片: // // ShowViewController.m // OpenGLES // // Copyright (c) 2014年 Y.X. All rights reserved. // #import "ShowViewController.h" #import <GLKit/GLKit.h> #import <CoreImage/Co

面向设计的半封装web组件开发(概要版)

一.传统web组件的妄想 目前很多Team和团队都有自己的一套web组件体系,模块化开发,封装良好,上手简单.然后希望该web组件可以应用到接手的各个项目中,节约日后的开发成本.甚至考虑开源. 这其实是很棒的,但是呢,希望一套web组件各个项目通用?在我看来,除非对项目没有追求,否则不太现实. 但是呢,希望一套web组件各个项目通用?在我看来,除非对项目没有追求,否则就是妄想. 为什么说传统web组件想一统天下不现实呢?因为就像秦始皇一统天下一样,要牺牲很多很多东西. 牺牲代码量 web组件要想

《疯狂动物城》 —浪潮分布式存储让动画渲染更高效

<疯狂动物城>这部以动物为主题的迪士尼动画很火爆,在华上映10天票房已达7.47亿,豆瓣评分达到9.3分.里边许多小细节很有趣:恶搞现实世界的品牌,星巴克logo换成了长颈鹿,NIKE的"just zoo it",还有慢到令人发笑却有个名字叫闪电的树獭.不过,这和分布式存储能扯上什么关系呢? 渲染耗时1000万小时以上,"拖延症"咋治疗? 有一些拍摄花絮你可能没注意,<疯狂动物城>是迪斯尼迄今为止最长的动画电影之一,片长达108分钟,50多个

物理渲染-基于物理的光照模型

文章所用图片来自相关领域文献,如有侵权请联系撤除, 转载本文请注明出处 1.关于光照模型 对于图形学领域和图形学开发来说,实时渲染的光照模型是一个最最基础的问题,简单的来讲,光照模型就是用来描述在真实环境下,物体表面一点在在光照下的反射颜色值.有许许多多的光照模型试图用数学的公式来模拟这个问题,当然这即是一个物理问题,也是一个数学问题.大学时最初接触计算机图形学时,对书本上关于光照模型的推到过程就极为不解,最近为了研究基于物理的光照模型看到一篇10年siggrgrah的course,(<Phys

使用IBInspectable和IBDesignable实现实时预览

Xcode6提供了这样一个激动人心的feature,在设计项目的时候建立一个自定义的界面来使你可以配置自定义的属性并控制它们实时显示出来,用IBInspectable和IBDesignable来完成. IBInspectable IBInspectable 属性提供了访问旧功能的新方式:用户自定义的运行时属性.从目前的身份检查器(identity inspector)中访问,这些属性在 Interface Builder 被整合到 Xcode 之前就可用了.他们提供了一个强有力的机制来配置一个

开源一个上架App Store的相机App

Osho 相机是我独立开发上架的一个相机 App.它支持1:1,4:3,16:9多种分辨率拍摄,滤镜可在取景框的实时预览,拍摄过程可与滤镜实时合成,支持分段拍摄,支持回删等特性.下面先分享分享开发这个 App 的一些心得体会,文末会给出项目的下载地址,阅读本文可能需要一点点 AVFoundation 开发的基础.  1.GLKView和GPUImageVideoCamera 一开始取景框的预览我是基于 GLKView 做的,GLKView 是苹果对 OpenGL 的封装,我们可以使用它的回调函数