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中所有濾鏡全部定義了出來,實在太懶沒寫全函數實現,如有大神全部寫全,請分享于我!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容