Android Crop Center von Bitmap


149

Ich habe Bitmaps, die Quadrate oder Rechtecke sind. Ich nehme die kürzeste Seite und mache so etwas:

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

Dann skaliere ich es auf eine 144 x 144 Bitmap, indem ich Folgendes verwende:

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

Das Problem ist, dass die obere linke Ecke der ursprünglichen Bitmap zugeschnitten wird. Hat jemand den Code, um die Mitte der Bitmap zuzuschneiden?

Antworten:


353

Geben Sie hier die Bildbeschreibung ein

Dies kann erreicht werden mit: Bitmap.createBitmap (Quelle, x, y, Breite, Höhe)

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
Die Antwort wurde so bearbeitet, dass die tatsächliche Zielbitmap ein Quadrat ist.
Joram van den Boezem

1
@ Lumis: Warum hast du Revision 3 zurückgesetzt? Es schien eine gültige korrekte zu sein. Ihre aktuelle Version erstellt den richtigen Startpunkt, enthält dann aber den Rest der zu langen Seite. Wenn Sie beispielsweise ein 100x1000Bild erhalten, erhalten Sie ein 100x550Bild zurück.
Guvante

Danke, Sie haben Recht, das Format ist Bitmap.createBitmap (Quelle, x, y, Breite, Höhe)
Lumis

11
Siehe meine Antwort zur Verwendung der integrierten ThumbnailUtils.extractThumbnail () -Methode. Warum das Rad neu erfinden ??? stackoverflow.com/a/17733530/1103584
DiscDev

1
Diese Lösung ist kürzer als das Erstellen einer Leinwand und das anschließende Zeichnen einer Zeichenfläche. Außerdem wird weniger verarbeitet als bei der ThumbnailUtils-Lösung (bei der die Stichprobengröße berechnet wird, um herauszufinden, wie skaliert werden soll).
Yincrash

319

Während die meisten der oben genannten Antworten eine Möglichkeit bieten, dies zu tun, gibt es bereits eine integrierte Möglichkeit, dies zu erreichen, und es handelt sich um eine Codezeile ( 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());
}

Wenn Sie möchten, dass das Bitmap-Objekt recycelt wird, können Sie Optionen übergeben, die dies ermöglichen:

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

Von: ThumbnailUtils-Dokumentation

public static Bitmap extractThumbnail (Bitmap-Quelle, int width, int height)

In API-Ebene 8 hinzugefügt Erstellt eine zentrierte Bitmap mit der gewünschten Größe.

Parameter Quelle Original-Bitmap-Quellbreite Zielbreite Höhe Zielhöhe

Bei der Verwendung der akzeptierten Antwort kam es manchmal zu Speicherfehlern, und die Verwendung von ThumbnailUtils löste diese Probleme für mich. Außerdem ist dies viel sauberer und wiederverwendbarer.


6
+1 Ich denke, Sie müssten diesen Code verbessern und statt 400px die kürzeste bmp-Größe übergeben, um eine Alternative für den ursprünglichen Beitrag oben bereitzustellen. Aber danke, dass Sie uns darauf aufmerksam gemacht haben, es scheint eine sehr nützliche Funktion zu sein. Schade, dass ich es noch nie gesehen habe ...
Lumis

Richtig, ich habe gerade 400 hartcodiert, um ein konkretes Beispiel zu geben ... die Details liegen beim Implementierer :)
DiscDev

4
@DiscDev - dies müsste buchstäblich eine der nützlichsten Antworten auf dieser gesamten Website sein. Ernsthaft. Es ist komisch mit Android-Fragen - Sie können oft zwei Stunden lang suchen, bevor Sie die einfache offensichtliche Antwort finden. Ich weiß nicht genug, wie ich dir danken soll. Kopfgeld unterwegs!
Fattie

2
Sie könnten sogar eine etwas andere Funktion verwenden, um auch die alte Bitmap zu recyceln: = ThumbnailUtils.extractThumbnail (Bitmap, Breite, Höhe, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
Android-Entwickler

1
Dies ist die mächtigste Antwort, die ich bisher für Android-Fragen gesehen habe. Ich habe wie 20 verschiedene Lösungen gesehen, wie man Bitmap auf Android skaliert / beschneidet / verkleinert / in der Größe ändert und so weiter. Alle Antworten sind unterschiedlich. Und dieser nimmt nur 1 Zeile und funktioniert genau wie erwartet. Danke dir.
Alex Sorokoletov

12

Haben Sie darüber nachgedacht, dies von der zu tun layout.xml? Sie könnten für Ihr Set ImageViewdes Scaletype auf android:scaleType="centerCrop"und legen Sie die Abmessungen des Bildes in dem ImageViewInnern der layout.xml.


Ich habe diese Idee mit dem folgenden OpenGLRenderer-Fehler versucht: "Bitmap zu groß, um in eine Textur hochgeladen zu werden (2432x4320, max = 4096x4096)" Ich vermute also, dass die Höhe 4320 nicht verarbeitet werden kann.
GregM

1
Natürlich ist dies eine richtige Antwort und beantwortet die Frage einfach perfekt! Optimierung der Bildqualität / -größe für große Bilder ... Nun, das ist eine andere Frage!
Ichalos

@ichalos Vielleicht haben Sie gefunden, wonach Sie gesucht haben, aber dies beantwortet nicht die ursprüngliche Frage. Die ursprüngliche Frage betraf das manuelle Rendern auf Leinwand. Eigentlich bin ich mir nicht sicher, wie jemandes erster Versuch, ein Foto
zuzuschneiden

@milosmns Vielleicht hast du recht. Vielleicht hat der Benutzer auf diese Weise versucht, das Problem des manuellen Zuschneidens in die Mitte anzugehen. Es hängt alles von den genauen Bedürfnissen des ursprünglichen Benutzers ab.
Ichalos

9

Sie können den folgenden Code verwenden, der Ihr Problem lösen kann.

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

Führen Sie die oben beschriebene Methode vor dem Zuschneiden nach dem Aufrufen des Bilds aus, damit Sie mit dem zugeschnittenen Bild das beste Ergebnis erzielen, ohne einen OOM-Fehler zu erhalten.

Weitere Informationen finden Sie in diesem Blog


1
E / AndroidRuntime (30010): Auslöser: java.lang.IllegalArgumentException: x + width muss <= bitmap.width () sein und dies wegen 4 mal 100px
Stan

9

Hier ein vollständigeres Snippet, das die Mitte einer [Bitmap] beliebiger Dimensionen ausschneidet und das Ergebnis auf die gewünschte [IMAGE_SIZE] skaliert . Sie erhalten also immer ein [croppedBitmap] skaliertes Quadrat der Bildmitte mit einer festen Größe. Ideal für Thumbnails und so.

Es ist eine vollständigere Kombination der anderen Lösungen.

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

Wahrscheinlich die bisher einfachste Lösung:

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

Importe:

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

3

So korrigieren Sie die @ willsteel-Lösung:

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

Dies ist eine Lösung für die WillSteel-Lösung. In diesem Fall ist tempBitmap nur eine Kopie der ursprünglichen (unveränderten) Bitmap oder sich selbst.
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;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.