UIRectClipを適切に使用してUIImageをアイコンサイズに縮小する
質問
任意の次元の UIImage が与えられた場合、正方形の「アイコン」を生成したいと思います。サイズが変更されたバージョンで、歪み(伸縮)なしで、 px
ピクセルを横に並べます。しかし、私は小さな障害に直面しています。問題がどこにあるかはよくわかりません。これが私がこれまでやっていることです。
まず、 UImage size
を指定して、3つのことを決定します。画像を縮小するときに使用する ratio
。 delta
(目的のアイコンサイズと最長辺の差)、および offset
(画像をクリッピングするときに原点座標を計算するために使用されます):
if (size.width > size.height) {
ratio = px / size.width;
delta = (ratio*size.width - ratio*size.height);
offset = CGPointMake(delta/2, 0);
} else {
ratio = px / size.height;
delta = (ratio*size.height - ratio*size.width);
offset = CGPointMake(0, delta/2);
}
今、幅640ピクセル、高さ480ピクセルの画像があり、これから50ピクセルx 50ピクセルのアイコンを取得したいとします。幅は高さよりも大きいため、計算は次のとおりです。
ratio = 50px / 640px = 0.078125
delta = (ratio * 640px) - (ratio * 480px) = 50px - 37.5px = 12.5px
offset = {x=6.25, y=0}
次に、歪みなしで目的のアイコンサイズにトリミングできる十分な大きさの CGRect rect
と、 clipRect
を作成しますクリッピング目的:
CGRect rect = CGRectMake(0.0, 0.0, (ratio * size.width) + delta,
(ratio * size.height) + delta);
CGRect clipRect = CGRectMake(offset.x, offset.y, px, px);
上記の値を代入すると、次のようになります:
rect = origin {x=0.0, y=0.0}, size {width=62.5, height=50.0}
clipRect = origin {x=6.25, y=0}, size {width=50.0, height=50.0}
これで、62.5px x 50pxの高さの長方形と、「中央」をつかむクリッピング長方形ができました。 50x50の部分。
ホームストレッチに!次に、イメージコンテキストを設定し、 UIImage (ここでは myImage
と呼ばれます)を四角形に描画し、クリッピング四角形を設定し、(おそらくクリップされた)イメージを取得します。それを使用し、最後に画像コンテキストをクリーンアップします:
UIGraphicsBeginImageContext(rect.size);
[myImage drawInRect:rect];
UIRectClip(clipRect);
UIImage *icon = UIGraphicsGetImageFromCurrentImageContext();
// Do something with the icon here ...
UIGraphicsEndImageContext();
唯一の問題:クリッピングは発生しません!最終的には、幅63ピクセル、高さ50ピクセルの画像になります。 :(
UIRectClip を誤用/誤解しているのでしょうか? rect
と clipRect
の使用を交換し、 drawInRect:の前に UIRectClip を移動します。 。サイコロなし。
この方法の例もオンラインで検索しようとしましたが、役に立ちませんでした。レコードの場合、 UIRectClip は次のように定義されます:
次の方法で現在のクリッピングパスを変更します 指定と交差する 長方形。
物事をシャッフルすると、少し近づきます:
UIGraphicsBeginImageContext(clipRect.size);
UIRectClip(rect);
[myImage drawInRect:rect];
今では歪みはありませんが、クリップされた画像は元の画像の中心にありません。それでも、少なくとも画像は50x50ですが、変数名はシャッフルの結果としてファウリングされています。 (読者のための演習として、名前の変更は敬意を表します。)
解決
エウレカ!私は物事が少し混乱していた。これは動作します:
CGRect clipRect = CGRectMake(-offset.x, -offset.y,
(ratio * size.width) + delta,
(ratio * size.height) + delta);
UIGraphicsBeginImageContext(CGSizeMake(px, px));
UIRectClip(clipRect);
[myImage drawInRect:clipRect];
UIImage *icon = UIGraphicsGetImageFromCurrentImageContext();
// Do something with the icon here ...
UIGraphicsEndImageContext();
rect
はもう必要ありません。トリックは、クリッピング長方形で負のオフセットを使用しているように見えるため、50 x 50の画像を取得する場所の原点を並べます(この例では)。
おそらくもっと簡単な方法があるでしょう。もしそうなら、計量してください!
他のヒント
同様のことを達成したかったのですが、元のポスターからの回答がうまくいかないことがわかりました。画像が歪んだ。これは、彼がソリューション全体を投稿せず、変数の初期化方法の一部を変更したためだけである可能性があります。
(if (size.width > size.height)
ratio = px / size.width;
私のソリューション(ソース画像から可能な限り最大の正方形を使用したかった)が間違っていました。また、UIClipRectを使用する必要はありません-コンテキストを抽出したい画像のサイズにすると、その長方形の外部で実際の描画は行われません。これは、画像の長方形のサイズをスケーリングし、原点座標の1つをオフセットするだけの問題です。以下にソリューションを投稿しました:
+(UIImage *)makeIconImage:(UIImage *)image
{
CGFloat destSize = 400.0;
CGRect rect = CGRectMake(0, 0, destSize, destSize);
UIGraphicsBeginImageContext(rect.size);
if(image.size.width != image.size.height)
{
CGFloat ratio;
CGRect destRect;
if (image.size.width > image.size.height)
{
ratio = destSize / image.size.height;
CGFloat destWidth = image.size.width * ratio;
CGFloat destX = (destWidth - destSize) / 2.0;
destRect = CGRectMake(-destX, 0, destWidth, destSize);
}
else
{
ratio = destSize / image.size.width;
CGFloat destHeight = image.size.height * ratio;
CGFloat destY = (destHeight - destSize) / 2.0;
destRect = CGRectMake(0, destY, destSize, destHeight);
}
[image drawInRect:destRect];
}
else
{
[image drawInRect:rect];
}
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
}
wheeliebinの回答は正しいが、destYの前にマイナス記号を忘れた
destRect = CGRectMake(0, -destY, destSize, destHeight);