Blog

Tutorial: Convert Images to Grayscale in Swift

Apple provides a few ways of image grayscale conversion or applying grayscale on UIViews, but their results may vary. First, you should decide what you want to use it for and how it should work.

Table of Content

  1. TL;DR
  2. Ways to convert images to grayscale
  3. The first way - CIFilter
  4. The second way - CGColorSpaceCreateDeviceGray
  5. The third way - Swift

TL;DR

The three ways of applying grayscale on images in Swift I'm talking about in this article are:

  • CIFilter that adds grayscale, but take a while to keep the picture quality,
  • using CoreGraphics filters that take less time and can be applied on multiple images at one time, but turn transparent elements into color,
  • simply adding the grayscale option in View.

Want details? Follow me!

Ways to convert images to grayscale

The first way - CIFilter

When I think about gray-scaling an image, filters for pictures come to my mind immediately. There are plenty of apps that enable you to apply filters on images. And I think that's also the most common way of using grayscale in Swift.

In that case, I’d use CIFilter created just for adding effects and filters on images. CIFilter has a component called CIPhotoEffectNoir used for effects in iOS Photos app.

There also 2 similar effects that can be applied to images:

  • CIPhotoEffectMono,
  • and CIPhotoEffectTonal.

So if you simply want to add grayscale to your image without losing image quality, just apply this function:

func grayscale(image: UIImage) -> UIImage? {
    let context = CIContext(options: nil)
    if let filter = CIFilter(name: "CIPhotoEffectNoir") {
        filter.setValue(CIImage(image: image), forKey: kCIInputImageKey)
        if let output = filter.outputImage {
            if let cgImage = context.createCGImage(output, from: output.extent) {
                return UIImage(cgImage: cgImage)
            }
        }
    }
    return nil
}

Although this effect works like a charm, as all CIFilters, the problem is with timing. Changing the image with CIPhotoEffectNoir (or others) takes a couple of seconds. That's because CIFilters keep image quality. So if you want to convert more than one image at once, then well, it will take time.

The second way - CGColorSpaceCreateDeviceGray

Another option, which takes less time and can be implemented for more than one image at a time is CoreGraphics.

Let’s take a look at our function:

func convertToGrayScale(image: UIImage) -> UIImage? {
        let imageRect:CGRect = CGRect(x:0, y:0, width:image.size.width, height: image.size.height)
        let colorSpace = CGColorSpaceCreateDeviceGray()
        let width = image.size.width
        let height = image.size.height
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue)
        let context = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
        if let cgImg = image.cgImage {
            context?.draw(cgImg, in: imageRect)
            if let makeImg = context?.makeImage() {
                let imageRef = makeImg
                let newImage = UIImage(cgImage: imageRef)
                return newImage
            }
        }
        return UIImage()
    }

It works much faster, but also has its limitations. You cannot use CGImageAlphaInfo.none for images that contain transparent elements. It means all PNGs will be transformed into images without transparency. Clear background colors in images will turn black.

This can be also handled with replacing colors, but in this tutorial, I’d rather like to focus only on grayscale.

The third way - Swift

At last, I’ll show you the simplest way to convert images to grayscale. This one works only with SwiftUI, so you can’t use it for older apps. You simply add an option called grayscale in View:

func grayscale(_ amount: Double) -> some View

where "amount" is the intensity of grayscale you want to apply on a view. This option is very easy to implement, but you must remember that it also doesn’t work as fast as transforming an image to a CGColorSpace object.

Wrapping up

Now, that's it. I hope that thanks to this tutorial, the grayscale image conversion in Swift is no longer rocket science or black magic to you!

Check our latest product - it's based on our experience of managing over 50-people strong company. The tool we're missing as a small company and not an enterprise.

humadroid.io is an employee and performance management software. It's an unique tool allowing everyone to be in the loop - by having up to date info about co-workers, time-off, benefits, assets, helping with one-on-ones, being a go-to place for company-wide announcements.

Check out humadroid.io
Top

Contact us

* Required fields

The controller of your personal data provided via this contact form is Prograils sp. z o.o., with a registered seat at Sczanieckiej 9A/10, 60-215 Poznań. Your personal data will be processed in order to respond to your inquiries and for our marketing purposes (e.g. when you ask us for our post-development, maintenance or ad hoc engagements for your app). You have the rights to: access your personal data, rectify or erase your personal data, restrict the processing of your personal data, data portability and to object to the processing of your personal data. Learn more.

Notice

We do not track you online. We use only session cookies and anonymous identifiers for the purposes specified in the cookie policy. No third-party trackers.

I understand
Elo Mordo!Elo Mordo!