简体   繁体   中英

Programmatic scaling of @3x image with UIScreen.main.scale has different result than Asset Catalog

I have an image being returned from the backend at an @3x scale. I am looking to scale the image programmatically based on the device. Something like:

let imageSize = CGSize(width: 300, height: 150)
let scale = UIScreen.main.scale / 3.0
let scaledSize = imageSize.applying(CGAffineTransform(scaleX: scale, y: scale))

As an example, on the iPhone 6s simulator, UIScreen.main.scale would be 2.0 ; thus the resulting scaledSize would be (2.0 / 3.0) * (width: 300, height: 150) = (width: 200, height: 100)

However, the image comes out too large.

I tried adding the same @3x asset to the Asset Catalog and using it directly in code, to find the size returned is @1x (which looks right). So, in this case, using the Asset Catalog returns an image of size (width: 100, height: 50)

Am I missing something about how UIScreen.main.scale could be used for this purpose? What would be the correct way to scale the @3x image programmatically?

It really depends on why you want to scale your image.

If you are displaying the image in a UIImageView , it will be scaled automatically by UIKit, so there's really no need to manually scale it.

However, if you have some other purpose... maybe you want to save a scaled version on the device? maybe you're doing something else with it?

One approach is to use UIGraphicsImageRenderer - for example:

func resizedImage(from image: UIImage, to scale: CGFloat) -> UIImage? {
    if scale == 1.0 {
        // don't need to scale the image,
        //  so just return it
        return image
    }
    let newSize = CGSize(width: image.size.width * scale, height: image.size.height * scale)
    let renderer = UIGraphicsImageRenderer(size: newSize)
    return renderer.image { (context) in
        image.draw(in: CGRect(origin: .zero, size: newSize))
    }
}

You could then scale your image like this:

    // using a 300x150 image for demonstration
    guard let img = UIImage(named: "bkg300x150") else {
        fatalError("Could not load image!!!!")
    }
    
    let scale = UIScreen.main.scale / 3.0

    guard let scaledImage = resizedImage(from: img, to: scale) else {
        fatalError("Image resize failed???")
    }
    
    print("Orig:", img.size)
    print("Scaled:", scaledImage.size)

the output on an iPhone 8 - @2x screen scale:

Orig: (300.0, 150.0)
Scaled: (200.0, 100.0)

the output on an iPhone 13 Pro Max - @3x screen scale:

Orig: (300.0, 150.0)
Scaled: (300.0, 150.0)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM