Kevin Sylvestre
Kevin Sylvestre

Reputation: 38012

Image from URL for Retina Display

I have an application that pulls images from an NSURL. Is it possible to inform the application that they are retina ('@2x') versions (the images are of retina resolution)? I currently have the following but the images appear pixelated on the higher resolution displays:

NSURL *url = [NSURL URLWithString:self.imageURL];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
self.pictureImageView.image = image;

Upvotes: 15

Views: 7903

Answers (6)

NSPratik
NSPratik

Reputation: 4836

To tell the iPhone programmatically that particular image is Retina, you can do something like this:

UIImage *img = [self getImageFromDocumentDirectory];
img = [UIImage imageWithCGImage:img.CGImage scale:2 orientation:img.imageOrientation];

In my case, TabBarItem image was dynamic i.e. that was downloading from server. Then the iOS cannot identify it as retina. The above code snippet worked for me like a charm.

Upvotes: 0

Ryan
Ryan

Reputation: 5496

Try using imageWithData:scale: (iOS 6 and later)

NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData scale:[[UIScreen mainScreen] scale]];

Upvotes: 12

Carter Allen
Carter Allen

Reputation: 1984

You need to rescale the UIImage before adding it to the image view.

NSURL *url = [NSURL URLWithString:self.imageURL];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
CGFloat screenScale = [UIScreen mainScreen].scale;
if (image.scale != screenScale)
    image = [UIImage imageWithCGImage:image.CGImage scale:screenScale orientation:image.imageOrientation];
self.pictureImageView.image = image;

It's best to avoid hard-coding the scale value, thus the UIScreen call. See Apple’s documentation on UIImage’s scale property for more information about why this is necessary.

It’s also best to avoid using NSData’s -dataWithContentsOfURL: method (unless your code is running on a background thread), as it uses a synchronous network call which cannot be monitored or cancelled. You can read more about the pains of synchronous networking and the ways to avoid it in this Apple Technical Q&A.

Upvotes: 17

n13
n13

Reputation: 6983

You need to set the scale on the UIImage.

UIImage* img = [[UIImage alloc] initWithData:data];
CGFloat screenScale = [UIScreen mainScreen].scale;
if (screenScale != img.scale) {
    img = [UIImage imageWithCGImage:img.CGImage scale:screenScale orientation:img.imageOrientation];
}

The documentation says to be careful to construct all your UIImages at the same scale, otherwise you might get weird display issues where things show at half size, double size, half resolution, et cetera. To avoid all that, load all UIImages at retina resolution. Resources will be loaded at the correct scale automatically. For UIImages constructed from URL data, you need to set it.

Upvotes: 5

JMattos
JMattos

Reputation: 202

Just to add to this, what I did specifically was the following, in the same situation, works like a charm.

double scaleFactor = [UIScreen mainScreen].scale;
        NSLog(@"Scale Factor is %f", scaleFactor);
        if (scaleFactor==1.0) {
            [cell.videoImageView setImageWithURL:[NSURL URLWithString:regularThumbnailURLString];
        }else if (scaleFactor==2.0){
            [cell.videoImageView setImageWithURL:[NSURL URLWithString:retinaThumbnailURLString];
        }

Upvotes: 1

Max
Max

Reputation: 16709

@2x convention is just convenient way for loading images from application bundle. If you wan't to show image on retina display then you have to make it 2x bigger:

Image size 100x100

View size: 50x50.

Edit: i think if you're loading images from server the best solution would be adding some additional param (e.g. scale) and return images of the appropriate size:

www.myserver.com/get_image.php?image_name=img.png&scale=2

You can obtain scale using [[UIScreen mainScreen] scale]

Upvotes: 0

Related Questions