Search code examples
iosuiimagecore-graphicstransparency

How to gray scale an image with transparent pixels making all of them opaque?


I'm using this function I found in this post to convert a colored image to a gray scaled one:

func grayScaleImage() -> UIImage {
    let imageRect = CGRectMake(0, 0, self.size.width, self.size.height);
    let colorSpace = CGColorSpaceCreateDeviceGray();

    let width = UInt(self.size.width)
    let height = UInt(self.size.height)
    let context = CGBitmapContextCreate(nil, width, height, 8, 0, colorSpace, .allZeros);
    CGContextDrawImage(context, imageRect, self.CGImage!);

    let imageRef = CGBitmapContextCreateImage(context);
    let newImage = UIImage(CGImage: imageRef)
    return newImage
}

I did some tests with some images that have transparent background, and the result I get is an image with black background. I'd like the transparent/translucent pixels to behave as if the background of the image were white, how could I do that?


Solution

  • To get the transparent part of your image to be white (or any other color), just draw a filled rectangle in the drawing context.

    Swift 3:

    extension UIImage {
        func grayScaleImage() -> UIImage {
            //let imageRect = CGRectMake(0, 0, self.size.width, self.size.height);
            let imageRect = CGRect(origin: CGPoint.zero, size: self.size)
            let colorSpace = CGColorSpaceCreateDeviceGray();
    
            let width = Int(self.size.width)
            let height = Int(self.size.height)
    
            let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: .allZeros)
    
            // set Fill Color to White (or some other color)
            context?.setFillColor(UIColor.white.cgColor)
            // Draw a white-filled rectangle before drawing your image
            context?.fill(imageRect)
    
            context?.draw(self.cgImage!, in: imageRect)
    
            let imageRef = context?.makeImage()
            let newImage = UIImage(cgImage: imageRef!)
            return newImage
        }
    }
    

    Swift 2.2:

    extension UIImage {
        func grayScaleImage() -> UIImage {
            let imageRect = CGRectMake(0, 0, self.size.width, self.size.height);
            let colorSpace = CGColorSpaceCreateDeviceGray();
    
            let width = Int(self.size.width)
            let height = Int(self.size.height)
            let context = CGBitmapContextCreate(nil, width, height, 8, 0, colorSpace, .allZeros);
    
            // set Fill Color to White (or some other color)
            CGContextSetFillColorWithColor(context, UIColor.whiteColor().CGColor)
            // Draw a white-filled rectangle before drawing your image
            CGContextFillRect(context, imageRect)
    
            CGContextDrawImage(context, imageRect, self.CGImage!);
    
            let imageRef = CGBitmapContextCreateImage(context);
            let newImage = UIImage(CGImage: imageRef!)
            return newImage
        }
    }