Search code examples
iosswiftimagephotoediting

Creating a Photo Editor with Brightroom | Swift


The code I was shown for creating a Brightroom photo editor, that offers all of the different Brightroom features, was:

@IBAction func editImage(_ sender: Any) {
        guard let image = image else { return }
        let editor = Brightroom.Editor(image: image)
        present(editor.controller, animated: true, completion: nil)
    }

This code is now out-of-date and inaccurate. Additionally, the GitHub documentation is not very thorough. Would someone please show me how I could create the editor shown in the GitHub visual examples (image editor, photo cropping, masking)?

Brightroom Library


Solution

  • If you want to create a Photo Editor (or, add that functionality to your app), your best bet is to go through that Brightroom code and learn how to do it.

    However, if you want a quick example of presenting its built-in editor:

    @IBAction func editImage(_ sender: Any) {
    
        guard let image = UIImage(named: "samplePic")
        else {
            print("Could not load image named \"samplePic\"!")
            return
        }
            
        let imageProvider: ImageProvider = ImageProvider(image: image)
        
        let editingStack = EditingStack(imageProvider: imageProvider)
        
        let controller = ClassicImageEditViewController(editingStack: editingStack)
        
        present(controller, animated: true, completion: nil)
    
    }
    

    Edit - to answer question in comment...

    If you want to use this BrightRoom library - it's open-source. You really, really, REALLY need to spend time going through all of its code so you know and understand how to use it.

    After a quick look, it appears the approach to saving the edited image is to render it via the editing stack class.

    Here's a really simple, sample implementation...

    Notes:

    • ViewController must be in a navigation controller, as the "Classic" editor UI uses navBar buttons
      • view will turn red if it is NOT in a nav controller and print a message to the debug console
    • sample code loads an image named "samplePic" from assets (replace with your image name)
      • view will turn red if it CANNOT load the image and print a message to the debug console

    If we pass the above tests, we should see this (with whatever image you added):

    enter image description here

    Tapping the "Start Editing" button will push to the "Classic" editor controller. Tapping "Done" in the nav bar of that controller will pop back to this view and update the image view with the edited image.

    Please keep in mind -- This is Sample Code Only!!! I wouldn't expect it to be anything close to actual production use.

    import UIKit
    import BrightroomEngine
    import BrightroomUI
    
    class ViewController: UIViewController {
        
        var imgView = UIImageView()
        var editBtn = UIButton()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            guard let _ = self.navigationController
            else {
                print("This controller must be in a UINaviagationController !!!")
                view.backgroundColor = .red
                return
            }
            
            // replace with your image resource name
            let imgName: String = "samplePic"
            
            guard let image = UIImage(named: imgName)
            else {
                print("Could not load image named \"\(imgName)\"!")
                view.backgroundColor = .red
                return
            }
    
            imgView.image = image
            imgView.contentMode = .scaleAspectFit
            imgView.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
    
            editBtn.setTitle("Start Editing", for: [])
            editBtn.setTitleColor(.white, for: .normal)
            editBtn.setTitleColor(.lightGray, for: .highlighted)
            editBtn.backgroundColor = .systemBlue
    
            [imgView, editBtn].forEach { v in
                v.translatesAutoresizingMaskIntoConstraints = false
                view.addSubview(v)
            }
            
            let g = view.safeAreaLayoutGuide
            NSLayoutConstraint.activate([
                
                imgView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
                imgView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
                imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor),
                imgView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
                
                editBtn.topAnchor.constraint(equalTo: imgView.bottomAnchor, constant: 20.0),
                editBtn.widthAnchor.constraint(equalToConstant: 240.0),
                editBtn.centerXAnchor.constraint(equalTo: g.centerXAnchor),
    
            ])
            
            editBtn.addTarget(self, action: #selector(editTapped(_:)), for: .touchUpInside)
            
        }
        
        @objc func editTapped(_ sender: Any?) {
            
            guard let image = imgView.image
            else {
                print("Could not load image from image view!")
                return
            }
            
            let imageProvider: ImageProvider = ImageProvider(image: image)
            
            let editingStack = EditingStack(imageProvider: imageProvider)
            
            // create the "Classic" editing controller
            let controller = ClassicImageEditViewController(editingStack: editingStack)
            
            // set the closure for NavBar "Cancel" tap
            controller.handlers.didCancelEditing = { [weak self] vc in
                guard let self = self else { return }
                self.navigationController?.popViewController(animated: true)
            }
            
            // set the closure for NavBar "Done" tap
            controller.handlers.didEndEditing = { [weak self] vc, editStack in
                guard let self = self else { return }
                
                var img: UIImage!
                do {
                    let r = try editStack.makeRenderer().render()
                    let imgData = r.makeOptimizedForSharingData(dataType: .png)
                    img = UIImage(data: imgData)
                } catch {
                    print("error?", error)
                }
                if let img = img {
                    self.imgView.image = img
                }
                self.navigationController?.popViewController(animated: true)
                
            }
    
            // push to the editing controller
            self.navigationController?.pushViewController(controller, animated: true)
            
        }
        
    }