Bitmap'in Android Kırpma Merkezi


150

Kareler veya dikdörtgenler olan bitmap'lerim var. En kısa tarafı alıp şöyle bir şey yapıyorum:

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

Sonra bunu kullanarak 144 x 144 Bitmap ölçek:

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

Sorun şu ki, orijinal bitmap'in sol üst köşesini kırpıyor, Herkes bitmap'in merkezini kırpacak koda sahip mi?

Yanıtlar:


354

resim açıklamasını buraya girin

Bu, Bitmap.createBitmap (kaynak, x, y, genişlik, yükseklik) ile elde edilebilir.

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
Cevabı, gerçek hedef bitmap'in bir kare olacağı şekilde düzenledi.
Joram van den Boezem

1
@ Lumum: Revizyon 3'ü neden geri aldınız? Geçerli bir doğru gibi görünüyordu. Geçerli sürümünüz doğru başlangıç ​​noktasını oluşturur, ancak daha sonra çok uzun tarafın geri kalanını içerir. Örneğin bir 100x1000görüntü verildiğinde bir görüntüyü geri alırsınız 100x550.
Mart'ta Guvante

Teşekkürler, haklısınız, biçim Bitmap.createBitmap (kaynak, x, y, genişlik, yükseklik)
Lumis

11
Yerleşik ThumbnailUtils.extractThumbnail () yöntemini kullanma hakkındaki cevabımı görün. Neden tekerleği yeniden icat ??? stackoverflow.com/a/17733530/1103584
DiscDev

1
bu çözüm bir tuval oluşturmak ve daha sonra ona bir çekilebilir çizmekten daha kısadır. ayrıca ThumbnailUtils çözümünden daha az işlem yapar (bu da nasıl ölçeklendirileceğini anlamak için örneklem büyüklüğünü hesaplar).
yincrash

320

Yukarıdaki cevapların çoğu bunu yapmanın bir yolunu sağlarken, bunu başarmak için zaten yerleşik bir yol var ve 1 kod satırı ( 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 nesnesinin geri dönüştürülmesini istiyorsanız, bunu yapan seçenekleri iletebilirsiniz:

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

Gönderen: ThumbnailUtils Belgeleri

Genel statik Bitmap özü: Kelebek (Bitmap kaynağı, int genişliği, int yüksekliği)

API seviye 8'e eklendi İstenen boyutta ortalanmış bir bitmap oluşturur.

Parametreler kaynak orijinal bitmap kaynak genişliği hedeflenen genişlik yükseklik hedeflenen yükseklik

Kabul edilen yanıtı kullanırken bazen bellek hatalarından çıkıyordum ve ThumbnailUtils kullanarak bu sorunları benim için çözdüm. Ayrıca, bu çok daha temiz ve daha yeniden kullanılabilir.


6
+1 Bence bu kodu geliştirmek ve 400px kullanmak yerine, yukarıdaki orijinal yazı için bir alternatif sağlamak için en kısa bmp boyutunu geçmek gerekir. Ancak bunu dikkatimize sunduğunuz için teşekkür ederiz, çok yararlı bir işlev gibi görünüyor. Yazık ki daha önce görmedim ...
Lumis

Doğru, somut bir örnek vermek için 400
kod yazdım

4
@DiscDev - bu kelimenin tam anlamıyla bu sitenin en yararlı cevaplarından biri olmalıdır. Ciddi anlamda. Android soruları garip - basit açık cevabı bulmadan önce iki saat arayabilirsiniz. Size nasıl teşekkür edeceğinizi bilmiyorum. Yolda ödül!
Fattie

2
Eski bitmap'i de geri dönüştürmek için biraz farklı bir işlev bile kullanabilirsiniz: = ThumbnailUtils.extractThumbnail (bitmap, genişlik, yükseklik, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
Android geliştirici

1
Bu, android sorusu için şimdiye kadar gördüğüm en güçlü cevap. Android'de Bitmap'i ölçeklendirmek / kırpmak / küçültmek / yeniden boyutlandırmak için 20 farklı çözüm gibi gördüm. Tüm cevaplar farklı. Ve bu sadece 1 satır alır ve tam olarak beklendiği gibi çalışır. Teşekkür ederim.
Alex Sorokoletov

12

Bunu ... 'dan yapmayı düşündünüz mü layout.xml? Eğer için ayarlayabilirsiniz ScaleType için ve de resmin boyutlarını ayarlamak içeride .ImageViewandroid:scaleType="centerCrop"ImageViewlayout.xml


Bu fikri aşağıdaki OpenGLRenderer hatasıyla denedim: "Bitmap bir dokuya yüklenemeyecek kadar büyük (2432x4320, max = 4096x4096)" Yani, 4320 yüksekliğinin işlenemeyeceğini tahmin ediyorum.
GregM

1
Tabii ki bu doğru bir cevap ve sadece mükemmel soruyu cevaplar! Büyük görüntüler için görüntü kalitesini / boyutunu optimize etme ... Bu farklı bir soru!
ichalos

@ ichalos Belki de aradığınızı bulmuşsunuzdur, ancak bu orijinal soruyu cevaplamaz. Orijinal soru tuval üzerine elle renderleme ile ilgili .. aslında, kimsenin bir fotoğrafı kırpmak için ilk denemenin bir tuval üzerine elle render olacağından emin değilim, ama hey, burada bir çözüm bulduğunuzda iyi :)
milosmns

@milosmns Belki haklısın. Belki de bu, kullanıcının merkeze manuel olarak kırpma sorununa nasıl yaklaşmaya çalıştığıdır. Her şey orijinal kullanıcının tam ihtiyaçlarına bağlıdır.
ichalos

9

Sorununuzu çözebilecek aşağıdaki kodu kullanabilirsiniz.

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

Yukarıdaki yöntem kırpma sonrası görüntünün çağrılması, böylece OOM hatası almadan kırpılmış görüntü ile en iyi sonucu elde edebilirsiniz.

Daha fazla ayrıntı için bu bloga başvurabilirsiniz


1
E / AndroidRuntime (30010): java.lang.IllegalArgumentException: neden olduğu x + genişliği olmalıdır olmak <= bitmap.width () ve bunun nedeni 4 kez 100 piksel
stan

9

Burada , keyfi boyutlarda bir [bitmap] ' in merkezini kesen ve sonucu istediğiniz [IMAGE_SIZE] ile ölçeklendiren daha eksiksiz bir snippet . Böylece, her zaman sabit bir boyutta [croppedBitmap] ölçekli kare elde edersiniz . küçük resimler ve benzeri için idealdir.

Diğer çözümlerin daha eksiksiz bir kombinasyonu.

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

Muhtemelen şimdiye kadarki en kolay çözüm:

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

ithalat:

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

3

@Willsteel çözümünü düzeltmek için:

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

bu WillSteel çözümü için bir çözümdür. Bu durumda, tempBitmap yalnızca orijinal (değiştirilmemiş) Bitmap'in veya kendisinin bir kopyasıdır.
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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.