Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIImageJPEGRepresentation returns nil

I'm using CIFilters to convert an image to grayscale and apply some image processing effects. Displaying the output in a UIImageView works; the image displays and has been modified as expected.

However, calling UIImageJPEGRepresentation appears to return no data - every time. It never works. Calling UIImageJPEGRepresentation using the original color image works fine.

What's going on here? Why might the jpeg conversion fail when displaying the image works fine? No exceptions are thrown (setting an exception breakpoint, it's not hit) and no messages appear in the console.

let _cicontext = CIContext(options:nil)

// Set up grayscale and blur filters:
let grayIze = CIFilter(name: "CIColorControls")
let blur = CIFilter(name: "CIGaussianBlur")
grayIze.setValue(0, forKey:kCIInputSaturationKey)
grayIze.setValue(0.5, forKey: kCIInputBrightnessKey)
blur.setValue(4, forKey: kCIInputRadiusKey)

// Go!
let originalImage = CIImage(image: colorImageThatDefinitelyExists)
grayIze.setValue(originalImage, forKey: kCIInputImageKey)
blur.setValue(grayIze.outputImage, forKey: kCIInputImageKey)

let output = UIImage(CIImage: blur.outputImage)
let imageData: NSData? = UIImageJPEGRepresentation(output, 1.0) // Returns nil!?

Edit: Here is the working code, based on Arbitur's answer:

// Define an image context at the class level, which will only be initialized once:
static let imageContext = CIContext(options:nil)

// And here's the updated code in a function:
class func convertToGrayscale(image: UIImage)->UIImage?
{
    // Set up grayscale and blur filters:
    let filter1_grayIze = CIFilter(name: "CIColorControls")
    let filter2_blur = CIFilter(name: "CIGaussianBlur")
    filter1_grayIze.setValue(0, forKey:kCIInputSaturationKey)
    filter1_grayIze.setValue(0.5, forKey: kCIInputBrightnessKey)
    filter2_blur.setValue(4, forKey: kCIInputRadiusKey)

    // Go!
    let originalImage = CIImage(image: image)
    filter1_grayIze.setValue(originalImage, forKey: kCIInputImageKey)
    filter2_blur.setValue(filter1_grayIze.outputImage, forKey: kCIInputImageKey)
    let outputCIImage = filter2_blur.outputImage

    let temp:CGImageRef = imageContext.createCGImage(outputCIImage, fromRect: outputCIImage.extent())
    let ret = UIImage(CGImage: temp)
    return ret
}

// And finally, the function call:
    if let grayImage = ProfileImage.convertToGrayscale(colorImage)
    {
        let imageData: NSData? = UIImageJPEGRepresentation(grayImage, 1.0)
    }
like image 800
stone Avatar asked Apr 19 '15 16:04

stone


3 Answers

UIImageJPEGRepresentation seems to use the CGImage property of the UIImage. Problem is, that when you initialize the UIImage with a CIImage, that property is nil.

My solution was to add following block before the UIImageJPEGRepresentation call:

Last update Swift 5.1

if image.cgImage == nil {
    guard 
        let ciImage = image.ciImage, 
        let cgImage = CIContext(options: nil).createCGImage(ciImage, from: ciImage.extent) 
    else { 
         return nil 
    }

    image = UIImage(cgImage: cgImage)
}
like image 175
Daniel Avatar answered Nov 19 '22 17:11

Daniel


Ive had the problem before with CIImage and to work around that I made a CGImage with the CIImage and then a UIImage with the CGImage.

like image 12
Arbitur Avatar answered Nov 19 '22 18:11

Arbitur


The answer from Daniel is working great. Below his answer converted for usage in Swift4.

Swift4

    if image?.cgImage == nil {
        guard let ciImage = image?.ciImage, let cgImage = CIContext(options: nil).createCGImage(ciImage, from: ciImage.extent) else { return }

        image = UIImage(cgImage: cgImage)
    }
like image 4
Vincent Avatar answered Nov 19 '22 18:11

Vincent