12

多くの人が不満を言っているように、Retina ディスプレイ用の Apple SDK にはバグがあり、imageWithContentsOfFile は実際には 2x 画像を自動的にロードしないようです。

UIScreen スケール ファクターを検出し、低解像度または高解像度の画像を適切に読み込む関数を作成する方法について、素敵な投稿を見つけました ( http://atastypixel.com/blog/uiimage-resolution-independence-and-the-iphone-4s -retina-display/ )、しかし、ソリューションは 2 倍の画像をロードし、画像の倍率は 1.0 に設定されたままです。これにより、2 倍に拡大された 2 倍の画像が生成されます (つまり、実際の外観よりも 4 倍大きくなります)。

imageNamed は、低解像度と高解像度の画像を正確にロードしているようですが、私には選択肢がありません。

imageNamed または imageWithContentsOfFile の自動読み込みを使用せずに、低/高解像度の画像を読み込むためのソリューションはありますか? (または、最終的には imageWithContentsOfFile を正しく機能させる方法を解決します)

4

6 に答える 6

13

わかりました、マイケルがここで見つけた実際の解決策: http://atastypixel.com/blog/uiimage-resolution-independence-and-the-iphone-4s-retina-display/

彼は、UIImage に "initWithCGImage" メソッドがあり、これもスケール ファクターを入力として受け取ることを発見しました (スケール ファクターを自分で設定できる唯一の方法だと思います)。

[UIImage initWithCGImage:scale:orientation:]

そして、これはうまくいくようです。高解像度の画像をカスタムロードして、倍率を 2.0 に設定するだけです。

imageWithContentsOfFile の問題は、現在正常に動作しないため、修正されたとしても信頼できないことです (一部のユーザーのデバイスには古い iOS が残っているため)。

于 2010-09-18T10:30:40.180 に答える
11

私たちはここで仕事でこれに遭遇しました。これが水を保持しているように見える私の回避策です:

NSString *imgFile = ...path to your file;
NSData *imgData = [[NSData alloc] initWithContentsOfFile:imgFile];
UIImage *img = [[UIImage alloc] initWithData:imgData];
于 2013-02-21T22:23:35.773 に答える
9

imageWithContentsOfFileiOS 4.1 以降では適切に動作します (正しい縮尺の @2x 画像を考慮)。

于 2010-12-15T04:17:34.310 に答える
6

リサ・ロッセリスの回答を強化して、網膜画像を目的のサイズに保つ(拡大しない):

NSString *imagePath = ...Path to your image
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfFile:imagePath] scale:[UIScreen mainScreen].scale];
于 2013-05-07T08:26:34.470 に答える
5

この問題のドロップイン回避策を開発しました。これは、メソッドswizzlingを使用して、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
于 2010-09-20T14:55:32.610 に答える
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の簡単な解決策 (私が修正してここに貼り付けました) の功績は認められます。

于 2012-04-12T18:52:41.013 に答える