ビットマップのAndroidクロップセンター


150

正方形または長方形のビットマップがあります。私は最短の側面を取り、次のようなことをします:

int value = 0;
if (bitmap.getHeight() <= bitmap.getWidth()) {
    value = bitmap.getHeight();
} else {
    value = bitmap.getWidth();
}

Bitmap finalBitmap = null;
finalBitmap = Bitmap.createBitmap(bitmap, 0, 0, value, value);

次に、これを使用して144 x 144ビットマップにスケーリングします。

Bitmap lastBitmap = null;
lastBitmap = Bitmap.createScaledBitmap(finalBitmap, 144, 144, true);

問題は、元のビットマップの左上隅をトリミングすることです。ビットマップの中央をトリミングするコードを誰かが持っていますか?

回答:


354

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

これは、Bitmap.createBitmap(source、x、y、width、height)で実現できます。

if (srcBmp.getWidth() >= srcBmp.getHeight()){

  dstBmp = Bitmap.createBitmap(
     srcBmp, 
     srcBmp.getWidth()/2 - srcBmp.getHeight()/2,
     0,
     srcBmp.getHeight(), 
     srcBmp.getHeight()
     );

}else{

  dstBmp = Bitmap.createBitmap(
     srcBmp,
     0, 
     srcBmp.getHeight()/2 - srcBmp.getWidth()/2,
     srcBmp.getWidth(),
     srcBmp.getWidth() 
     );
}

1
実際の宛先ビットマップが正方形になるように回答を編集しました。
Joram van den Boezem 2013年

1
@ルミス:なぜリビジョン3をロールバックしたのですか?有効な正解のようです。現在のバージョンでは正しい開始点が作成されますが、長すぎる側の残りが含まれます。たとえば、100x1000画像を指定すると、画像が返されます100x550
Guvante 2013年

ありがとう、あなたは正しい、形式はBitmap.createBitmap(source、x、y、width、height)
Lumis

11
組み込みのThumbnailUtils.extractThumbnail()メソッドの使用に関する私の回答を参照してください。なぜ車輪を再発明するのか??? stackoverflow.com/a/17733530/1103584
DiscDev

1
このソリューションは、キャンバスを作成してそれにドローアブルを描画するよりも短いです。また、ThumbnailUtilsソリューション(スケーリングの方法を理解するためにサンプルサイズを計算する)よりも処理が少なくなります。
yincrash 2014年

319

上記の回答のほとんどはこれを行う方法を提供していますが、これを達成するための組み込みの方法がすでにあり、それは1行のコード(ThumbnailUtils.extractThumbnail())です。

int dimension = getSquareCropDimensionForBitmap(bitmap);
bitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension);

...

//I added this method because people keep asking how 
//to calculate the dimensions of the bitmap...see comments below
public int getSquareCropDimensionForBitmap(Bitmap bitmap)
{
    //use the smallest dimension of the image to crop to
    return Math.min(bitmap.getWidth(), bitmap.getHeight());
}

ビットマップオブジェクトをリサイクルする場合は、それを行うオプションを渡すことができます。

bitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);

From:ThumbnailUtilsドキュメント

public static Bitmap extractThumbnail(ビットマップソース、int幅、int高さ)

APIレベル8で追加必要なサイズの中央揃えのビットマップを作成します。

パラメータソースオリジナルビットマップソース幅ターゲット幅高さターゲット高さ

承認された回答を使用すると、メモリ不足エラーが発生することがありました。ThumbnailUtilsを使用すると、これらの問題が解決しました。さらに、これははるかにクリーンで再利用可能です。


6
+1このコードを改善し、400pxを使用する代わりに、最短のbmpのサイズを渡して、上記の元の投稿の代替を提供する必要があると思います。しかし、これを私たちの注意を喚起してくれてありがとう、それは非常に便利な機能のようです。同情私はこれまでに見たことがない...
Lumis 2013年

右、具体例を示すために400をハードコーディングしただけです...詳細は実装者
次第です

4
@DiscDev-これは、文字通り、このサイト全体で最も役立つ答えの1つである必要があります。真剣に。Androidの質問では奇妙です。単純な明白な答えを見つける前に、2時間検索することがよくあります。どうやって感謝するか分からない。途中バウンティ!
Fattie、2014年

2
少し異なる関数を使用して、古いビットマップをリサイクルすることもできます。= ThumbnailUtils.extractThumbnail(bitmap、width、height、ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
android developer

1
これは、Androidの質問に対してこれまでに見た中で最も強力な答えです。私は、Androidのビットマップで20の異なるソリューションをスケーリング/クロップ/ダウンスケール/リサイズなどする方法を見てきました。すべての答えは異なります。そして、これはたった1行で、期待どおりに機能します。ありがとうございました。
Alex Sorokoletov 14

12

からこれを行うことを検討しましたlayout.xmlか?あなたは、あなたのために設定することができScaleTypeにし、画像の大きさを設定する内部。ImageViewandroid:scaleType="centerCrop"ImageViewlayout.xml


次のOpenGLRendererエラーでこのアイデアを試しました:「ビットマップが大きすぎてテクスチャにアップロードできません(2432x4320、max = 4096x4096)」したがって、4320の高さを処理できないと思います。
GregM 2014

1
もちろん、これは正解であり、質問にぴったりです。大きな画像の画質/サイズを最適化する...まあ、それは別の質問です!
ichalos

@ichalosおそらく探していたものを見つけたかもしれませんが、これは元の質問には答えません。元の質問は、キャンバスに手動でレンダリングすることでした。実際、写真をトリミングする最初の試みがどのようにキャンバスに手動でレンダリングされるのかはわかりませんが、ここで解決策を見つけたのはいいですね:)
milosmns

@milosmns多分あなたは正しいです。たぶんこれは、ユーザーが手動で中央までトリミングする問題にアプローチしようとした方法です。それはすべて、元のユーザーの正確なニーズに依存します。
ichalos

9

問題を解決できる以下のコードを使用できます。

Matrix matrix = new Matrix();
matrix.postScale(0.5f, 0.5f);
Bitmap croppedBitmap = Bitmap.createBitmap(bitmapOriginal, 100, 100,100, 100, matrix, true);

上記のメソッドは、トリミングの前に画像のpostScallingを行うため、OOMエラーが発生することなく、トリミングされた画像で最良の結果を得ることができます。

詳細については、このブログを参照してください


1
E / AndroidRuntime(30010):原因:java.lang.IllegalArgumentException:x +幅は<= bitmap.width()である必要があります。これは、100pxの4倍のため
Stan

9

ここでは、任意の次元の[ビットマップ]の中心を切り取り、結果を希望の[IMAGE_SIZE]にスケーリングする、より完全なスニペットを示します。したがって、常に[croppedBitmap]を取得します 、固定サイズのスケーリングされた画像の中心の正方形。サムネイルなどに最適です。

他のソリューションのより完全な組み合わせ。

final int IMAGE_SIZE = 255;
boolean landscape = bitmap.getWidth() > bitmap.getHeight();

float scale_factor;
if (landscape) scale_factor = (float)IMAGE_SIZE / bitmap.getHeight();
else scale_factor = (float)IMAGE_SIZE / bitmap.getWidth();
Matrix matrix = new Matrix();
matrix.postScale(scale_factor, scale_factor);

Bitmap croppedBitmap;
if (landscape){
    int start = (tempBitmap.getWidth() - tempBitmap.getHeight()) / 2;
    croppedBitmap = Bitmap.createBitmap(tempBitmap, start, 0, tempBitmap.getHeight(), tempBitmap.getHeight(), matrix, true);
} else {
    int start = (tempBitmap.getHeight() - tempBitmap.getWidth()) / 2;
    croppedBitmap = Bitmap.createBitmap(tempBitmap, 0, start, tempBitmap.getWidth(), tempBitmap.getWidth(), matrix, true);
}

8

おそらくこれまでで最も簡単なソリューション:

public static Bitmap cropCenter(Bitmap bmp) {
    int dimension = Math.min(bmp.getWidth(), bmp.getHeight());
    return ThumbnailUtils.extractThumbnail(bmp, dimension, dimension);
}

インポート:

import android.media.ThumbnailUtils;
import java.lang.Math;
import android.graphics.Bitmap;

3

@willsteelソリューションを修正するには:

if (landscape){
                int start = (tempBitmap.getWidth() - tempBitmap.getHeight()) / 2;
                croppedBitmap = Bitmap.createBitmap(tempBitmap, start, 0, tempBitmap.getHeight(), tempBitmap.getHeight(), matrix, true);
            } else {
                int start = (tempBitmap.getHeight() - tempBitmap.getWidth()) / 2;
                croppedBitmap = Bitmap.createBitmap(tempBitmap, 0, start, tempBitmap.getWidth(), tempBitmap.getWidth(), matrix, true);
            }

これはWillSteelソリューションの修正です。この場合、tempBitmapは元の(変更されていない)ビットマップのコピー、またはそれ自体です。
Yman

1
public static Bitmap resizeAndCropCenter(Bitmap bitmap, int size, boolean recycle) {
    int w = bitmap.getWidth();
    int h = bitmap.getHeight();
    if (w == size && h == size) return bitmap;
    // scale the image so that the shorter side equals to the target;
    // the longer side will be center-cropped.
    float scale = (float) size / Math.min(w,  h);
    Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap));
    int width = Math.round(scale * bitmap.getWidth());
    int height = Math.round(scale * bitmap.getHeight());
    Canvas canvas = new Canvas(target);
    canvas.translate((size - width) / 2f, (size - height) / 2f);
    canvas.scale(scale, scale);
    Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
    canvas.drawBitmap(bitmap, 0, 0, paint);
    if (recycle) bitmap.recycle();
    return target;
}

private static Bitmap.Config getConfig(Bitmap bitmap) {
    Bitmap.Config config = bitmap.getConfig();
    if (config == null) {
        config = Bitmap.Config.ARGB_8888;
    }
    return config;
}

1
public Bitmap getResizedBitmap(Bitmap bm) {
    int width = bm.getWidth();
    int height = bm.getHeight();

    int narrowSize = Math.min(width, height);
    int differ = (int)Math.abs((bm.getHeight() - bm.getWidth())/2.0f);
    width  = (width  == narrowSize) ? 0 : differ;
    height = (width == 0) ? differ : 0;

    Bitmap resizedBitmap = Bitmap.createBitmap(bm, width, height, narrowSize, narrowSize);
    bm.recycle();
    return resizedBitmap;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.