41

UIImageViewを使用して画像のサムネイルを表示し、選択してフルサイズで表示できます。UIImageViewのコンテンツモードはアスペクトフィットに設定されています。

画像は通常、約500pxx500pxから100pxx100pxに縮小されます。Retina iPadでは、それらは非常によく表示されますが、iPad2では、サイズがネイティブの画像サイズに近づくまで、エイリアシングがひどくなります。

例:

元の画像

元の画像

Retina iPad 100x100

100pxx100pxでレンダリングするRetinaiPad

iPad 2 100x100

100pxx100pxでのiPad2レンダリング

iPad 2と新しいiPadの違いは、画面の解像度だけかもしれませんし、GPUが画像を拡大縮小するのに適しているかもしれません。いずれにせよ、iPad2のレンダリングは非常に貧弱です。

最初に、新しいコンテキストを作成し、補間品質を高く設定して、画像をコンテキストに描画することにより、画像サイズを縮小してみました。この場合、画像は両方のiPadで正常に表示されます。

画像のコピー/サイズ変更の方法を続ける前に、私が見逃していたより単純なものがないことを確認したかったのです。UIImageがスケーリングされていないことを感謝しますが、UIImageViewがスケーリングを処理するために存在しているという印象を受けましたが、現時点では、スケールダウンがうまく機能していないようです。私は何が(もしあれば)欠けていますか?

更新:注:レンダリング/サイズ変更された画像のドロップシャドウがコードに追加されます。これを無効にしても、スケーリングの品質に違いはありません。

4

5 に答える 5

75

私が試したもう1つのアプローチは、物事を改善しているようですが、minificationFilterを設定することです。

[imageView.layer setMinificationFilter:kCAFilterTrilinear]

品質は確かに向上しており、パフォーマンスの低下には気づいていません。

于 2012-10-05T09:01:24.273 に答える
10

自分で画像をリサンプリングしたくない場合は、小さな縮小フィルターバイアスを適用するとこれに役立ちます。

imageView.layer.minificationFilter = kCAFilterTrilinear
imageView.layer.minificationFilterBias = 0.1

ここに画像の説明を入力してください

左の画像にはフィルタリングが適用されていません。右の画像には0.1のフィルターバイアスがあります。

明示的なラスタライズは必要ないことに注意してください。

非常に小さい値で遊んでみると、通常、スケーリングアーティファクトを十分に滑らかにする値を思い付くことができ、ビットマップのサイズを自分で変更するよりもはるかに簡単です。確かに、バイアスが大きくなるとディテールが失われるため、画像を表示している画像ビューのフレームのサイズにもよりますが、0.1未満の値でもおそらく十分です。

トリリニアフィルタリングは、レイヤー上でのミップマッピングを効果的に有効にすることを理解してください。これは、基本的に、徐々に小さいスケールでビットマップの余分なコピーを生成することを意味します。これは、レンダリング速度を上げ、スケーリングエイリアシングを減らすためにレンダリングで使用される非常に一般的な手法です。トレードオフは、より多くのメモリを必要とすることですが、連続してダウンサンプリングされたビットマップのメモリ使用量は指数関数的に減少します。

この手法のもう1つの潜在的な利点は、私自身は試していませんが、アニメーション化できることですminificationFilterBias。したがって、アニメーションの一部として画像ビューをかなり縮小する0.0場合は、縮小されたサイズに適していると判断した小さな値からフィルターバイアスをアニメーション化することも検討してください。

最後に、他の人が指摘しているように、ソース画像が非常に大きい場合、Core Animationは常に元のビットマップを維持するため、この手法は使いすぎると適切ではありません。ほとんどの場合、ミップマップを使用するのではなく、画像のサイズを変更してからソース画像を破棄することをお勧めしますが、1回限りの場合や、画像ビューの割り当てがすぐに解除される場合は、これで問題ありません。

于 2017-04-08T21:46:51.217 に答える
7

大きな画像を小さな画像ビューに配置するだけでは、見栄えが悪くなります。

解決策は、画像のサイズを適切に変更することです...トリックを実行する関数の例を追加します。

- (UIImage *)resizeImage:(UIImage*)image newSize:(CGSize)newSize {
    CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
    CGImageRef imageRef = image.CGImage;

    UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
    CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height);

    CGContextConcatCTM(context, flipVertical);
    CGContextDrawImage(context, newRect, imageRef);

    CGImageRef newImageRef = CGBitmapContextCreateImage(context);
    UIImage *newImage = [UIImage imageWithCGImage:newImageRef];

    CGImageRelease(newImageRef);
    UIGraphicsEndImageContext();

    return newImage;
}

この関数には時間がかかる場合があります。そのため、結果をキャッシュファイルに保存することをお勧めします。

于 2012-10-04T16:12:02.653 に答える
7

あなたが記憶を無駄にすることを恐れず、あなたが特定のケースのために何をしているのかを知っているなら、これは美しく働きます。

myView.layer.shouldRasterize = YES;
myView.layer.rasterizationScale = 2;

結果として得られる品質は、setMinificationFilterよりもはるかに優れています。

256x256の画像を使用しており、48ピクセルのように拡大縮小しています。明らかに、ここでの賢明な解決策は、画像を正確な宛先サイズに縮小することです。

于 2014-06-25T23:06:26.473 に答える
1

次に私を助けました:

imageView.layer.minificationFilter = kCAFilterTrilinear
imageView.layer.shouldRasterize = true
imageView.layer.rasterizationScale = UIScreen.mainScreen().scale

スクロールリストで使用する場合は、パフォーマンスに注意してください。

于 2016-07-05T10:38:42.743 に答える