天天品尝iOS7甜点 :: Day 15 :: CoreImage Filters

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


Introduction - 介绍

在iOS5中就引入了CoreImage这个框架,它是用来进行图像处理的。它抽象所有低级的与图像处理有关联的方法,从用户角度提供易于使用的过滤事件链架构。i0S7中介绍了新的过滤器,其中的一些,我们将会在进行的文章中介绍,我们将会来看看一些传统的图像过滤效果,然后在查看创建具有过滤效果的生成二维码的效果。

本章的实例程序能够在github上面进行访问,访问地址:github.com/ShinobiControls/iOS7-day-by-day

Photo Effect Filters - 图像过滤效果

在移动应用程序世界里,能够应用比较酷的图片效果是一种趋势。例如instagram就十分的流行。CoreImage添加了很多十分简单的是可以使用的过滤效果来帮助我们在应用程序中添加很多功能。

为了能够使用这些过滤器,我们需要首先为CoreImage做点功课。CoreImage指定它自己的图像类型-CIImage,它可以从很多不同的源被创建,包括与CoreGraphics等价的CGImage

1
2
UIImage *_inputUIImage = [UIImage imageNamed:@"shinobi-badge-head.jpg"];
CIImage *_inputImage = [CIImage imageWithCGImage:[_inputUIImage CGImage]];

使用过滤器十分的简单,而且你还可以把他们串联起来,但是我们的目的是指定一个简单的过滤器:

1
2
CIFilter *filter = [CIFilter filterWithName:@"CIPhotoEffectChrome"];
[filter setValue:_inputImage forKey:kCIInputImageKey];

一个CoreImage过滤器就是代表了一个CIFilter类,它可以通过一个工厂方法来创建一个指定的过滤器对象。这些过滤器对象都是通过使用KVC的方式来指定相关的过滤参数的。所有的新图像的过滤器都是通过这些简单的属性-输入的图像,它指定使用一个字符串kCIInputImageKey表示的key值。

然后我们可以把获得的过滤器输出的图像转换成UIImage,然后展示在UIImageView上面:

1
UIImage *outputImage = [UIImage imageWithCIImage:filter.outputImage];

新的图像的效果过滤器引用的key值有下面的一些:

1
2
3
4
5
6
7
8
@"CIPhotoEffectChrome"
@"CIPhotoEffectFade"
@"CIPhotoEffectInstant"
@"CIPhotoEffectMono"
@"CIPhotoEffectNoir"
@"CIPhotoEffectProcess"
@"CIPhotoEffectTonal"
@"CIPhotoEffectTransfer"

在今天我们需要完成的是一个示例是我们有一个collection视图,他们用来示范同一个输入的图像在新的过滤器上面的不同输出图像。

我们还需要构造CGImage版本对应每个CIImage过滤输出。这是因为属性outputImage是懒加载的。为了达到目的,我们使用一个CIContext来绘制CIImageCoreGraphics的上下文中:

1
2
3
4
5
CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:filter.outputImage fromRect:filter.outputImage.extent];
UIImage *image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);

[images addObject:image];

接下来的程序都是写在SCPhotoFiltersViewController中的使用了自定义的cell。如果你运行程序,你可以看到下面不同的过滤效果:

QR Code Generation - 生成二维码

在iOS7中添加的图像效果过滤器中也引入了一个过滤器,它可以有能力来生成一个二维码来代表特性的数据对象。在应用程序的第二个页签(SCQRGeneratorViewController)示例中,当’Generate’按钮点击之后,文本框中的内容就会被编码到二维码中,展示出来。

生成二维码的代码也是十分的简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
- (CIImage *)createQRForString:(NSString *)qrString {
// Need to convert the string to a UTF-8 encoded NSData object
NSData *stringData = [qrString dataUsingEncoding:NSUTF8StringEncoding];

// Create the filter
CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
// Set the message content and error-correction level
[qrFilter setValue:stringData forKey:@"inputMessage"];
[qrFilter setValue:@"H" forKey:@"inputCorrectionLevel"];

// Send the image back
return qrFilter.outputImage;
}

生成二维码的过滤器需要一个NSData对象,所以我们首先把NSString对象使用UTF-8的编码转换成一个NSData对象。

然后和之前我们做的一样,创建一个CIFilter对象,使用filterWithName:工厂方法,指定名字为CIQRCodeGenerator,这种情况下面我们需要设置两个key,一个是设置inputMessage,它代表我们刚刚创建的NSData对象,还有一个inputCorrectionLevel用来指定生成二维码的等级,一共有4中等级:

  • L 7%的错误弹性
  • M 15%的错误弹性
  • Q 25%的错误弹性
  • H 30%的错误弹性

一旦我们完成了这些,然后我们可以返回一个过滤器的输出图像,它是一个1pt的最小的分辨率的CIImage对象。

我们想要重设这个图像的大小,但是我们并不想对它进行篡改。为了达到这个目的,我们创建一个新的方法来进行图像的调整:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (UIImage *)createNonInterpolatedUIImageFormCIImage:(CIImage *)image withScale:(CGFloat) scale {
// Render the CIImage into a CGImage
CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:image fromRect:image.extent];

// Now we'll rescale using CoreGraphics
UIGraphicsBeginImageContext(CGSizeMake(image.extent.size.width * scale, image.extent.size.width * scale));
CGContextRef context = UIGraphicsGetCurrentContext();
// We don't want to interpolate (since we've got a pixel-corrent image)
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
CGContextDrawImage(context, CGContextGetClipBoundingBox(context), cgImage);
// Get the image out
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
// Tidy up
UIGraphicsEndImageContext();
CGImageRelease(cgImage);
return scaledImage;
}

这个上面的例子一样,我们首先创建了一个CGImage来代表CIImage.然后我们创建一个核心的图像上下文来重新调节。最重要的一行是设置质量不能篡改。如果我们重新调节图像,它看来就是十分可怕的,并且形成像素化,但是这里我们就是需要像素化的二维码:

1
CGContextSetInterpolationQuality(context, kCGInterpolationNone);

一旦我们绘制这个图像到上下文中,我们就可以抓住这个形成的UIImage然后返回它。到此为止,我们完成的生成器就像这个样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (IBAction)handleGenerateButtonPressed:(id)sender {
// Disable the UI
[self setUIElementsAsEnabled:NO];
[self.stringTextField resignFirstResponder];

// Get the string
NSString *stringToEncode = self.stringTextField.text;

// Generate the image
CIImage *grCode = [self createQRForString:stringToEncode];

// Convert to an UIImage
UIImage *qrCodeImg = [self createNonInterpolatedUIImageFromCIImage:qrCode withScale 2 * [[UIScreen mainScreen] scale]];

// And push the image on to the screen
self.qrImageView.image = qrCodeImg;

// Re-enable the UI
[self setUIElementsAsEnable:YES];
}

这里还有一个工具的方法来用进行禁用UI的(当生成二维码过程中):

1
2
3
4
- (void)setUIElementsAsEnabled:(BOOL)enabled {
self.generateButton.enabled = enabled;
self.stringTextField.enabled = enabled;
}

如果你运行应用程序,你就会看到可以有能力随时生成二维码,这是我们不做处理,以后我们就可以给出一个方法来阅读他们.

Conclusion

CoreImage是一个方便的框架做一些相当先进的图像处理,而不必太涉及低级图像处理。它的怪癖,但它可以是非常有用的。与新图像过滤器和QR代码生成器可能就挽救了你找到一个外部依赖项或编写自己的版本。

本文翻译自:iOS7 Day-by-Day :: Day 15 :: CoreImage Filters

文章目录
  1. 1. Introduction - 介绍
  2. 2. Photo Effect Filters - 图像过滤效果
  3. 3. QR Code Generation - 生成二维码
  4. 4. Conclusion
,