Изображение из URL для отображения Retina

У меня есть приложение, которое извлекает изображения из NSURL. Можно ли сообщить программе, что они являются сетчатыми ('@2x') версиями (изображения имеют разрешение сетчатки)? В настоящее время у меня есть следующее, но изображения отображаются на пикселях с более высоким разрешением:

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

Ответы

Ответ 1

Попробуйте использовать imageWithData:scale: (iOS 6 и более поздние версии)

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

Ответ 2

Вам нужно перемасштабировать UIImage, прежде чем добавлять его в представление изображения.

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;

Лучше избегать жесткого кодирования значения шкалы, таким образом, вызов UIScreen. Дополнительную информацию о том, почему это необходимо, см. В документации на яблоки UIImage s scale property.

Также лучше избегать использования метода NSData s -dataWithContentsOfURL: (если ваш код не работает в фоновом потоке), поскольку он использует синхронный сетевой вызов, который нельзя контролировать или отменять. Вы можете больше узнать о проблемах синхронной сети и о способах избежать этого в этом техническом Q & A в Apple.

Ответ 3

Вам нужно установить масштаб на 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];
}

В документации говорится о том, чтобы быть осторожным, чтобы построить все ваши UIImages в одном масштабе, иначе вы можете получить странные проблемы с отображением, когда вещи показывают половину размера, двойной размер, половинное разрешение и т.д. Чтобы избежать всего этого, загрузите все UIImages при разрешении сетчатки. Ресурсы будут загружены в правильной шкале автоматически. Для UIImages, созданных из URL-данных, вам нужно установить его.

Ответ 4

Чтобы добавить к этому, то, что я сделал конкретно, было следующим, в той же ситуации, как шарм.

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];
        }

Ответ 5

@2x соглашение - это просто удобный способ для загрузки изображений из набора приложений. Если вы не хотите показывать изображение на экране сетчатки, вам нужно сделать его в 2 раза больше:

Размер изображения 100x100

Размер: 50x50.

Изменить: я думаю, что если вы загружаете изображения с сервера, лучшим решением будет добавление некоторого дополнительного параметра (например, масштаба) и возврата изображений соответствующего размера:

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

Вы можете получить масштаб, используя шкалу [[UIScreen mainScreen]]

Ответ 6

+ (void)deviceScaledImageForView:(UIImageView*)v
        withParameterizedUrl:(NSString*)url
                 iPadSupport:(BOOL)iPadSupport
                       after:(UITask)after
{

// ...Declare Retina and Retina Plus versions of the the URL string...
NSString* url2x = @"";
NSString* url3x = @"";

// ...And if I'm on an iPad with my caller allowing iPad-specific images...
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && iPadSupport) {
    // ...Generate the iPad non-retina and retina versions of the URL...
    /* Note 3x is not applicable to iPad */
    url = [url stringByReplacingOccurrencesOfString:@".png" withString:@"~ipad.png"];
    url2x = [url stringByReplacingOccurrencesOfString:@"~ipad.png" withString:@"@2x~ipad.png"];
}
// ...Or, for iPhone...
else {
    // ...Generate the iPhone non-Retina, Retina and Retina Plus versions of the URL...
    url2x = [url stringByReplacingOccurrencesOfString:@".png" withString:@"@2x.png"];
    url3x = [url stringByReplacingOccurrencesOfString:@".png" withString:@"@3x.png"];
}

// ...If I'm running on iOS 7.1 or newer...
CGFloat scale = .0f;
UIScreen* screen = [UIScreen mainScreen];
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1)
    // ...Choose a scale based on the iOS 8 API.

    //currently the scale for the 6 plus ranges from 2.6 to 2.8 to 3.0 depending on zoomed mode or running on the sim
    // since our images are at 2x or at 3x we want whole numbers.
    scale = ceilf(screen.nativeScale);
else
    // ...Choose a device scale on the iOS 7 API.
    scale = screen.scale;

// ...If I've chosen a Retina Plus scale...
if (scale > 2.0f){
    // ...Select the 3x Retina Plus version of the image.
    url = url3x;
}

// ...Otherwise for retina displays...
else if (scale == 2.0f)
    // ...Select the Retina version of the image.
    url = url2x;

// ...And finally, request the image data with SDWebImage (for cache support)...
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:[NSURL URLWithString:url]
                                                      options:SDWebImageDownloaderUseNSURLCache
                                                     progress:nil
                                                    completed:^(UIImage* i,
                                                                NSData* d,
                                                                NSError* e,
                                                                BOOL finished)
 {
     // ...And after the image is obtained...
     // ...Apply it to the image view with the correct device scale...
     v.image = [UIImage imageWithData:d scale:scale];

     // ...And if I have an after-action...
     if (after)
         // ...Run it.
         after();
 }];

}

Ответ 7

Чтобы программно определить iPhone, что конкретное изображение Retina, вы можете сделать что-то вроде этого:

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

В моем случае изображение TabBarItem было динамическим, то есть загружалось с сервера. Тогда iOS не может идентифицировать его как сетчатку. Вышеприведенный фрагмент кода работал у меня как шарм.