iOS Swift: How to properly scale down an image?
Asked Answered
D

2

3

I'm using AlamofireImage to download and set my UIImage:

backdrop.af_setImageWithURL(downloadURL)

The image is substantially larger than what I will be displaying and so I have an issue with aliasing. How can I resize this image properly?

Results:

enter image description here

Danieladaniele answered 27/6, 2016 at 20:1 Comment(6)
Can you tell us what have you done so far and it's not working, so that we can help you out. Because as the question is looking now it can be categorised as opinion based and is not suitable for this forum.Isaak
I haven't done anything regarding anti-aliasing, I don't know how to. My image displays perfectly fine apart from the aliasing. @IsaakDanieladaniele
What is your issue re aliasing? Most resizing algorithms are likely to yield the same effect. Re general resizing algorithms, see https://mcmap.net/q/832225/-how-to-resize-a-bitmap-on-ios. Generally we're resizing to minimize memory impact, though, not to tackle any softening of the image due to changing its size.Stila
BTW, Alamofireimage already has image scaling methods, so you probably don't need to write your own.Stila
I have already described my issue regarding aliasing to the best of my ability, the only way I can describe it is that it looks too sharp. Fine lines that are close together don't look right. I feel that the image does need to be softer. I used the 'Aspect Fit' mode in storyboard to scale my image. I will post before and after pictures using the accepted solution so that you can see. @StilaDanieladaniele
Blur the image before scale down the image.Lack
H
7

You can resize the image with any size once you have a valid UIImage:

func resizedImageWith(image: UIImage, targetSize: CGSize) -> UIImage {

    let imageSize = image.size
    let newWidth  = targetSize.width  / image.size.width
    let newHeight = targetSize.height / image.size.height
    var newSize: CGSize

    if(newWidth > newHeight) {
        newSize = CGSizeMake(imageSize.width * newHeight, imageSize.height * newHeight)
    } else {
        newSize = CGSizeMake(imageSize.width * newWidth,  imageSize.height * newWidth)
    }

    let rect = CGRectMake(0, 0, newSize.width, newSize.height)

    UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)

    image.drawInRect(rect)

    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage
}

For any other queries/modifications you have, refer this NShipster

Hayden answered 27/6, 2016 at 20:26 Comment(5)
Agreed! Yes when we set the scale to 0.0 then the main screen's scale would be used which is 2.0 or more for Retina screens. Updated my answer.Hayden
I would also scale it down with UIJPEGRepresentation(image, amountToScale0Through1)Protolithic
@Protolithic - UIImageJPEGRepresentation doesn't do any scaling. All it does is convert UIImage to NSData (either making the asset much larger or shrinking it but introducing JPEG artifacts in the process). There are times you need UIImageJPEGRepresentation, but there's nothing in this question to suggest that's what's needed here.Stila
I am sure that it reduces the file size. I guess I misinterpreted what was needed.Protolithic
@sethmr - Yep, you can use a quality setting below 1.0 to reduce file size, but it doesn't scale the image, but rather applies a lossy compression (i.e. degrades image quality, introducing artifacts, barely noticeable at values of 0.8 or 0.9, but visually noticeable at lower values). It's useful when trying to reduce size of image that is, for example, being uploaded to web service, but doesn't reduce run-time memory usage of UIImage. To achieve run-time memory savings, you have to scale image, like shown in Santosh's answer (or use Alamofireinage scaling methods, which do the same thing).Stila
N
1

Here is @Santosh's answer in ObjC:

- (UIImage*) scaleImage:(UIImage*)image toSize:(CGSize)newSize {

    CGSize imageSize = image.size;
    CGFloat newWidth  = newSize.width  / image.size.width;
    CGFloat newHeight = newSize.height / image.size.height;
    CGSize newImgSize;

    if(newWidth > newHeight) {
        newImgSize = CGSizeMake(imageSize.width * newHeight, imageSize.height * newHeight);
    } else {
        newImgSize = CGSizeMake(imageSize.width * newWidth,  imageSize.height * newWidth);
    }

    CGRect rect = CGRectMake(0, 0, newImgSize.width, newImgSize.height);

    UIGraphicsBeginImageContextWithOptions(newImgSize, false, 0.0);

    [image drawInRect:rect];;

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}
Neelon answered 22/6, 2018 at 20:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.