Android Crop Center of Bitmap

150

Saya memiliki bitmap yang kotak atau persegi panjang. Saya mengambil sisi terpendek dan melakukan sesuatu seperti ini:

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);

Kemudian saya skalakan menjadi 144 x 144 Bitmap menggunakan ini:

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

Masalahnya adalah ia memotong sudut kiri atas bitmap asli, Adakah yang punya kode untuk memotong bagian tengah bitmap?

Maurice
sumber

Jawaban:

354

masukkan deskripsi gambar di sini

Ini dapat dicapai dengan: Bitmap.createBitmap (sumber, x, y, lebar, tinggi)

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() 
     );
}
Lumis
sumber
1
Mengedit jawaban sehingga bitmap tujuan sebenarnya adalah bujur sangkar.
Joram van den Boezem
1
@Lumis: Mengapa Anda mengembalikan revisi 3? Tampaknya itu benar dan benar. Versi Anda saat ini menciptakan titik awal yang benar tetapi kemudian menyertakan sisa dari sisi yang terlalu panjang. Misalnya diberikan 100x1000gambar, Anda mendapatkan kembali 100x550gambar.
Guvante
Terima kasih, Anda benar, formatnya adalah Bitmap.createBitmap (sumber, x, y, lebar, tinggi)
Lumis
11
Lihat jawaban saya tentang menggunakan metode ThumbnailUtils.extractThumbnail () bawaan. Mengapa menemukan kembali roda ??? stackoverflow.com/a/17733530/1103584
DiscDev
1
solusi ini lebih pendek daripada membuat kanvas dan kemudian menggambar yang bisa digambar untuk itu. itu juga melakukan pemrosesan kurang dari solusi ThumbnailUtils (yang menghitung ukuran sampel untuk mencari tahu bagaimana skala).
yincrash
319

Sementara sebagian besar jawaban di atas menyediakan cara untuk melakukan ini, sudah ada cara bawaan untuk mencapai ini dan ini 1 baris kode ( 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());
}

Jika Anda ingin objek bitmap didaur ulang, Anda bisa meneruskan opsi yang membuatnya:

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

Dari: Dokumentasi ThumbnailUtils

mengekstrak Bitmap statis publikThumbnail (sumber Bitmap, lebar int, tinggi int)

Ditambahkan di API level 8 Membuat bitmap terpusat dengan ukuran yang diinginkan.

Sumber sumber, sumber bitmap asli, lebar ditargetkan, tinggi, tinggi, dan tinggi yang ditargetkan

Saya keluar dari kesalahan memori kadang-kadang ketika menggunakan jawaban yang diterima, dan menggunakan ThumbnailUtils menyelesaikan masalah tersebut untuk saya. Plus, ini jauh lebih bersih dan lebih dapat digunakan kembali.

DiscDev
sumber
6
+1 Saya pikir Anda harus memperbaiki kode ini dan alih-alih menggunakan 400px, berikan ukuran bmp terpendek, untuk memberikan alternatif untuk posting asli di atas. Tapi terima kasih telah membawa ini menjadi perhatian kami, sepertinya fungsi yang sangat berguna. Sayang sekali aku belum pernah melihatnya sebelumnya ...
Lumis
Benar, saya hanya hardcoded 400 untuk memberikan contoh konkret ... detailnya terserah implementor :)
DiscDev
4
@DiscDev - ini harus benar-benar salah satu jawaban paling berguna di seluruh situs ini. Serius. Ini aneh dengan pertanyaan Android - Anda sering dapat mencari selama dua jam sebelum menemukan jawaban yang jelas dan sederhana. Tidak tahu bagaimana harus cukup berterima kasih. Bounty dalam perjalanan!
Fattie
2
Anda bahkan dapat menggunakan fungsi yang sedikit berbeda, untuk juga mendaur ulang bitmap lama: = ThumbnailUtils.extractThumbnail (bitmap, lebar, tinggi, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
pengembang android
1
Ini adalah jawaban paling kuat yang pernah saya lihat sejauh ini untuk pertanyaan android. Saya telah melihat seperti 20 solusi berbeda bagaimana skala / memotong / menurunkan / mengubah ukuran dan sebagainya Bitmap di Android. Semua jawaban berbeda. Dan yang ini hanya membutuhkan 1 baris dan bekerja persis seperti yang diharapkan. Terima kasih.
Alex Sorokoletov
12

Sudahkah Anda mempertimbangkan untuk melakukan ini dari layout.xml? Anda bisa mengatur untuk Anda ImageViewyang ScaleType untuk android:scaleType="centerCrop"dan mengatur dimensi gambar di ImageViewdalam layout.xml.

Ovidiu Latcu
sumber
Saya mencoba ide ini dengan kesalahan OpenGLRenderer berikut: "Bitmap terlalu besar untuk diunggah ke dalam tekstur (2432x4320, maks = 4096x4096)" Jadi, saya menduga ketinggian 4320 tidak dapat diproses.
GregM
1
Tentu saja ini adalah jawaban yang benar dan menjawab pertanyaan dengan sempurna! Mengoptimalkan kualitas gambar / ukuran untuk gambar besar ... Ya, ini pertanyaan yang berbeda!
ichalos
@ichalos Mungkin Anda menemukan apa yang Anda cari, tetapi ini tidak menjawab pertanyaan awal. Pertanyaan aslinya adalah tentang render secara manual di atas kanvas .. sebenarnya, saya tidak yakin bagaimana upaya pertama seseorang untuk memotong foto akan secara manual render di atas kanvas, tapi hei, bagusnya Anda menemukan solusi di sini :)
milosmns
@milosmns Mungkin Anda benar. Mungkin ini hanya bagaimana pengguna mencoba mendekati masalah pemangkasan secara manual ke pusat. Itu semua tergantung pada kebutuhan yang tepat dari pengguna asli.
ichalos
9

Anda dapat menggunakan kode berikut yang dapat memecahkan masalah Anda.

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

Metode di atas melakukan postScalling gambar sebelum memotong, sehingga Anda bisa mendapatkan hasil terbaik dengan gambar yang dipangkas tanpa mendapatkan kesalahan OOM.

Untuk lebih jelasnya Anda bisa mereferensikan blog ini

Hitesh Patel
sumber
1
E / AndroidRuntime (30010): Disebabkan oleh: java.lang.IllegalArgumentException: x + width harus <= bitmap.width () dan ini karena 4 kali 100px
Stan
9

Di sini, potongan yang lebih lengkap yang memangkas bagian tengah suatu [bitmap] dimensi arbitrer dan menskala hasilnya ke [IMAGE_SIZE] yang Anda inginkan . Jadi, Anda akan selalu mendapatkan persegi skala [croppedBitmap] dari pusat gambar dengan ukuran tetap. ideal untuk thumbnail dan semacamnya.

Ini kombinasi yang lebih lengkap dari solusi lain.

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);
}
mschmoock
sumber
8

Mungkin solusi termudah sejauh ini:

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

impor:

import android.media.ThumbnailUtils;
import java.lang.Math;
import android.graphics.Bitmap;
Kirill Kulakov
sumber
3

Untuk memperbaiki solusi @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);
            }
Yman
sumber
ini merupakan perbaikan untuk solusi WillSteel. Dalam hal ini, tempBitmap hanyalah salinan dari Bitmap asli (tidak diubah), atau dirinya sendiri.
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;
}
kakopappa
sumber
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;
}
Vahe Gharibyan
sumber