Search code examples
iosuiimageretina-displayuigraphicscontext

Resizing and placing a Retina UIImage from server


I know this has been asked before... but I think I'm doing everything alright but the image doesn't look good on retina display. I heard that if need to display UIImage in retina all I have to do is to set the scale to 2.0. But still not working I don't know if the UIGraphics resizing and cropping is messing with the quality of the image. normally I'll call my resizer from the setImage inside a custom class of UIImageView (the image from the server it has the correct width, but is taller, so it suppose to only crop) in my controller ill call it like this:

[customUIImageViewInstance setImage:[UIImage imageWithData:[impreso thumb] scale:isRetina()?2:1]];

in my custom UIImageView implementation:

-(void)setImage:(UIImage *)image{
    if (image==nil) {
        [super setImage:nil];
    }else{
        [super setImage:[self scaleAnImageAspectFillCropHeight:image withNewWide:self.frame.size.width andNewTall:self.frame.size.height]];
    }
}



-(UIImage*) scaleAnImageAspectFillCropHeight:(UIImage*) image withNewWide:(NSUInteger) wide andNewTall:(NSUInteger) tall{
    if (image.size.width!=wide || image.size.height!=tall){
        BOOL retina;
        if ([image scale]==2) {
            retina = YES;
            wide*=2;
            tall*=2;
        }else{
            retina = NO;
        }
        CGFloat width = image.size.width;
        CGFloat height = image.size.height;
        CGFloat targetWidth = wide;
        CGFloat targetHeight = tall;
        CGFloat scaleFactor = 0.0;
        CGFloat scaledWidth;
        CGFloat scaledHeight;
        CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

    CGFloat widthFactor = targetWidth / width;
    CGFloat heightFactor = targetHeight / height;

    scaleFactor = widthFactor; // the width must be all visible, the height might be cropped but that is the inteded behavior

    scaledWidth  = width * scaleFactor;
    scaledHeight = height * scaleFactor;

    // centers X if needed, Y starts in 0 because the top part of the image is important
    thumbnailPoint.y = 0;
    if (widthFactor < heightFactor){
        thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
    }


    UIGraphicsBeginImageContext(CGSizeMake(wide, tall)); // this will crop

    CGRect thumbnailRect = CGRectZero;
    thumbnailRect.origin = thumbnailPoint;
    thumbnailRect.size.width  = scaledWidth;
    thumbnailRect.size.height = scaledHeight;

    [image drawInRect:thumbnailRect];

    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    if (retina) {
        newImage = [UIImage imageWithCGImage:newImage.CGImage scale:2 orientation:newImage.imageOrientation];
    }

    if(newImage == nil){
        [self setContentMode:UIViewContentModeScaleAspectFit];
    }else{
        //pop the context to get back to the default
        UIGraphicsEndImageContext();
        return newImage;
    }
}
return image;
}

I been debugging... and this sizes and the scale are the correct ones. I don't know what is messing with the quality of the image. A simple explanation will help a lot, thx.


Solution

  • Were you trying to forcibly scale any image up twice for a retina display? If yes, a quality of an image doesn't get better. It's reasonable. As you may know, a quality of an image is NOT improved by simply stretching a width and a height.

    What you really need to do is to use high resolution image which has twice resolution originally.