iOS图形图像及核心动画实战二Block基础知识

本教程是一个合集,涉及到的目录结构:
基础知识总结
Block基础知识
GCD实战
CoreGraphics & ImageIO实战
CoreAnimation实战

Block是在iOS 4.0及以上系统才提供的一种类似于匿名函数(或闭包)的语法,它被定义在SDK中,所以基本上现在所有的开发人员都是不得不需要掌握的一项技能。

本篇文章也仅仅作为快速入门使用,不涉及底层实现,如对Block有所了解,请移步!

Block的基础结构剖析

先上张图:


Paste_Image.png

这张图应该很经典了,基本上不用Google,百度这个渣渣都能搜索到。

Block定义部分主要了解几个地方即可:

  • 符号中文叫:脱字符,定义Block时必须要写,也可以理解为有符号才应该是Block
  • Block可以有返回值,也就是图上最左边的int
  • Block有个名字,也就是图上的myBlock
  • Block可以带参数(并且可以多个),也就是图上的从左往右第二个int

Block实现部分主要了解几个地方即可:

  • 以脱字符打头
  • 括号内是参数
  • 使用花括号包起来,内部写实际的算法代码,然后该返回就返回(例如图上应该返回int)

Block实战

  • 最最有代表性的用法
int result = myBlock(10);
printf("%d",result);

这段代码会输出:70

  • 如果Block就仅仅上面这点用,那就太小看它了,我们来点最最实在的 -- 链式语法

链式语法白话理解就是先产生某个对象,没个函数操作实际又会返回它自己(其实也可以返回它自己类型的指针),然后一路 . 下去,不断的可以调用函数,最后一个函数即可得到一个最终结果。

例如下面代码,就是一路 . 下去:

maker.add(10).subtract(2).multiply(3).divide(4);

最终的结果为:6
以上计算步骤为:
0 + 10 = 10
10 - 2 = 8
8 * 3 = 24
24 / 4 = 6

哈哈哈,帅不帅!

我们剖析链式语法实现之前先来了解个东西:

  • property中用Block
@property (nonatomic,readonly) CaculatorMaker *(^add)(NSInteger number);
@property (nonatomic,readonly) CaculatorMaker *(^subtract)(NSInteger number);
@property (nonatomic,readonly) CaculatorMaker *(^multiply)(NSInteger number);
@property (nonatomic,readonly) CaculatorMaker *(^divide)(NSInteger number);
  • method中用Block
- (CaculatorMaker* (^)(NSInteger))add;
- (CaculatorMaker* (^)(NSInteger))subtract;
- (CaculatorMaker* (^)(NSInteger))multiply;
- (CaculatorMaker* (^)(NSInteger))divide;

Property中用Block,我想应该很容易理解,但是那个Method中用Block初学者很容易看蒙。蒙在哪呢,主要在add前面那个NSIneteger,其实这个是代表add的参数!😓

仔细剖析下:

Method中用Block

a -> 代表静态函数
b -> Block返回值、参数打头括号及结尾括号
c -> 返回值
d -> 表明这是一个Block(不需要名称)
e -> 参数(同样不需要名称)
f -> 函数命名

OK,准备工作都已做好,我们来看看链式语法的实操!

使用链式语法打造不一样的CoreImage

CoreImage是Apple封装好的一个滤镜操作库,它可以让我们很容易的对图像进行滤镜。

来来来,我们利用前面的Block基础知识以及链式语法的基础来实现一个最基本的棕色滤镜:

@interface CIImage (XPImage)

// 棕色滤镜
@property (nonatomic, readonly) CIImage *(^sepiaTone)(CGFloat intensity);

// 拉直滤镜
@property (nonatomic, readonly) CIImage *(^straightenFilter)(CGFloat angle);

- (CIImage* (^)(CGFloat intensity))sepiaTone {
    return ^CIImage* (CGFloat intensity) {
        CIFilter *sepiaFilter = [CIFilter filterWithName:@"CISepiaTone"];
        [sepiaFilter setValue:self forKey:kCIInputImageKey];
        [sepiaFilter setValue:@(intensity) forKey:kCIInputIntensityKey];
        return [sepiaFilter outputImage];
    };
}

- (CIImage*(^)(CGFloat angle))straightenFilter {
    return ^(CGFloat angle) {
        CIFilter *filter = [CIFilter filterWithName:@"CIStraightenFilter"];
        [filter setValue:self forKey:kCIInputImageKey];
        [filter setValue:@(angle) forKey:kCIInputAngleKey];
        return filter.outputImage;
    };
}

然后我们来测试下看看:

CIImage *ciimage = [CIImage imageWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"1_1.png"]];
UIImage *image = ciimage.sepiaTone(0.9).straightenFilter(0).UIImage;
self.imageView.image = image;
原图
滤镜后

啦啦啦,啦啦啦,我能装逼了~~~哈哈哈

言归正传,Block是一个浅入深出的技术,它最基本的用处是匿名函数,但是同时它如果配合其他的模式(如链式、GCD)就能产生无穷大的力量!

备注

CoreImage其实底层提供了非常多的滤镜,但是Apple没有很直接的暴露出来,只提供了一个获取滤镜的函数:
[CIFilter filterNamesInCategory:kCICategoryBuiltIn]
每个滤镜也可获取它的输入、输出参数:
CIFilter filter = [CIFilter filterWithName:name];
NSArray<NSString
> inputKeys = filter.inputKeys;
NSArray<NSString
> *outputKeys = filter.outputKeys;

附录

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

NS_ASSUME_NONNULL_BEGIN

@interface CIImage (XPImage)

// 棕色滤镜
@property (nonatomic, readonly) CIImage *(^sepiaTone)(CGFloat intensity);

// 仿射变换滤镜
@property (nonatomic, readonly) CIImage *(^affineTransform)(CGAffineTransform transform);

// 混合滤镜(给有Alpha通道的图片添加底层图片)
@property (nonatomic, readonly) CIImage *(^sourceAtopCompositing)(CIImage *backgroundImage);

// 拉直滤镜
@property (nonatomic, readonly) CIImage *(^straightenFilter)(CGFloat angle);

// 色彩控制滤镜
@property (nonatomic, readonly) CIImage *(^colorControls)(CGFloat bright,CGFloat contrast,CGFloat saturation);

// 反转颜色滤镜
@property (nonatomic,readonly) CIImage *(^colorInvert)(void);

@property (nonatomic,readonly)CIImage *(^accordionFoldTransition)(CIImage *targetImage,CGFloat bottomHeight,NSInteger numberOfFolds,NSInteger foldShadowAmount,CGFloat time);

@property (nonatomic,readonly)CIImage *(^additionCompositing)(CIImage *backgroundImage);

@property (nonatomic,readonly)CIImage *(^affineClamp)(CGAffineTransform transform);

@property (nonatomic,readonly)CIImage *(^affineTile)(CGAffineTransform transform);

//TODO: 下面的滤镜还未实现
@property (nonatomic,readonly)CIImage *(^areaHistogram)(NSString *extent,NSString *scale,NSString *count);
@property (nonatomic,readonly)CIImage *(^aztecCodeGenerator)(NSString *message,NSString *correctionLevel,NSString *layers,NSString *compactStyle);
@property (nonatomic,readonly)CIImage *(^barsSwipeTransition)(NSString *targetImage,NSString *angle,NSString *width,NSString *barOffset,NSString *time);
@property (nonatomic,readonly)CIImage *(^blendWithAlphaMask)(NSString *backgroundImage,NSString *maskImage);
@property (nonatomic,readonly)CIImage *(^blendWithMask)(NSString *backgroundImage,NSString *maskImage);
@property (nonatomic,readonly)CIImage *(^bloom)(NSString *radius,NSString *intensity);
@property (nonatomic,readonly)CIImage *(^bumpDistortion)(NSString *center,NSString *radius,NSString *scale);
@property (nonatomic,readonly)CIImage *(^bumpDistortionLinear)(NSString *center,NSString *radius,NSString *angle,NSString *scale);
@property (nonatomic,readonly)CIImage *(^checkerboardGenerator)(NSString *center,NSString *color0,NSString *color1,NSString *width,NSString *sharpness);
@property (nonatomic,readonly)CIImage *(^circleSplashDistortion)(NSString *center,NSString *radius);
@property (nonatomic,readonly)CIImage *(^circularScreen)(NSString *center,NSString *width,NSString *sharpness);
@property (nonatomic,readonly)CIImage *(^code128BarcodeGenerator)(NSString *message,NSString *quietSpace);
@property (nonatomic,readonly)CIImage *(^colorBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^colorBurnBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^colorClamp)(NSString *minComponents,NSString *maxComponents);
@property (nonatomic,readonly)CIImage *(^colorCrossPolynomial)(NSString *coefficients,NSString *redCoefficients,NSString *greenCoefficients,NSString *blueCoefficients);
@property (nonatomic,readonly)CIImage *(^colorCube)(NSString *cubeDimension,NSString *cubeData);
@property (nonatomic,readonly)CIImage *(^colorCubeWithColorSpace)(NSString *cubeDimension,NSString *cubeData,NSString *colorSpace);
@property (nonatomic,readonly)CIImage *(^colorDodgeBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^colorMap)(NSString *gradientImage);
@property (nonatomic,readonly)CIImage *(^colorMatrix)(NSString *rVector,NSString *gVector,NSString *bVector,NSString *aVector,NSString *biasVector);
@property (nonatomic,readonly)CIImage *(^colorMonochrome)(NSString *color,NSString *intensity);
@property (nonatomic,readonly)CIImage *(^colorPolynomial)(NSString *redCoefficients,NSString *greenCoefficients,NSString *blueCoefficients,NSString *alphaCoefficients);
@property (nonatomic,readonly)CIImage *(^colorPosterize)(NSString *levels);
@property (nonatomic,readonly)CIImage *(^constantColorGenerator)(NSString *color);
@property (nonatomic,readonly)CIImage *(^convolution3X3)(NSString *weights,NSString *bias);
@property (nonatomic,readonly)CIImage *(^convolution5X5)(NSString *weights,NSString *bias);
@property (nonatomic,readonly)CIImage *(^convolution9Horizontal)(NSString *weights,NSString *bias);
@property (nonatomic,readonly)CIImage *(^convolution9Vertical)(NSString *weights,NSString *bias);
@property (nonatomic,readonly)CIImage *(^copyMachineTransition)(NSString *targetImage,NSString *extent,NSString *color,NSString *time,NSString *angle,NSString *width,NSString *opacity);
@property (nonatomic,readonly)CIImage *(^crop)(NSString *rectangle);
@property (nonatomic,readonly)CIImage *(^darkenBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^differenceBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^disintegrateWithMaskTransition)(NSString *targetImage,NSString *maskImage,NSString *time,NSString *shadowRadius,NSString *shadowDensity,NSString *shadowOffset);
@property (nonatomic,readonly)CIImage *(^dissolveTransition)(NSString *targetImage,NSString *time);
@property (nonatomic,readonly)CIImage *(^divideBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^dotScreen)(NSString *center,NSString *angle,NSString *width,NSString *sharpness);
@property (nonatomic,readonly)CIImage *(^eightfoldReflectedTile)(NSString *center,NSString *angle,NSString *width);
@property (nonatomic,readonly)CIImage *(^exclusionBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^exposureAdjust)(NSString *eV);
@property (nonatomic,readonly)CIImage *(^falseColor)(NSString *color0,NSString *color1);
@property (nonatomic,readonly)CIImage *(^flashTransition)(NSString *targetImage,NSString *center,NSString *extent,NSString *color,NSString *time,NSString *maxStriationRadius,NSString *striationStrength,NSString *striationContrast,NSString *fadeThreshold);
@property (nonatomic,readonly)CIImage *(^fourfoldReflectedTile)(NSString *center,NSString *angle,NSString *width,NSString *acuteAngle);
@property (nonatomic,readonly)CIImage *(^fourfoldRotatedTile)(NSString *center,NSString *angle,NSString *width);
@property (nonatomic,readonly)CIImage *(^fourfoldTranslatedTile)(NSString *center,NSString *angle,NSString *width,NSString *acuteAngle);
@property (nonatomic,readonly)CIImage *(^gammaAdjust)(NSString *power);
@property (nonatomic,readonly)CIImage *(^gaussianBlur)(NSString *radius);
@property (nonatomic,readonly)CIImage *(^gaussianGradient)(NSString *center,NSString *color0,NSString *color1,NSString *radius);
@property (nonatomic,readonly)CIImage *(^glassDistortion)(NSString *texture,NSString *center,NSString *scale);
@property (nonatomic,readonly)CIImage *(^glideReflectedTile)(NSString *center,NSString *angle,NSString *width);
@property (nonatomic,readonly)CIImage *(^gloom)(NSString *radius,NSString *intensity);
@property (nonatomic,readonly)CIImage *(^hardLightBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^hatchedScreen)(NSString *center,NSString *angle,NSString *width,NSString *sharpness);
@property (nonatomic,readonly)CIImage *(^highlightShadowAdjust)(NSString *radius,NSString *shadowAmount,NSString *highlightAmount);
@property (nonatomic,readonly)CIImage *(^histogramDisplayFilter)(NSString *height,NSString *highLimit,NSString *lowLimit);
@property (nonatomic,readonly)CIImage *(^holeDistortion)(NSString *center,NSString *radius);
@property (nonatomic,readonly)CIImage *(^hueAdjust)(NSString *angle);
@property (nonatomic,readonly)CIImage *(^hueBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^lanczosScaleTransform)(NSString *scale,NSString *aspectRatio);
@property (nonatomic,readonly)CIImage *(^lightenBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^lightTunnel)(NSString *center,NSString *rotation,NSString *radius);
@property (nonatomic,readonly)CIImage *(^linearBurnBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^linearDodgeBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^linearGradient)(NSString *point0,NSString *point1,NSString *color0,NSString *color1);
@property (nonatomic,readonly)CIImage *(^linearToSRGBToneCurve)(void);
@property (nonatomic,readonly)CIImage *(^lineScreen)(NSString *center,NSString *angle,NSString *width,NSString *sharpness);
@property (nonatomic,readonly)CIImage *(^luminosityBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^maskToAlpha)(void);
@property (nonatomic,readonly)CIImage *(^maximumComponent)(void);
@property (nonatomic,readonly)CIImage *(^maximumCompositing)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^minimumComponent)(void);
@property (nonatomic,readonly)CIImage *(^minimumCompositing)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^modTransition)(NSString *targetImage,NSString *center,NSString *time,NSString *angle,NSString *radius,NSString *compression);
@property (nonatomic,readonly)CIImage *(^motionBlur)(NSString *radius,NSString *angle);
@property (nonatomic,readonly)CIImage *(^multiplyBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^multiplyCompositing)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^overlayBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^perspectiveCorrection)(NSString *topLeft,NSString *topRight,NSString *bottomRight,NSString *bottomLeft);
@property (nonatomic,readonly)CIImage *(^photoEffectChrome)(void);
@property (nonatomic,readonly)CIImage *(^photoEffectFade)(void);
@property (nonatomic,readonly)CIImage *(^photoEffectInstant)(void);
@property (nonatomic,readonly)CIImage *(^photoEffectMono)(void);
@property (nonatomic,readonly)CIImage *(^photoEffectNoir)(void);
@property (nonatomic,readonly)CIImage *(^photoEffectProcess)(void);
@property (nonatomic,readonly)CIImage *(^photoEffectTonal)(void);
@property (nonatomic,readonly)CIImage *(^photoEffectTransfer)(void);
@property (nonatomic,readonly)CIImage *(^pinchDistortion)(NSString *center,NSString *radius,NSString *scale);
@property (nonatomic,readonly)CIImage *(^pinLightBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^pixellate)(NSString *center,NSString *scale);
@property (nonatomic,readonly)CIImage *(^qRCodeGenerator)(NSString *message,NSString *correctionLevel);
@property (nonatomic,readonly)CIImage *(^radialGradient)(NSString *center,NSString *radius0,NSString *radius1,NSString *color0,NSString *color1);
@property (nonatomic,readonly)CIImage *(^randomGenerator)(void);
@property (nonatomic,readonly)CIImage *(^saturationBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^screenBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^sharpenLuminance)(NSString *sharpness);
@property (nonatomic,readonly)CIImage *(^sixfoldReflectedTile)(NSString *center,NSString *angle,NSString *width);
@property (nonatomic,readonly)CIImage *(^sixfoldRotatedTile)(NSString *center,NSString *angle,NSString *width);
@property (nonatomic,readonly)CIImage *(^smoothLinearGradient)(NSString *point0,NSString *point1,NSString *color0,NSString *color1);
@property (nonatomic,readonly)CIImage *(^softLightBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^sourceInCompositing)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^sourceOutCompositing)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^sourceOverCompositing)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^sRGBToneCurveToLinear)(void);
@property (nonatomic,readonly)CIImage *(^starShineGenerator)(NSString *center,NSString *color,NSString *radius,NSString *crossScale,NSString *crossAngle,NSString *crossOpacity,NSString *crossWidth,NSString *epsilon);
@property (nonatomic,readonly)CIImage *(^stripesGenerator)(NSString *center,NSString *color0,NSString *color1,NSString *width,NSString *sharpness);
@property (nonatomic,readonly)CIImage *(^subtractBlendMode)(NSString *backgroundImage);
@property (nonatomic,readonly)CIImage *(^swipeTransition)(NSString *targetImage,NSString *extent,NSString *color,NSString *time,NSString *angle,NSString *width,NSString *opacity);
@property (nonatomic,readonly)CIImage *(^temperatureAndTint)(NSString *neutral,NSString *targetNeutral);
@property (nonatomic,readonly)CIImage *(^toneCurve)(NSString *point0,NSString *point1,NSString *point2,NSString *point3,NSString *point4);
@property (nonatomic,readonly)CIImage *(^triangleKaleidoscope)(NSString *point,NSString *size,NSString *rotation,NSString *decay);
@property (nonatomic,readonly)CIImage *(^twelvefoldReflectedTile)(NSString *center,NSString *angle,NSString *width);
@property (nonatomic,readonly)CIImage *(^twirlDistortion)(NSString *center,NSString *radius,NSString *angle);
@property (nonatomic,readonly)CIImage *(^unsharpMask)(NSString *radius,NSString *intensity);
@property (nonatomic,readonly)CIImage *(^vibrance)(NSString *amount);
@property (nonatomic,readonly)CIImage *(^vignette)(NSString *intensity,NSString *radius);
@property (nonatomic,readonly)CIImage *(^vignetteEffect)(NSString *center,NSString *radius,NSString *intensity,NSString *falloff);
@property (nonatomic,readonly)CIImage *(^vortexDistortion)(NSString *center,NSString *radius,NSString *angle);
@property (nonatomic,readonly)CIImage *(^whitePointAdjust)(NSString *color);
@property (nonatomic,readonly)CIImage *(^zoomBlur)(NSString *radius,NSString *center);

/**
 *  @author huangxinping, 16-04-01
 *
 *  获取所有可用滤镜
 *
 *  @return 滤镜名称
 */
+ (NSArray<NSString*>*)filterNames;

/**
 *  @author huangxinping
 *
 *  从路径创建
 *
 *  @param path 路径
 *
 *  @return 实例
 */
+ (nullable instancetype)imageWithPath:(nonnull NSString*)path;

/**
 *  @author huangxinping, 16-04-01
 *
 *  转换到UIImage
 *
 *  @return UIImage
 */
- (nullable UIImage*)UIImage;

/**
 *  @author huangxinping, 16-04-01
 *
 *  是否是面部
 *
 *  @return YES-是面部;NO-不是面部
 */
- (BOOL)hasFace;

/**
 *  @author huangxinping, 16-04-01
 *
 *  检测有多少个特征(CIDetectorTypeFace、CIDetectorTypeRectangle、CIDetectorTypeQRCode、CIDetectorTypeText)
 *
 *  @return feature数组
 */
- (nullable NSArray<CIFeature*>*)featuresWithType:(nonnull NSString*)type;

/**
 *  @author huangxinping, 16-04-01
 *
 *  左眼位置
 *
 *  @return 位置数组(NSValue里面是CGPoint)
 */
- (nullable NSArray<NSValue*>*)leftEyePosition;

/**
 *  @author huangxinping, 16-04-01
 *
 *  右眼位置
 *
 *  @return 位置数组(NSValue里面是CGPoint)
 */
- (nullable NSArray<NSValue*>*)rightEyePosition;

/**
 *  @author huangxinping, 16-04-01
 *
 *  嘴巴位置
 *
 *  @return 位置数组(NSValue里面是CGPoint)
 */
- (nullable NSArray<NSValue*>*)mouthEyePosition;

@end

NS_ASSUME_NONNULL_END
#import "CIImage+XPImage.h"

@implementation CIImage (XPImage)

- (CIImage* (^)(CGFloat intensity))sepiaTone {
    return ^CIImage* (CGFloat intensity) {
        CIFilter *sepiaFilter = [CIFilter filterWithName:@"CISepiaTone"];
        [sepiaFilter setValue:self forKey:kCIInputImageKey];
        [sepiaFilter setValue:@(intensity) forKey:kCIInputIntensityKey];
        return [sepiaFilter outputImage];
    };
}

- (CIImage*(^)(CGAffineTransform transform))affineTransform {
    return ^(CGAffineTransform transform) {
        CIFilter *transFilter = [CIFilter filterWithName:@"CIAffineTransform"];
        [transFilter setValue:self forKey:kCIInputImageKey];
        [transFilter setValue:[NSValue valueWithCGAffineTransform:transform] forKey:kCIInputTransformKey];
        return transFilter.outputImage;
    };
}

- (CIImage*(^)(CIImage *backgroundImage))sourceAtopCompositing {
    return ^(CIImage *backgroundImage) {
        CIFilter *filter = [CIFilter filterWithName:@"CISourceAtopCompositing"];
        [filter setValue:self forKey:kCIInputImageKey];
        [filter setValue:backgroundImage forKey:kCIInputBackgroundImageKey];
        return filter.outputImage;
    };
}

- (CIImage*(^)(CGFloat angle))straightenFilter {
    return ^(CGFloat angle) {
        CIFilter *filter = [CIFilter filterWithName:@"CIStraightenFilter"];
        [filter setValue:self forKey:kCIInputImageKey];
        [filter setValue:@(angle) forKey:kCIInputAngleKey];
        return filter.outputImage;
    };
}

- (CIImage*(^)(CGFloat bright,CGFloat contrast,CGFloat saturation))colorControls {
    return ^(CGFloat bright,CGFloat contrast,CGFloat saturation) {
        CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"];
        [filter setValue:self forKey:kCIInputImageKey];
        [filter setValue:@(bright) forKey:kCIInputBrightnessKey];
        [filter setValue:@(contrast) forKey:kCIInputContrastKey];
        [filter setValue:@(saturation) forKey:kCIInputSaturationKey];
        return filter.outputImage;
    };
}

- (CIImage*(^)(void))colorInvert {
    return ^(void){
        CIFilter *filter = [CIFilter filterWithName:@"CIColorInvert"];
        [filter setValue:self forKey:kCIInputImageKey];
        return filter.outputImage;
    };
}

- (CIImage*(^)(CIImage *targetImage,CGFloat bottomHeight,NSInteger numberOfFolds,NSInteger foldShadowAmount,CGFloat time))accordionFoldTransition {
    return ^(CIImage *targetImage,CGFloat bottomHeight,NSInteger numberOfFolds,NSInteger foldShadowAmount,CGFloat time){
        CIFilter *filter = [CIFilter filterWithName:@"CIAccordionFoldTransition"];
        [filter setValue:self forKey:kCIInputImageKey];
        [filter setValue:targetImage forKey:kCIInputTargetImageKey];
        [filter setValue:@(bottomHeight) forKey:@"inputBottomHeight"];
        [filter setValue:@(numberOfFolds) forKey:@"inputNumberOfFolds"];
        [filter setValue:@(foldShadowAmount) forKey:@"inputFoldShadowAmount"];
        [filter setValue:@(time) forKey:@"inputTime"];
        return filter.outputImage;
    };

}

- (CIImage*(^)(CIImage *backgroundImage))additionCompositing {
    return ^(CIImage *backgroundImage) {
        CIFilter *filter = [CIFilter filterWithName:@"CIAdditionCompositing"];
        [filter setValue:self forKey:kCIInputImageKey];
        [filter setValue:backgroundImage forKey:kCIInputBackgroundImageKey];
        return filter.outputImage;
    };
}

- (CIImage*(^)(CGAffineTransform transform))affineClamp {
    return ^(CGAffineTransform transform) {
        CIFilter *filter = [CIFilter filterWithName:@"CIAffineClamp"];
        [filter setValue:self forKey:kCIInputImageKey];
        [filter setValue:[NSValue valueWithCGAffineTransform:transform] forKey:kCIInputTransformKey];
        return filter.outputImage;
    };
}

- (CIImage*(^)(CGAffineTransform transform))affineTile {
    return ^(CGAffineTransform transform) {
        CIFilter *filter = [CIFilter filterWithName:@"CIAffineTile"];
        [filter setValue:self forKey:kCIInputImageKey];
        [filter setValue:[NSValue valueWithCGAffineTransform:transform] forKey:kCIInputTransformKey];
        return filter.outputImage;
    };
}

+ (NSArray<NSString*>*)filterNames {
    return [CIFilter filterNamesInCategory:kCICategoryBuiltIn];
}

+ (instancetype)imageWithPath:(NSString*)path {
    NSURL *url = [NSURL fileURLWithPath:path];
    CIImage *coreImage = [CIImage imageWithContentsOfURL:url];
    return coreImage;
}

- (UIImage*)UIImage {
//    return [UIImage imageWithCIImage:self]; // 该函数每一次都会创建一个CIContext对象,对于频繁调用时会很消耗性能。代码如下:
    
//    EAGLContext *glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
//    if (!glContext) {
//        NSLog(@"Failed to create ES context");
//    }
//    CIContext *context = [CIContext contextWithEAGLContext:glContext]; // 使用GPU
//    CGImageRef cgimg = [context createCGImage:self fromRect:[self extent]];
//    UIImage *image = [UIImage imageWithCGImage:cgimg];
//    CGImageRelease(cgimg);
//    return image;
    
    // 为了提高性能,我们可以在init时,将CIContext就初始化好,后面直接使用
    static CIContext *context = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        EAGLContext *glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
        if (!glContext) {
            NSLog(@"Failed to create ES context");
        }
        context = [CIContext contextWithEAGLContext:glContext]; // 使用GPU
    });
    CGImageRef cgimg = [context createCGImage:self fromRect:[self extent]];
    UIImage *image = [UIImage imageWithCGImage:cgimg];
    CGImageRelease(cgimg);
    return image;
}

- (BOOL)hasFace {
    return [self featuresWithType:CIDetectorTypeFace].count?YES:NO;
}

- (NSArray<CIFeature*>*)featuresWithType:(NSString *)type {
    CIDetector *faceDetector = [CIDetector detectorOfType:type context:nil options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh}];
    CIImage *ciimg = [CIImage imageWithCGImage:[self UIImage].CGImage];
    NSArray<CIFeature*> *features = [faceDetector featuresInImage:ciimg];
    return features;
}

- (NSArray*)leftEyePosition {
    if (![self hasFace]) {
        return nil;
    }
    NSArray *features = [self featuresWithType:CIDetectorTypeFace];
    NSMutableArray *buffer = [NSMutableArray arrayWithCapacity:features.count];
    for (CIFaceFeature *f in features) {
        if (f.hasMouthPosition) {
            [buffer addObject:[NSValue valueWithCGPoint:f.leftEyePosition]];
        }
    }
    return buffer;
}

- (NSArray*)rightEyePosition {
    if (![self hasFace]) {
        return nil;
    }
    NSArray *features = [self featuresWithType:CIDetectorTypeFace];
    NSMutableArray *buffer = [NSMutableArray arrayWithCapacity:features.count];
    for (CIFaceFeature *f in features) {
        if (f.hasMouthPosition) {
            [buffer addObject:[NSValue valueWithCGPoint:f.rightEyePosition]];
        }
    }
    return buffer;
}

- (NSArray<NSValue*>*)mouthEyePosition {
    if (![self hasFace]) {
        return nil;
    }
    NSArray *features = [self featuresWithType:CIDetectorTypeFace];
    NSMutableArray *buffer = [NSMutableArray arrayWithCapacity:features.count];
    for (CIFaceFeature *f in features) {
        if (f.hasMouthPosition) {
            [buffer addObject:[NSValue valueWithCGPoint:f.mouthPosition]];
        }
    }
    return buffer;
}

@end

唯一遗憾:
本人只把CoreImage中所有滤镜全部定义了出来,实在太懒没写全函数实现,如有大神全部写全,请分享于我!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容