Manipulating photos with Core Image

In this chapter, you have already seen that iOS has powerful capabilities for recording and playing media. In this section, you will learn how you can manipulate images with Core Image. The Core Image framework provides many different filters that you can use to process both images and video. You will expand on the photo-taking capabilities that you implemented in the Captured app so users can grayscale and crop images.

Every Core Image filter you apply to images is an instance of the CIFilter class. You can create instances of filters as follows:

let filter = CIFilter(name: "CIPhotoEffectNoir")

The name parameter in the filter's initializer is expected to be a string that refers to a specific filter. You can refer to Apple's documentation on Core Image and the Core Image Filter Reference guide to see an overview of all the filters that you can use in your apps.

Every filter has a certain set of parameters that you need to set on the CIFilter instance to use the filter. For instance, a grayscale filter requires you to provide an input image. Other filters might take an intensity, location, or other properties. The best way to see how you can apply a filter to an image is through an example. Add the following implementation for applyGrayScale() to ImageViewController.swift to implement a grayscale filter:

@IBAction func applyGrayScale() {
  // 1
  guard let cgImage = selectedImage?.cgImage,
    // 2
    let initialOrientation = selectedImage?.imageOrientation,
    // 3
    let filter = CIFilter(name: "CIPhotoEffectNoir")
    else { return }

  // 4
  let sourceImage = CIImage(cgImage: cgImage)
  filter.setValue(sourceImage, forKey: kCIInputImageKey)

  // 5
  let context = CIContext(options: nil)
  guard let outputImage = filter.outputImage,
    let cgImageOut = context.createCGImage(outputImage, from: outputImage.extent)
    else { return }

  // 6
  selectedImage = UIImage(cgImage: cgImageOut, scale: 1, orientation: initialOrientation)
}

The preceding code has a lot of small, interesting details, highlighted with numbered comments. Let's go over the comments one by one to see how the grayscale filter is applied:

  1. The UIImage instance that is stored in selectedImage is converted to a CGImage instance. Strictly speaking, this conversion isn't required, but it does make applying other filters to the UIImage instance later a bit easier.
  2. One downside of using CGImage, instead of UIImage, is that the orientation information that is stored in the image is lost. To make sure the final image maintains its orientation, the initial orientation is stored.
  3. This step creates an instance of the grayscale filter.
  1. Since Core Image does not directly support CGImage instances, the CGImage instance is converted to a CIImage instance that can be used with Core Image. The CIImage instance is then assigned as the input image for the grayscale filter, by calling setValue(_:forKey:) on the filter.
  2. The fifth step extracts the new image from the filter, and uses a CIContext object to export the CIImage output to a CGImage instance.
  3. The sixth and final step is to create a new UIImage instance, based on the CGImage output. The initial orientation is passed to the new UIImage instance to make sure it has the same orientation as the original image.

Even though there are a lot of steps involved, and you need to convert between different image types quite a bit, applying the filter is relatively simple. Most of the preceding code takes care of switching between image types, while the filter itself is set up in just a couple of lines. Try running the app now and taking a picture. The initial picture will be in full color. After you apply the grayscale filter, the image is automatically replaced with a grayscale version of the image, as shown in the following screenshot:

The next filter you will implement is a crop filter. The crop filter will crop the image so that it's a square, rather than a portrait or landscape picture. The process for implementing the crop filter is mostly the same as the grayscale filter, except for the values that need to be passed to the crop filter. Add the following implementation for cropSquare() to implement the crop filter:

@IBAction func cropSquare() {
  let context = CIContext(options: nil)

  guard let cgImage = selectedImage?.cgImage,
    let initialOrientation = selectedImage?.imageOrientation,
    let filter = CIFilter(name: "CICrop")
    else { return }

  let size = CGFloat(min(cgImage.width, cgImage.height))
  let center = CGPoint(x: cgImage.width / 2, y: cgImage.height / 2)
  let origin = CGPoint(x: center.x - size / 2, y: center.y - size / 2)
  let cropRect = CGRect(origin: origin, size: CGSize(width: size, height: size))

  let sourceImage = CIImage(cgImage: cgImage)
  filter.setValue(sourceImage, forKey: kCIInputImageKey)
  filter.setValue(CIVector(cgRect: cropRect), forKey: "inputRectangle")

  guard let outputImage = filter.outputImage,
    let cgImageOut = context.createCGImage(outputImage, from: outputImage.extent)
    else { return }

  selectedImage = UIImage(cgImage: cgImageOut, scale: 1, orientation: initialOrientation)
}

The preceding code performs several calculations to figure out the best way to crop the image into a square. The CGRect instance that specifies the crop coordinates and size, which are then used to create a CIVector object. This object is then passed to the filter as the value for the inputRectangle key. Apart from specifying the crop values, the process of applying the filter is identical, so the code should look familiar to you.

If you run the app now and tap the crop button, the image will be cropped, as shown in the following screenshot:

There are many more filters available in Core Image, which you can play with to build pretty advanced filters. You can even apply multiple filters to a single image to create elaborate effects for the pictures in your apps. Because all filters work in very similar ways, it's relatively easy to apply any filter to your images once you understand how the general process of applying a filter works. You can always use the code from the preceding examples if you need a reminder about how to apply Core Image filters.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.14.219