Android Crop Center di Bitmap


150

Ho bitmap che sono quadrati o rettangoli. Prendo il lato più corto e faccio qualcosa del genere:

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

Quindi lo ridimensiono su una bitmap 144 x 144 usando questo:

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

Il problema è che ritaglia l'angolo in alto a sinistra della bitmap originale, Qualcuno ha il codice per ritagliare il centro della bitmap?

Risposte:


354

inserisci qui la descrizione dell'immagine

Questo può essere ottenuto con: Bitmap.createBitmap (sorgente, x, y, larghezza, altezza)

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
Modificata la risposta in modo che la bitmap di destinazione effettiva sia un quadrato.
Joram van den Boezem,

1
@Lumis: Perché hai effettuato il rollback della revisione 3? Sembrava un valido valido. La tua versione attuale crea il punto di partenza corretto ma poi include il resto del lato troppo lungo. Ad esempio, data 100x1000un'immagine ottieni 100x550un'immagine.
Guvante,

Grazie, hai ragione, il formato è Bitmap.createBitmap (sorgente, x, y, larghezza, altezza)
Lumis

11
Vedi la mia risposta sull'utilizzo del metodo ThumbnailUtils.extractThumbnail () incorporato. Perché reinventare la ruota ??? stackoverflow.com/a/17733530/1103584
DiscDev

1
questa soluzione è più breve della creazione di una tela e quindi del disegno di un disegno. inoltre esegue meno elaborazioni rispetto alla soluzione ThumbnailUtils (che calcola le dimensioni del campione per capire come ridimensionare).
yincrash,

320

Mentre la maggior parte delle risposte di cui sopra fornisce un modo per farlo, esiste già un modo integrato per ottenere questo risultato ed è 1 riga di codice ( 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());
}

Se si desidera riciclare l'oggetto bitmap, è possibile passare opzioni che lo rendono tale:

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

Da: Documentazione ThumbnailUtils

estratto statico di bitmap pubblicoTumbumb (origine bitmap, larghezza int, altezza int)

Aggiunto nel livello API 8 Crea una bitmap centrata della dimensione desiderata.

Parametri sorgente originale bitmap larghezza sorgente larghezza target altezza target altezza target

A volte stavo esaurendo gli errori di memoria quando utilizzavo la risposta accettata e l'utilizzo di ThumbnailUtils mi ha risolto questi problemi. Inoltre, questo è molto più pulito e riutilizzabile.


6
+1 Penso che dovresti migliorare questo codice e invece di usare 400px, passa la dimensione del bmp più breve, al fine di fornire un'alternativa al post originale sopra. Ma grazie per averlo portato alla nostra attenzione, sembra una funzione molto utile. Peccato non l'ho mai visto prima ...
Lumis,

Bene, ho appena codificato 400 per fare un esempio concreto ... i dettagli dipendono dall'implementatore :)
DiscDev

4
@DiscDev - questa dovrebbe essere letteralmente una delle risposte più utili su questo intero sito. Sul serio. È strano con le domande su Android: puoi cercare spesso due ore prima di trovare la semplice risposta ovvia. Non so ringraziarti abbastanza. Bounty in rotta!
Fattie,

2
Potresti anche usare una funzione leggermente diversa, per riciclare anche la vecchia bitmap: = ThumbnailUtils.extractThumbnail (bitmap, larghezza, altezza, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
sviluppatore Android

1
Questa è la risposta più potente che ho visto finora per la domanda Android. Ho visto come 20 diverse soluzioni su come ridimensionare / ritagliare / ridimensionare / ridimensionare e così via Bitmap su Android. Tutte le risposte sono diverse. E questo prende solo 1 riga e funziona esattamente come previsto. Grazie.
Alex Sorokoletov,

12

Hai pensato di farlo dal layout.xml? È possibile impostare per il vostro ImageViewlo ScaleType per android:scaleType="centerCrop"e impostare le dimensioni dell'immagine nella ImageViewall'interno della layout.xml.


Ho provato questa idea con il seguente errore OpenGLRenderer: "Bitmap troppo grande per essere caricato in una trama (2432x4320, max = 4096x4096)" Quindi, immagino che l'altezza 4320 non possa essere elaborata.
GregM,

1
Naturalmente questa è una risposta corretta e risponde alla domanda semplicemente perfetta! Ottimizzare la qualità / dimensione dell'immagine per immagini di grandi dimensioni ... Beh, è ​​una domanda diversa!
ichalos,

@ichalos Forse hai trovato quello che cercavi, ma questo non risponde alla domanda originale. La domanda originale era sul rendering manuale su tela .. in realtà, non sono sicuro di come il primo tentativo di qualcuno di ritagliare una foto sarebbe il rendering manuale su una tela, ma hey, bene che hai trovato una soluzione qui :)
milosmns

@milosmns Forse hai ragione. Forse è così che l'utente ha cercato di affrontare il problema del ritaglio manuale al centro. Tutto dipende dalle esigenze esatte dell'utente originale.
ichalos,

9

È possibile utilizzare il seguente codice che può risolvere il problema.

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

Il metodo sopra fa postScalling dell'immagine prima del ritaglio, in modo da poter ottenere i migliori risultati con l'immagine ritagliata senza ottenere errori OOM.

Per maggiori dettagli puoi consultare questo blog


1
E / AndroidRuntime (30010): Causato da: java.lang.IllegalArgumentException: x + width deve essere <= bitmap.width () e questo a causa di 4 volte 100px
Stan

9

Qui uno snippet più completo che ritaglia il centro di una [bitmap] di dimensioni arbitrarie e ridimensiona il risultato in base al [IMAGE_SIZE] desiderato . In questo modo otterrai sempre un quadrato in scala [croppedBitmap] del centro dell'immagine con una dimensione fissa. ideale per miniature e simili.

È una combinazione più completa delle altre soluzioni.

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

Probabilmente la soluzione più semplice finora:

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

importazioni:

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

3

Per correggere la soluzione @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);
            }

questa è una soluzione alla soluzione WillSteel. In questo caso, tempBitmap è solo una copia della Bitmap originale (inalterata) o di se stessa.
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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.