Search code examples
iosuiimagecore-imageuigraphicscontextciimage

Create CIImage Pattern from image file


I'm trying to understand what is the most efficient way to create a CIImage with a pattern, based on an image file.

let patternImage = UIImage(named: "pattern.png")

The first approach I took:

// First create UIColor pattern
let uiColorPattern = UIColor(patternImage: patternImage!) 

// Than init CIColor using the UIColor pattern object
let ciColorPattern = CIColor(color: uiColorPattern)

// Finally, create CIImage using the CIColor initialiser
let ciImagePattern = CIImage(color: ciColorPattern) //

Sadly, for unknown reason the CIImage is simply blank. I also tried applying clampedToExtent() and than cropping it but it still blank.

The second approach I took (works but too slow):

UIGraphicsBeginImageContext(size) // create context

patternImage?.drawAsPattern(in: rect) // draw pattern as 'UIImage'

let patternUIImage = UIGraphicsGetImageFromCurrentImageContext() // fetch 'UIImage'

UIGraphicsEndImageContext() // end context

if let patternUIImage = patternUIImage {
     let ciImagePattern = CIImage(image: patternUIImage) // Create 'CIImage' using 'UIImage'
}    

this method works but as I said, too slow.


In general, my intuition was that if I could make the first approach work, it'll be a lot more efficient than the second approach.

Any other approaches/suggestions would be highly appreciated!


Solution

  • The first approach you are taking would not work as From WWDC 2013:

    So, because, you know, and CIColor doesn't handle color spaces, it won't do CMYK color, it won't do patterns.

    So, these are all things that you're going to lose.

    If you ever think that you're going to need that, then probably not the right strategy.

    So the second approach is what we can optimise on. I have a snippet which returns a pattern image you can give it a try.

            let myImage = UIImage.init(named: "www")
            let imageSize = myImage?.size
            let imageWidth = imageSize?.width
            let imageHeight = imageSize?.height
            let widthIterations = self.view.bounds.size.width / imageWidth!
            let heightIterations = self.view.bounds.size.height / imageHeight!
    
            UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, true, UIScreen.main.scale)
            let context = UIGraphicsGetCurrentContext()
    
    
                for i in 0 ... Int(heightIterations) {
                    let yPoint = CGFloat(i) * imageHeight!
                    for j in 0 ... Int(widthIterations) {
                        let xPoint = CGFloat(j) * imageWidth!
                        myImage?.draw(at: CGPoint.init(x: xPoint, y: yPoint))
                    }
                }
            let tempImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
    

    enter image description here

    Further reading