You are currently viewing Handling WebP Images When Using PHPickerViewController

Handling WebP Images When Using PHPickerViewController

This week, I worked on a feature that required integration with the PHPickerViewController. Everything went well until I noticed that some of the selected images failed to convert into UIImage in the picker(_:didFinishPicking:) delegate method.

Upon investigation, I discovered that the issue arose because some of the images were in WebP format, and the way to handle image results recommended by Apple did not work for WebP images.

Fortunately, resolving the issue is quite straightforward. All we need to do is load the WebP image as data and convert it to UIImage.

Let me show you.


Why Does It Fail?

In this WWDC video, Apple recommends using the following code to handle images from a PHPickerViewController:

if itemProvider.canLoadObject(ofClass: UIImage.self) {

    // Handle UIImage type
    itemProvider.loadObject(ofClass: UIImage.self) { image, error in

        guard let resultImage = image as? UIImage else {
            return
        }

        // Do something with `resultImage`
    }
}

The issue arises because the loadObject(ofClass:) method does not support the WebP image format, resulting in the canLoadObject(ofClass:) method returning false.

To resolve this problem, we will have to rely on another way for loading WebP images. Let’s take a look.


How to Handle WebP Images When Using PHPickerViewController?

The method we are looking for is loadDataRepresentation(forTypeIdentifier:completionHandler:). This method allows us to convert the given WebP image into a generic data object.

Once we have the data object, it becomes straightforward to convert it into UIImage.

// Get the first item provider from the results
guard let itemProvider = results.first?.itemProvider else {
    return
}

// Ensure that image format is WebP
if itemProvider.hasItemConformingToTypeIdentifier(UTType.webP.identifier) {
    
    // Convert WebP image into data object
    itemProvider.loadDataRepresentation(forTypeIdentifier: UTType.webP.identifier) { data, error in
        
        // Convert data to UIImage
        guard let data, let webpImage = UIImage(data: data) else {
            return
        }
        
        // Do something with the WebP image
    }
}

Adding WebP Support to NSItemProvider

To enhance the readability and reusability of our sample code, we can consolidate the WebP image-handling code with the existing image-handling code and create an extension for NSItemProvider.

import UIKit
import UniformTypeIdentifiers

extension NSItemProvider {
    
    enum NSItemProviderLoadImageError: Error {
        case unexpectedImageType
    }
    
    func loadImage(completion: @escaping (UIImage?, Error?) -> Void) {
        
        if canLoadObject(ofClass: UIImage.self) {
            
            // Handle UIImage type
            loadObject(ofClass: UIImage.self) { image, error in
               
                guard let resultImage = image as? UIImage else {
                    completion(nil, error)
                    return
                }
                
                completion(resultImage, error)
            }
            
        } else if hasItemConformingToTypeIdentifier(UTType.webP.identifier) {
            
            // Handle WebP Image
            loadDataRepresentation(forTypeIdentifier: UTType.webP.identifier) { data, error in
                
                guard let data,
                      let webpImage = UIImage(data: data) else {
                    completion(nil, error)
                    return
                }
                
                completion(webpImage, error)
            }
            
        } else {
            completion(nil, NSItemProviderLoadImageError.unexpectedImageType)
        }
    }
}

By utilizing this extension, we can now extract images returned by PHPickerViewController more easily. Here’s an example of how to use it:

guard let itemProvider = results.first?.itemProvider else {
    return
}

itemProvider.loadImage { image, error in
    // Do something with `image`
}

Further Readings


I hope you will find this article helpful. If you like this article, consider following me on Twitter and LinkedIn. Also, subscribe to my newsletter so that you won’t miss out on any of my upcoming iOS development-related articles.

Thanks for reading. 👨🏻‍💻


👋🏻 Hey!

While you’re still here, why not check out some of my favorite Mac tools on Setapp? They will definitely help improve your day-to-day productivity. Additionally, doing so will also help support my work.

  • Bartender: Superpower your menu bar and take full control over your menu bar items.
  • CleanShot X: The best screen capture app I’ve ever used.
  • PixelSnap: Measure on-screen elements with ease and precision.
  • iStat Menus: Track CPU, GPU, sensors, and more, all in one convenient tool.