Centre de cultures Android de Bitmap

150

J'ai des bitmaps qui sont des carrés ou des rectangles. Je prends le côté le plus court et fais quelque chose comme ceci:

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

Ensuite, je le redimensionne à un bitmap 144 x 144 en utilisant ceci:

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

Le problème est qu'il recadre le coin supérieur gauche du bitmap d'origine. Quelqu'un a-t-il le code pour recadrer le centre du bitmap?

Maurice
la source

Réponses:

354

entrez la description de l'image ici

Ceci peut être réalisé avec: Bitmap.createBitmap (source, x, y, largeur, hauteur)

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
la source
1
Modification de la réponse afin que le bitmap de destination réel soit un carré.
Joram van den Boezem
1
@Lumis: Pourquoi avez-vous annulé la révision 3? Cela semblait être un correct correct. Votre version actuelle crée le bon point de départ, mais inclut ensuite le reste du côté trop long. Par exemple, étant donné une 100x1000image, vous récupérez une 100x550image.
Guvante
Merci, vous avez raison, le format est Bitmap.createBitmap (source, x, y, largeur, hauteur)
Lumis
11
Voir ma réponse sur l'utilisation de la méthode intégrée ThumbnailUtils.extractThumbnail (). Pourquoi réinventer la roue ??? stackoverflow.com/a/17733530/1103584
DiscDev
1
cette solution est plus courte que de créer un canevas et d'y dessiner ensuite un dessin. elle effectue également moins de traitement que la solution ThumbnailUtils (qui calcule la taille de l'échantillon pour déterminer comment mettre à l'échelle).
yincrash
320

Bien que la plupart des réponses ci-dessus fournissent un moyen de le faire, il existe déjà un moyen intégré de le faire et il s'agit d'une ligne de code ( 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());
}

Si vous voulez que l'objet bitmap soit recyclé, vous pouvez passer des options qui le rendent ainsi:

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

De: Documentation ThumbnailUtils

public static Bitmap extractThumbnail (source Bitmap, largeur int, hauteur int)

Ajouté au niveau de l'API 8 Crée un bitmap centré de la taille souhaitée.

Paramètres source source bitmap originale largeur cible largeur cible hauteur cible

Je sortais parfois d'erreurs de mémoire lors de l'utilisation de la réponse acceptée, et l'utilisation de ThumbnailUtils a résolu ces problèmes pour moi. De plus, c'est beaucoup plus propre et plus réutilisable.

DiscDev
la source
6
+1 Je pense que vous devriez améliorer ce code et au lieu d'utiliser 400px, passez la taille de bmp la plus courte, afin de fournir une alternative au message original ci-dessus. Mais merci d'avoir porté cela à notre attention, cela semble une fonction très utile. Dommage que je ne l'ai pas vu auparavant ...
Lumis
Bon, je viens de coder en dur 400 pour donner un exemple concret ... les détails sont à la charge de l'implémenteur :)
DiscDev
4
@DiscDev - cela devrait être littéralement l'une des réponses les plus utiles de tout ce site. Sérieusement. C'est bizarre avec les questions Android - vous pouvez souvent rechercher pendant deux heures avant de trouver la réponse simple et évidente. Je ne sais pas comment vous remercier assez. Bounty en route!
Fattie
2
Vous pouvez même utiliser une fonction un peu différente, pour recycler également l'ancien bitmap: = ThumbnailUtils.extractThumbnail (bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
développeur android
1
C'est la réponse la plus puissante que j'ai vue jusqu'à présent pour la question Android. J'ai vu 20 solutions différentes pour redimensionner / recadrer / réduire / redimensionner et ainsi de suite Bitmap sur Android. Toutes les réponses sont différentes. Et celui-ci ne prend qu'une ligne et fonctionne exactement comme prévu. Je vous remercie.
Alex Sorokoletov
12

Avez-vous envisagé de faire cela depuis le layout.xml? Vous pouvez définir pour votre ImageViewl' ScaleType à android:scaleType="centerCrop"et définir les dimensions de l'image dans l' ImageViewintérieur du layout.xml.

Ovidiu Latcu
la source
J'ai essayé cette idée avec l'erreur OpenGLRenderer suivante: "Bitmap trop grand pour être téléchargé dans une texture (2432x4320, max = 4096x4096)" Donc, je suppose que la hauteur 4320 ne peut pas être traitée.
GregM
1
Bien sûr, c'est une réponse correcte et répond à la question tout simplement parfaite! Optimiser la qualité / taille de l'image pour les grandes images ... Eh bien, c'est une autre question!
ichalos
@ichalos Vous avez peut-être trouvé ce que vous cherchiez, mais cela ne répond pas à la question initiale. La question initiale concernait le rendu manuel sur la toile ... en fait, je ne suis pas sûr de savoir comment la première tentative de recadrage d'une photo serait
rendue
@milosmns Peut-être que vous avez raison. C'est peut-être ainsi que l'utilisateur a tenté d'aborder le problème du recadrage manuel vers le centre. Tout dépend des besoins exacts de l'utilisateur d'origine.
ichalos
9

Vous pouvez utiliser le code suivant qui peut résoudre votre problème.

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

La méthode ci-dessus fait postScalling de l'image avant le recadrage, afin que vous puissiez obtenir le meilleur résultat avec l'image recadrée sans obtenir d'erreur OOM.

Pour plus de détails, vous pouvez consulter ce blog

Hitesh Patel
la source
1
E / AndroidRuntime (30010): Causé par: java.lang.IllegalArgumentException: x + width doit être <= bitmap.width () et ceci à cause de 4 fois 100px
Stan
9

Voici un extrait de code plus complet qui rogne le centre d'un [bitmap] de dimensions arbitraires et met le résultat à l' échelle [IMAGE_SIZE] souhaitée . Ainsi, vous obtiendrez toujours un carré [croppedBitmap] du centre de l'image avec une taille fixe. idéal pour les vignettes et autres.

C'est une combinaison plus complète des autres solutions.

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
la source
8

Probablement la solution la plus simple à ce jour:

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

importations:

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

Pour corriger la solution @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
la source
il s'agit d'un correctif de la solution WillSteel. Dans ce cas, tempBitmap est juste une copie du Bitmap original (non modifié), ou lui-même.
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
la source
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
la source