代码之家  ›  专栏  ›  技术社区  ›  Marin Todorov

如何获取[uiimage imagewithcontentsofile:]和高分辨率图像工作

  •  11
  • Marin Todorov  · 技术社区  · 15 年前

    正如许多人抱怨的那样,苹果的视网膜显示软件开发工具包中似乎有一个bug,ImageWithContentsFile实际上不会自动加载2X图像。

    我偶然发现了一篇很好的文章:如何制作一个检测uiscreen比例因子并正确加载低或高分辨率图像的函数( http://atastypixel.com/blog/uiimage-resolution-independence-and-the-iphone-4s-retina-display/ ,但该解决方案加载一个2x图像,并且仍然将图像的比例因子设置为1.0,这将导致一个2x图像缩放2倍(因此,比它的外观大4倍)。

    ImageNamed似乎可以准确地加载低分辨率和高分辨率的图像,但我没有选择。

    是否有任何人可以不使用自动加载ImageNamed或ImageWithContentsOfFile来加载低/高分辨率图像?(或最终解决如何使包含文件内容的图像正确工作)

    6 回复  |  直到 12 年前
        1
  •  13
  •   Marin Todorov    15 年前

    好的,迈克尔在这里找到了实际的解决方案: http://atastypixel.com/blog/uiimage-resolution-independence-and-the-iphone-4s-retina-display/

    他发现uiimage有一个方法“initwithcgimage”,这个方法也将比例因子作为输入(我猜是唯一一个可以自己设置比例因子的方法)。

    [UIImage initWithCGImage:scale:orientation:]
    

    这似乎很管用,你可以自定义加载高分辨率图像,只需设置比例系数为2.0。

    ImageWithContentsOfFile的问题在于,由于它当前无法正常工作,因此即使修复了它,我们也无法信任它(因为某些用户的设备上仍有旧的iOS)

        2
  •  11
  •   Lisa Rosselli    12 年前

    我们只是在工作中碰到这个。 以下是我的工作内容,似乎很有说服力:

    NSString *imgFile = ...path to your file;
    NSData *imgData = [[NSData alloc] initWithContentsOfFile:imgFile];
    UIImage *img = [[UIImage alloc] initWithData:imgData];
    
        3
  •  9
  •   bioffe John Petrone    14 年前

    imageWithContentsOfFile 从iOS 4.1及更高版本开始正常工作(考虑具有正确比例的@2x图像)。

        4
  •  5
  •   Marco B    15 年前

    我为这个问题开发了一个临时解决方案。 它使用方法swizzing来替换uiimage的“imagewithContentsOfFile:”方法的行为。 它对iPhone/iPod视网膜前/后很好。 不确定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
    
        5
  •  5
  •   Gasper    12 年前

    增强Lisa Rossellis的答案,使视网膜图像保持在所需大小(而不是放大):

    NSString *imagePath = ...Path to your image
    UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfFile:imagePath] scale:[UIScreen mainScreen].scale];
    
        6
  •  3
  •   bentford Marko Hlebar    13 年前

    [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 对于他的简单解决方案(我修改并粘贴在这里)。

    推荐文章