Loading WebP Images from UIPasteboard

February 24, 2021

I recently got a bug report for Transparent App Icons to the effect of "I tried to paste in a transparent image, but it didn't work." After cropping the background to create a "transparent" image users can use for their Shortcuts icons, the app allows the user to paste an image from the clipboard to overlay and create a semi-transparent icon - this user was trying to paste a WebP image.

Turns out that WebP, the web-optimized image format developed by Google, isn't supported natively by UIKit. Luckily it's not too hard to implement support for it with the help of a small library and some deeper UIKit APIs.

Looking for a UIPasteboard extension which loads WebP images? Skip to the bottom!

UIPasteboard data

I haven't had to use the more complicated parts of UIPasteboard very much in my time as an iOS developer - in Transparent App Icons, I was just checking UIPasteboard.general.image in order to figure out whether there was an image copied. In iOS 14, you can copy a WebP image no problem, but there's no UIImage initializer representation for it, and as such it doesn't get reported as a UIImage in the same way it would if you had copied a PNG.

Luckily, there's a higher-effort, higher-reward way to interact with UIPasteboard. When the user copies data, the app it copied from might choose to write multiple representations of the data to the pasteboard - for example, if I'm writing an HTML editor and the user copies part of the document, I could write both HTML and string repreesentations to the pasteboard. Then, an app like notes doesn't have to worry about the HTML representation, it can just read the string value.

Each representation of an object in the pasteboard is denoted by a type, usually a Uniform Type Identifier. We can request the raw data for a pasteboard item using UIPasteboard's' data(forPasteboardType:) method, and since iOS 14 there's even a more strongly typed way, using UTType - here's the UTType identifier for WebP.

Note: When I was trying to figure this out, I first tried using loadItem on the pasteboard's itemProviders, but this returns a URL that you can't read the data of since it's restricted (annoyingly, only on device will you get permission denied errors - this URL is perfectly readable on simulator). I then moved on to loadData, before realizing I could just use data(forPasteboardType:) directly.

Parsing WebP

Once we have the data, we'll need to convert it into a UIImage - UIImage doesn't support this out of the box, but luckily Mattt has a great little library for encoding/decoding UIImages with WebP. Taking that with our data representation, we can write an extension to load a WebP image if one exists:

extension UIPasteboard {
    func loadImage() -> UIImage? {
        if self.types.contains(UTType.webP.identifier),
           let provider = self.itemProviders.first,
           self.image == nil,
           let data = self.data(forPasteboardType: UTType.webP.identifier) {
            do {
                let webpImage = try WebPImageSerialization.image(with: data)
                return webpImage
            } catch {
                // Log error
                return nil
            }
        }
        return UIPasteboard.general.image
    }
}

This ended up working great, and Transparent App Icons will support WebP in the coming version.

Picture of me with a corgi

Noah Gilmore

Hello! I'm Noah, a software developer based in the San Francisco bay area. I focus mainly on iOS, Apple platform development, and full stack web development.

  • 💻 I'm writing a macOS editor for Atlassian Confluence called Fluency
  • 📱 I wrote an app which lets you create transparent app icons called Transparent App Icons
  • 🧩 I made a puzzle game for iPhone and iPad called Trestle
  • 🎨 I wrote a CoreImage filter utility app for iOS developers called CIFilter.io
  • 👋 Please feel free to reach out on Twitter