NEW: Join my free 100 Days of SwiftUI challenge today! >>

Controlling image interpolation in SwiftUI

Paul Hudson    @twostraws   

What happens if you make a SwiftUI Image view that stretches its content to be larger than its original size? By default, we get image interpolation, which is where iOS blends the pixels so smoothly you might not even realize they have been stretched at all. There’s a performance cost to this of course, but most of the time it’s not worth worrying about.

However, there is one place where image interpolation causes a problem, and that’s when you’re dealing with precise pixels. As an example, the files for this project on GitHub contain a little cartoon alien image called example@3x.png – it’s taken from the Kenney Platform Art Deluxe bundle at https://kenney.nl/assets/platformer-art-deluxe and is available under the public domain.

Go ahead and add that graphic to your asset catalog, then change your ContentView struct to this:

Image("example")
    .resizable()
    .scaledToFit()
    .frame(maxHeight: .infinity)
    .background(Color.black)
    .edgesIgnoringSafeArea(.all)

That renders the alien character against a black background to make it easier to see, and because it’s resizable SwiftUI will stretch it up to fill all available space.

Take a close look at the edges of the colors: they look jagged, but also blurry. The jagged part comes from the original image because it’s only 66x92 pixels in size, but the blurry part is where SwiftUI is trying to blend the pixels as they are stretched to make the stretching less obvious.

Often this blending works great, but it struggles here because the source picture is small (and therefore needs a lot of blending to be shown at the size we want), and also because the image has lots of solid colors so the blended pixels stand out quite obviously.

For situations just like this one, SwiftUI gives us the interpolation() modifier that lets us control how pixel blending is applied. There are multiple levels to this, but realistically we only care about one: .none. This turns off image interpolation entirely, so rather than blending pixels they just get scaled up with sharp edges.

So, modify your image to this:

Image("example")
    .interpolation(.none)    
    .resizable()
    .scaledToFit()
    .frame(maxHeight: .infinity)
    .background(Color.black)
    .edgesIgnoringSafeArea(.all)

Now you’ll see the alien character retains its pixellated look, which not only is particularly popular in retro games but is also important for line art that would look wrong when blurred.

LEARN SWIFTUI FOR FREE I have a massive, free SwiftUI video collection on YouTube teaching you how to build complete apps with SwiftUI – check it out!

BUY OUR BOOKS
Buy Pro Swift Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!

Average rating: 3.5/5