get the cgImage from a UIImage that was selected using UIImagePickerController

218 views Asked by At

I am trying to build something for my own learning where I select an image from my photo library then divide that image up into sections. I had found info on how to split a single UIImage into sections, but in order to do that I need to have access to the cgImage property of the UIImage object. My problem is, the cgImage is always nil/null when selecting an image from the UIImagePickerController. Below is a stripped down version of my code, I'm hoping someone knows why the cgImage is always nil/null...

class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
  @IBOutlet weak var selectButton: UIButton!
  let picker = UIImagePickerController()

  var image: UIImage!
  var images: [UIImage]!

  override func viewDidLoad() {
    super.viewDidLoad()
    picker.delegate = self
    picker.sourceType = .photoLibrary
  }

  @objc func selectPressed(_ sender: UIButton) {
    self.present(picker, animated: true)
  }

  func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info [UIImagePickerController.InfoKey : Any]) {
    guard let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else {
      self.picker.dismiss(animated: true, completion: nil)
      return
    }
    self.image = image
    self.picker.dismiss(animated: true, completion: nil)
    self.makePuzzle()
  }

  func makePuzze() {
    let images = self.image.split(times: 5)
  }
}
extension UIImage {
  func split(times: Int) -> [UIImage] {
    let size = self.size
    var xpos = 0, ypos = 0
    var images: [UIImage] = []
    let width = Int(size.width) / times
    let height = Int(size.height) / times
    for x in 0..<times {
      xpos = 0
      for y in 0..<times {
        let rect = CGRect(x: xpos, y: ypos, width: width, height: height)
        let ciRef = self.cgImage?.cropping(to: rect) //this is always nil
        let img = UIImage(cgImage: ciRef!) //crash because nil
        xpos += width
        images.append(img)
      }
      ypos += height
    }
    return images
  }
}

I can't seem to get the cgImage to be anything but nil/null and the app crashes every time. I know I can change the ! to ?? nil or something similar to avoid the crash, or add a guard or something, but that isn't really the problem, the problem is the cgImage is nil. I have looked around and the only thing I can find is how to get the cgImage with something like image.cgImage but that doesn't work. I think it has something to do with the image being selected from the UIImagePickerController, maybe that doesn't create the cgImage properly? Honestly not sure and could use some help. Thank you.

1

There are 1 answers

0
workingdog support Ukraine On

This is not an answer, just a beefed up comment with code. Your assumption that the problem may be due to the UIImagePickerController could be correct.

Here is my SwiftUI test code. It shows your split(..) code (with some minor mods) working.

extension UIImage {
    
    func split(times: Int) -> [UIImage] {
        let size = self.size
        var xpos = 0, ypos = 0
        var images: [UIImage] = []
        let width = Int(size.width) / times
        let height = Int(size.height) / times
        
        if let cgimg = self.cgImage { // <-- here
            for _ in 0..<times {
                xpos = 0
                for _ in 0..<times {
                    let rect = CGRect(x: xpos, y: ypos, width: width, height: height)
                    if let ciRef = cgimg.cropping(to: rect) { // <-- here
                        let img = UIImage(cgImage: ciRef)
                        xpos += width
                        images.append(img)
                    }
                }
                ypos += height
            }
        }
        return images
    }
    
}

struct ContentView: View {
    @State var imgSet = [UIImage]()
    
    var body: some View {
        ScrollView {
            ForEach(imgSet, id: \.self) { img in
                Image(uiImage: img).resizable().frame(width: 100, height: 100)
            }
        }
        .onAppear {
            if let img = UIImage(systemName: "globe") {  // for testing
                imgSet = img.split(times: 2)
            }
        }
    }
}