iOS – Tap to zoom and share image using Apple’s QuickLook framework

QuickLook framework is one of the best framework by Apple. It can be used to preview files such as iWork, MS Office, RTF, CSV documents, pdf, text files, Images.

You can use this framework to implement image zooming and sharing feature. We don’t need to write this zooming and sharing code ourself. QuickLook framework provides this all awesome functionality.

Let’s start implementing this powerful and easy framework.
(I have used Swift 3 and XCode 8.3.2)

*  Use Single View application template and give a name to your project(App). Select Swift language.

* On Storyboard make your view controller UI like this :  Check this image.
Take 2 UIImageViews  and take 1 UIButton on each UIImageView. Create necessary IBOutlets and IBActions.

* Your final ViewController Code should look like below.


import UIKit
import QuickLook   // Import QuickLook to use it’s functionalities.

let imageURLs =  [“https://static2.hdwallpapers.net/wallpapers/2015/03/24/574/thumb_steve-jobs-typographic-portrait.jpg”, “http://www.planetware.com/photos-large/F/france-paris-eiffel-tower.jpg”]

class Downloader  {    // This is Image Downloader helper class
        class func downloadImageWithURL(_ url:String) -> UIImage? {
               let data = try? Data(contentsOf: URL(string: url)!)

if
let imgData = data {
                   return UIImage(data: imgData)
               }

              else {
                  print(“\n\nThis image url may be wrong : \n \(url)”)
                  return nil
               }

    }

}


class iOSConcurrencyViewController: UIViewController, QLPreviewControllerDataSource

    // Connect this 2 imageView outlets with your imageViews.
    @IBOutlet weak var imageView1: UIImageView!  
    @IBOutlet weak var imageView2: UIImageView!

   // Connect this outlet with Bar button named – Start
    @IBOutlet
weak var barButton_Start: UIBarButtonItem!

   let quickLookController = QLPreviewController()
   var myQLimageURL: URL?

    override func viewDidLoad() {

        super.viewDidLoad()

       // Add QuickLook dataSource to  self
       quickLookController.dataSource =
self

    }

@IBAction func didClickOnStart(_ sender: AnyObject) {  // Connect this IBAction with Bar button item – Start

        // Here we will start downloading images and then disable the start button.
        barButton_Start.isEnabled = false

        //   ##################  Dispatch Queues ##################

         // Default(System provided) global Dispatch queue

        // It can download any image in any order at any time once started.

        let imgDownloader_DefaultConcurrentQueue = DispatchQueue.global(qos: .default)

        //img1

        downloadUsingGCD_AndShowImage(in: imageView1, index: 0, with: imgDownloader_DefaultConcurrentQueue)

        //img2

        downloadUsingGCD_AndShowImage(in: imageView2, index: 1, with: imgDownloader_DefaultConcurrentQueue)

}

 

// For GCD – Dispatch Queues

    func downloadUsingGCD_AndShowImage(in imageView: UIImageView, index imageIndex: Int, with Queue: DispatchQueue) {

            Queue.async {  // To avoid blocking UI, download images in background.

            let img = Downloader.downloadImageWithURL(imageURLs[imageIndex])

            let fileParts = imageURLs[imageIndex].components(separatedBy: “/”)

            DispatchQueue.main.async { // UI update code should be on main thread.

                imageView.image = img

                self.saveImageToDirectory(imageName: fileParts.last!, img: img!)

            }

        }

    }


// You have used a button on each imageView. Give 0 tag for button1 and 1 for button2. Then connect both buttons IBAction to this.
@IBAction func button_ZoomImage_Tapped(_ sender: UIButton) {

        var index = Int()

        switch sender.tag {

        case 0:

            index = 0

        case 1:

            index = 1

        default:

            break

        }

        // Get image name with extension from image url
        let fileParts = imageURLs[index].components(separatedBy: “/”)

        myQLimageURL = getImageFromDirectory(imageName: fileParts.last!) 

        if let QLImgURL = myQLimageURL {

            if QLPreviewController.canPreview(QLImgURL as QLPreviewItem) { 

                // This line refreshes current preview otherwise you will see only 1 image for both image views.
                quickLookController.refreshCurrentPreviewItem() 

                //navigationController?.pushViewController(quickLookController, animated: true)

                            present(quickLookController, animated: true, completion: {

                                print(“completion block”)

                            })

            }

        }

    }

 

    // Get Documents Directory helper function

    func getDocumentsDirectory() -> URL {

        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)

        let documentsDirectory = paths[0]

        return documentsDirectory

    }

    

    // Save Image to Directory

    func saveImageToDirectory(imageName: String, img: UIImage) {

        //if let image = UIImage(named: imageName) {

            if let data = UIImageJPEGRepresentation(img, 0.8) {

                let filename = getDocumentsDirectory().appendingPathComponent(imageName)

                try? data.write(to: filename)

            }

        //}

    }

    

    // Get Image from Directory

    func getImageFromDirectory(imageName: String) -> URL? {

        let imageURL = getDocumentsDirectory().appendingPathComponent(imageName)

        let imagePath = (getDocumentsDirectory().appendingPathComponent(imageName)).path

        if FileManager.default.fileExists(atPath: imagePath) {

            return imageURL

        }

        else {

            return nil

        }

    }

    

    // QuickLook Datasource
    func numberOfPreviewItems(in controller: QLPreviewController) -> Int {

        return 1    // This will return only 1 image at a time

    }

    func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {

        return myQLimageURL! as QLPreviewItem

    }

 

Have fun… 🙂

Let me know if you have any queries or problems implementing this feature. Enjoy … 🙂