2010-09-17 2 views
11

Как и многие люди жалуются, кажется, что в Apple SDK для Retina Display есть ошибка, а imageWithContentsOfFile фактически не загружает 2x изображения автоматически.Как получить [UIImage imageWithContentsOfFile:] и High Res Изображения, работающие

Я наткнулся на хороший пост, как сделать функцию, которая обнаруживает масштабный коэффициент UIScreen и правильно загружает изображения с низким или высоким разрешением (http://atastypixel.com/blog/uiimage-resolution-independence-and-the-iphone-4s-retina-display/), но решение загружает изображение 2x и по-прежнему имеет масштабный коэффициент изображения установите значение 1.0, и это приведет к увеличению 2x изображений в 2 раза (так, в 4 раза больше, чем это должно выглядеть)

imageNamed, похоже, точно загружает изображения с низким и высоким разрешением, но для меня это не вариант.

Есть ли у кого-нибудь решение для загрузки изображений с низким/высоким разрешением, не используя автоматическую загрузку изображенияNamed или imageWithContentsOfFile? (Или в конечном итоге решение, как сделать imageWithContentsOfFile работу правильно)

ответ

13

Ok, фактическое решение, найденное Michael здесь: http://atastypixel.com/blog/uiimage-resolution-independence-and-the-iphone-4s-retina-display/

Он понял, что UIImage имеет метод «initWithCGImage», который также принимает масштабный коэффициент в качестве входных данных (Я думаю, единственный способом, где вы можете установить себе масштабный коэффициент)

[UIImage initWithCGImage:scale:orientation:] 

и это, кажется, отлично работает, вы можете загрузить ваше пользовательское высокое разрешение изображения и просто установить, что масштабный коэффициент 2,0

Проблема с imageWithContentsOfFile заключается в том, что, поскольку она в настоящее время не работает должным образом, мы не можем доверять ей, даже когда она исправлена ​​(поскольку некоторые пользователи будут по-прежнему иметь более старую iOS на своих устройствах)

+0

Если вы поддерживаете IOS 4,1 или позже, см. ответ «bioffe». Гораздо проще. –

5

Я разработал каплю - обходной путь для этой проблемы. Использует метод swizzling, чтобы заменить поведение метода image imageWithContentsOfFile: UIImage. Он отлично работает на iPhones/iPods до/после сетчатки. Не уверен в iPad.

Надеюсь, это поможет.

#import </usr/include/objc/objc-class.h> 

@implementation NSString(LoadHighDef) 

/** If self is the path to an image, returns the nominal path to the high-res variant of that image */ 
-(NSString*) stringByInsertingHighResPathModifier { 

    NSString *path = [self stringByDeletingPathExtension]; 

    // We determine whether a device modifier is present, and in case it is, where is 
    // the "split position" at which the "@2x" token is to be added 
    NSArray *deviceModifiers = [NSArray arrayWithObjects:@"~iphone", @"~ipad", nil]; 
    NSInteger splitIdx = [path length]; 
    for (NSString *modifier in deviceModifiers) { 
      if ([path hasSuffix:modifier]) { 
       splitIdx -= [modifier length]; 
       break; 
      } 
    } 

    // We insert the "@2x" token in the string at the proper position; if no 
    // device modifier is present the token is added at the end of the string 
    NSString *highDefPath = [NSString stringWithFormat:@"%@@2x%@",[path substringToIndex:splitIdx], [path substringFromIndex:splitIdx]]; 

    // We possibly add the extension, if there is any extension at all 
    NSString *ext = [self pathExtension]; 
    return [ext length]>0? [highDefPath stringByAppendingPathExtension:ext] : highDefPath; 
} 

@end 

@implementation UIImage (LoadHighDef) 

/* Upon loading this category, the implementation of "imageWithContentsOfFile:" is exchanged with the implementation 
* of our custom "imageWithContentsOfFile_custom:" method, whereby we replace and fix the behavior of the system selector. */ 
+(void)load { 
    Method originalMethod = class_getClassMethod([UIImage class], @selector(imageWithContentsOfFile:)); 
    Method replacementMethod = class_getClassMethod([UIImage class], @selector(imageWithContentsOfFile_custom:)); 
    method_exchangeImplementations(replacementMethod, originalMethod); 
} 

/** This method works just like the system "imageWithContentsOfFile:", but it loads the high-res version of the image 
* instead of the default one in case the device's screen is high-res and the high-res variant of the image is present. 
* 
* We assume that the original "imageWithContentsOfFile:" implementation properly sets the "scale" factor upon 
* loading a "@2x" image . (this is its behavior as of OS 4.0.1). 
* 
* Note: The "imageWithContentsOfFile_custom:" invocations in this code are not recursive calls by virtue of 
* method swizzling. In fact, the original UIImage implementation of "imageWithContentsOfFile:" gets called. 
*/ 

+ (UIImage*) imageWithContentsOfFile_custom:(NSString*)imgName { 

    // If high-res is supported by the device... 
    UIScreen *screen = [UIScreen mainScreen]; 
    if ([screen respondsToSelector:@selector(scale)] && [screen scale]>=2.0) { 

      // then we look for the high-res version of the image first 
      UIImage *hiDefImg = [UIImage imageWithContentsOfFile_custom:[imgName stringByInsertingHighResPathModifier]]; 

      // If such high-res version exists, we return it 
      // The scale factor will be correctly set because once you give imageWithContentsOfFile: 
      // the full hi-res path it properly takes it into account 
      if (hiDefImg!=nil) 
       return hiDefImg; 
    } 

    // If the device does not support high-res of it does but there is 
    // no high-res variant of imgName, we return the base version 
    return [UIImage imageWithContentsOfFile_custom:imgName]; 
} 

@end 
+0

Привет, Марко, как описано в вопросе - имена файлов не являются проблемой вообще, а масштабным фактором самого изображения. –

+0

Привет Ican, мой код правильно устанавливает масштабный коэффициент (тестируется в симуляторе с ОС 4.0.1 и 4.1). Дело в том, что в то время как imageWithContentsOfFile: автоматически не находит вариант «@ 2x», как вы говорите, как только вы укажете ему, чтобы получить файл «@ 2x» напрямую (как в моем swizzled методе), он затем правильно устанавливает масштабный коэффициент. Просто оставьте мои две категории где-то в вашем коде, где они скомпилируются и попробуйте использовать imageWithContentsOfFile: как бы если бы они не были сломаны –

9

imageWithContentsOfFile работает должным образом (с учетом @ 2x изображений с правильным масштабом), начиная IOS 4.1 и далее.

+1

Несмотря на то, что в документации написано: 'imageWithContentsOfFile:' не работает на абсолютных путях. Протестировано на iOS 5.1 – bentford

+0

@bentford работает на iOS 5.1 для меня – bioffe

+1

Он не работает на абсолютном пути изображений в папке Caches для меня. Будут исследовать дальше, может быть, это был плохой тест. – bentford

3

[UIImage imageWithContentsOfFile:] не загружает @ 2x графики, если вы указываете абсолютный путь.

Вот решение:

- (UIImage *)loadRetinaImageIfAvailable:(NSString *)path { 

    NSString *retinaPath = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@@2x.%@", [[path lastPathComponent] stringByDeletingPathExtension], [path pathExtension]]]; 

    if([UIScreen mainScreen].scale == 2.0 && [[NSFileManager defaultManager] fileExistsAtPath:retinaPath] == YES) 
     return [[[UIImage alloc] initWithCGImage:[[UIImage imageWithData:[NSData dataWithContentsOfFile:retinaPath]] CGImage] scale:2.0 orientation:UIImageOrientationUp] autorelease]; 
    else 
     return [UIImage imageWithContentsOfFile:path]; 
} 

Заслуга Christof Dorner его простое решение (которое я изменил и вставить здесь).

11

Мы просто столкнулись с этим здесь, на работе. Вот моя работа вокруг, что, кажется, держит воду:

NSString *imgFile = ...path to your file; 
NSData *imgData = [[NSData alloc] initWithContentsOfFile:imgFile]; 
UIImage *img = [[UIImage alloc] initWithData:imgData]; 
5

Повышение ответ Лизы Rossellis, чтобы держать сетчатку изображений нужного размера (не масштабируется их):

NSString *imagePath = ...Path to your image 
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfFile:imagePath] scale:[UIScreen mainScreen].scale]; 
Смежные вопросы