2010-09-17 5 views
11

Comme beaucoup de gens se plaignent, il semble que dans le SDK Apple pour l'écran Retina il y a un bug et imageWithContentsOfFile ne charge pas automatiquement les images 2x.Comment obtenir [Ullmage imageWithContentsOfFile:] et haute résolution Images

Je suis tombé dans un joli post comment faire une fonction qui détecte le facteur d'échelle UIScreen et charge correctement les images basse ou haute résolution (http://atastypixel.com/blog/uiimage-resolution-independence-and-the-iphone-4s-retina-display/), mais la solution charge une image 2x et a toujours le facteur d'échelle de l'image mis à 1.0 et cela se traduit par un 2x images redimensionnées 2 fois (donc, 4 fois plus grand que ce qu'il doit ressembler)

imageNamed semble charger avec précision les images basse et haute résolution, mais ce n'est pas une option pour moi.

Est-ce que quelqu'un a une solution pour charger des images basse/haute résolution sans utiliser le chargement automatique de imageNamed ou imageWithContentsOfFile? (Ou éventuellement solution comment faire le travail de imageWithContentsOfFile correct)

Répondre

13

Ok, solution réelle trouvée par Michael ici: http://atastypixel.com/blog/uiimage-resolution-independence-and-the-iphone-4s-retina-display/

Il a compris que UIImage a la méthode « initWithCGImage » qui prend également un facteur d'échelle en entrée (Je suppose que la seule méthode où vous pouvez définir vous-même le facteur d'échelle)

[UIImage initWithCGImage:scale:orientation:] 

et cela semble fonctionner très bien, vous pouvez personnaliser charger vos images haute résolution et vient de mettre que le facteur d'échelle est de 2,0

Le problème avec imageWithContentsOfFile est que depuis qu'il ne fonctionne actuellement correctement, nous ne pouvons pas lui faire confiance même quand il est fixe (parce que certains utilisateurs auront toujours un iOS sur leurs anciens appareils)

+0

Si vous soutenez iOS 4.1 ou plus tard, voir la réponse de 'bioffe'. Beaucoup plus simple. –

5

J'ai développé une goutte -En solution de contournement pour ce problème. Il utilise la méthode swizzling pour remplacer le comportement de la méthode "imageWithContentsOfFile:" de UIImage. Fonctionne très bien sur les iPhones/iPods avant/après la rétine. Je ne suis pas sûr de l'iPad.

Espérons que cela aide.

#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

Salut Marco, comme décrit dans la question - les noms des fichiers ne sont pas un problème du tout, mais le facteur d'échelle de l'image elle-même. –

+0

Salut Ican, mon code définit correctement le facteur d'échelle (testé en simulateur avec OS 4.0.1 et 4.1). Le point est que tandis que imageWithContentsOfFile: ne trouve pas automatiquement la variante "@ 2x", comme vous le dites, une fois que vous lui demandez d'obtenir directement le fichier "@ 2x" (comme dans ma méthode swizzled), il définit correctement le facteur d'échelle. Déposez juste mes deux catégories quelque part dans votre code où elles sont compilées et essayez d'utiliser imageWithContentsOfFile: comme si vous n'étiez pas cassé. –

9

imageWithContentsOfFile fonctionne correctement (en tenant compte @ 2x images avec la bonne échelle) à partir iOS 4.1 et au-delà.

+1

Malgré ce que dit la documentation, 'imageWithContentsOfFile:' ne fonctionne pas sur les chemins absolus. Testé sur iOS 5.1 – bentford

+0

@bentford cela fonctionne sur iOS 5.1 pour moi – bioffe

+1

Cela ne fonctionne pas sur le chemin absolu des images dans le dossier Caches pour moi. Va enquêter plus loin, peut-être que c'était un mauvais test. – bentford

3

[UIImage imageWithContentsOfFile:] ne charge pas les graphiques 2x si vous spécifiez un chemin absolu.

Voici une solution:

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

Le crédit va à Christof Dorner pour sa solution simple (que je modifiée et collé ici).

11

Nous avons juste couru dans ceci ici au travail. Voici mon travail autour qui semble contenir de l'eau:

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

Amélioration de la réponse de Lisa Rossellis de garder les images de la rétine à la taille désirée (pas les plus grande échelle):

NSString *imagePath = ...Path to your image 
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfFile:imagePath] scale:[UIScreen mainScreen].scale]; 
Questions connexes