Jak zmienić rozmiar mapy bitowej w systemie Android?


336

Mam pobraną mapę bitową ciągu Base64 z mojej zdalnej bazy danych ( encodedImagejest to ciąg reprezentujący obraz z Base64):

profileImage = (ImageView)findViewById(R.id.profileImage);

byte[] imageAsBytes=null;
try {
    imageAsBytes = Base64.decode(encodedImage.getBytes());
} catch (IOException e) {e.printStackTrace();}

profileImage.setImageBitmap(
    BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
);

profileImage to mój ImageView

Ok, ale muszę zmienić rozmiar tego obrazu, zanim pokażę go na ImageViewmoim układzie. Muszę go zmienić na 120 x 120.

Czy ktoś może mi powiedzieć kod, aby zmienić jego rozmiar?

Przykłady, które znalazłem, nie mogły zostać zastosowane do bitmapy uzyskanej w oparciu o ciąg base64.


Możliwy duplikat zmiany rozmiaru
mapy

Odpowiedzi:


550

Zmiana:

profileImage.setImageBitmap(
    BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)

Do:

Bitmap b = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
profileImage.setImageBitmap(Bitmap.createScaledBitmap(b, 120, 120, false));

Załóżmy, że masz obraz w wysokiej rozdzielczości, powiedzmy 1200x1200, a gdy go wyświetlisz, będzie on pełny w widoku obrazu. Jeśli przeskaluję go w dół, powiedz 75%, a ekran będzie wyświetlał obraz w całości również w widoku obrazu, co należy zrobić dla takich ekranów?
jxgn

5
CreateScaledBitmap generuje wyjątek braku pamięci na moim Galaxy Tab2, co jest dla mnie bardzo dziwne, ponieważ jest dużo pamięci i nie działa żadna inna konkretna aplikacja. Rozwiązanie Matrix działa jednak.
Ludovic

28
co jeśli chcemy zapisać proporcje?
Błędy występowały

3
Co powiesz na skalowanie dpi? Myślę, że skalowana bitmapa powinna być oparta na wysokości i szerokości ekranu urządzenia?
Doug Ray

2
Użycie funkcji Bitmap.createScaledBitmap () w celu zmniejszenia skali obrazu o ponad połowę oryginalnego rozmiaru może spowodować powstanie artefaktów aliasingu. Możesz rzucić okiem na post, który napisałem, w którym proponuję alternatywy i porównuję jakość i wydajność.
Petrakeas,

288
import android.graphics.Matrix
public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
    int width = bm.getWidth();
    int height = bm.getHeight();
    float scaleWidth = ((float) newWidth) / width;
    float scaleHeight = ((float) newHeight) / height;
    // CREATE A MATRIX FOR THE MANIPULATION
    Matrix matrix = new Matrix();
    // RESIZE THE BIT MAP
    matrix.postScale(scaleWidth, scaleHeight);

    // "RECREATE" THE NEW BITMAP
    Bitmap resizedBitmap = Bitmap.createBitmap(
        bm, 0, 0, width, height, matrix, false);
    bm.recycle();
    return resizedBitmap;
}

EDYCJA: jak sugeruje @aveschini, dodałem bm.recycle();do wycieków pamięci. Pamiętaj, że jeśli używasz poprzedniego obiektu do innych celów, postępuj odpowiednio.


6
Próbowałem zarówno bitmap.createscaledbitmap, jak i tego podejścia macierzowego. Uważam, że obraz jest znacznie wyraźniejszy przy podejściu matrycowym. Nie wiem, czy to jest powszechne, czy tylko dlatego, że używam symulatora zamiast telefonu. Tylko wskazówka dla kogoś, kto napotyka takie same kłopoty jak ja.
Anson Yao,

2
tutaj również musisz dodać bm.recycle (), aby uzyskać znacznie lepszą wydajność pamięci
aveschini

2
Dzięki za rozwiązanie, ale byłoby lepiej, gdyby parametry zostały zmienione; public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight). Spędziłem dużo czasu, zastanawiając się nad tym. ; P
Attacktive

1
Pamiętaj, że prawidłowym importem dla Matrix jest android.graphics.Matrix.
Lev

11
Jest to to samo, co wywołanie Bitmap.createScaledBitmap (). Zobacz android.googlesource.com/platform/frameworks/base/+/refs/heads/…
BamsBamx

122

Jeśli masz już mapę bitową, możesz użyć następującego kodu, aby zmienić rozmiar:

Bitmap originalBitmap = <original initialization>;
Bitmap resizedBitmap = Bitmap.createScaledBitmap(
    originalBitmap, newWidth, newHeight, false);

1
@beginner, jeśli zmienisz rozmiar obrazu, możesz skalować w oparciu o różne wymiary, które albo przekształcają mapę bitową na nieprawidłowe proporcje, albo usuwają niektóre informacje o mapie bitowej.
ZenBalance,

Próbowałem zmienić rozmiar mapy bitowej w oparciu o proporcje, ale potem pojawił się ten błąd. Przyczyna: java.lang.RuntimeException: Canvas: próba użycia przetworzonej mapy bitowej android.graphics.Bitmap@2291dd13
początkujący

@ początkujący za każdym razem, gdy zmieniasz rozmiar mapy bitowej, w zależności od tego, co robisz, zwykle musisz utworzyć kopię o nowym rozmiarze, a nie zmienić rozmiar istniejącej mapy bitowej (ponieważ w tym przypadku wygląda to na odniesienie do mapy bitowej już przetworzone w pamięci).
ZenBalance,

1
poprawne ... próbowałem i działa teraz poprawnie. dzięki
początkujący

39

Skala oparta na współczynniku kształtu :

float aspectRatio = yourSelectedImage.getWidth() / 
    (float) yourSelectedImage.getHeight();
int width = 480;
int height = Math.round(width / aspectRatio);

yourSelectedImage = Bitmap.createScaledBitmap(
    yourSelectedImage, width, height, false);

Aby użyć wysokości jako podstawy szerokości, zmień na:

int height = 480;
int width = Math.round(height * aspectRatio);

24

Skaluj bitmapę z docelowym maksymalnym rozmiarem i szerokością, zachowując proporcje:

int maxHeight = 2000;
int maxWidth = 2000;    
float scale = Math.min(((float)maxHeight / bitmap.getWidth()), ((float)maxWidth / bitmap.getHeight()));

Matrix matrix = new Matrix();
matrix.postScale(scale, scale);

bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

7

spróbuj tego kodu:

BitmapDrawable drawable = (BitmapDrawable) imgview.getDrawable();
Bitmap bmp = drawable.getBitmap();
Bitmap b = Bitmap.createScaledBitmap(bmp, 120, 120, false);

Mam nadzieję, że to się przyda.


7

Ktoś zapytał, jak zachować proporcje w tej sytuacji:

Oblicz współczynnik używany do skalowania i użyj go dla obu wymiarów. Powiedzmy, że chcesz, aby obraz miał 20% wysokości ekranu

int scaleToUse = 20; // this will be our percentage
Bitmap bmp = BitmapFactory.decodeResource(
    context.getResources(), R.drawable.mypng);
int sizeY = screenResolution.y * scaleToUse / 100;
int sizeX = bmp.getWidth() * sizeY / bmp.getHeight();
Bitmap scaled = Bitmap.createScaledBitmap(bmp, sizeX, sizeY, false);

Aby uzyskać rozdzielczość ekranu, masz następujące rozwiązanie: Uzyskaj wymiary ekranu w pikselach


3

Spróbuj tego: Ta funkcja proporcjonalnie zmienia rozmiar mapy bitowej. Gdy ostatni parametr jest ustawiony na „X”, newDimensionXorYtraktowany jest jak nowa szerokość, a gdy ustawiony jest na „Y” nowa wysokość.

public Bitmap getProportionalBitmap(Bitmap bitmap, 
                                    int newDimensionXorY, 
                                    String XorY) {
    if (bitmap == null) {
        return null;
    }

    float xyRatio = 0;
    int newWidth = 0;
    int newHeight = 0;

    if (XorY.toLowerCase().equals("x")) {
        xyRatio = (float) newDimensionXorY / bitmap.getWidth();
        newHeight = (int) (bitmap.getHeight() * xyRatio);
        bitmap = Bitmap.createScaledBitmap(
            bitmap, newDimensionXorY, newHeight, true);
    } else if (XorY.toLowerCase().equals("y")) {
        xyRatio = (float) newDimensionXorY / bitmap.getHeight();
        newWidth = (int) (bitmap.getWidth() * xyRatio);
        bitmap = Bitmap.createScaledBitmap(
            bitmap, newWidth, newDimensionXorY, true);
    }
    return bitmap;
}

3
profileImage.setImageBitmap(
    Bitmap.createScaledBitmap(
        BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length), 
        80, 80, false
    )
);

3
  public Bitmap scaleBitmap(Bitmap mBitmap) {
        int ScaleSize = 250;//max Height or width to Scale
        int width = mBitmap.getWidth();
        int height = mBitmap.getHeight();
        float excessSizeRatio = width > height ? width / ScaleSize : height / ScaleSize;
         Bitmap bitmap = Bitmap.createBitmap(
                mBitmap, 0, 0,(int) (width/excessSizeRatio),(int) (height/excessSizeRatio));
        //mBitmap.recycle(); if you are not using mBitmap Obj
        return bitmap;
    }

dla mnie to zadziałało po trochę przepisywaniu nadmiaru floatSizeRatio = szerokość> wysokość? (float) ((float) width / (float) ScaleSize): (float) ((float) height / (float) ScaleSize);
Csabi

3
public static Bitmap resizeBitmapByScale(
            Bitmap bitmap, float scale, boolean recycle) {
        int width = Math.round(bitmap.getWidth() * scale);
        int height = Math.round(bitmap.getHeight() * scale);
        if (width == bitmap.getWidth()
                && height == bitmap.getHeight()) return bitmap;
        Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap));
        Canvas canvas = new Canvas(target);
        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;
    }


2

Zmiana rozmiaru mapy bitowej na podstawie dowolnego rozmiaru wyświetlacza

public Bitmap bitmapResize(Bitmap imageBitmap) {

    Bitmap bitmap = imageBitmap;
    float heightbmp = bitmap.getHeight();
    float widthbmp = bitmap.getWidth();

    // Get Screen width
    DisplayMetrics displaymetrics = new DisplayMetrics();
    this.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    float height = displaymetrics.heightPixels / 3;
    float width = displaymetrics.widthPixels / 3;

    int convertHeight = (int) hight, convertWidth = (int) width;

    // higher
    if (heightbmp > height) {
        convertHeight = (int) height - 20;
        bitmap = Bitmap.createScaledBitmap(bitmap, convertWidth,
                convertHighet, true);
    }

    // wider
    if (widthbmp > width) {
        convertWidth = (int) width - 20;
        bitmap = Bitmap.createScaledBitmap(bitmap, convertWidth,
                convertHeight, true);
    }

    return bitmap;
}

1

Chociaż zaakceptowana odpowiedź jest poprawna, nie zmienia rozmiaru Bitmap, zachowując ten sam współczynnik kształtu . Jeśli szukasz metody zmiany rozmiaru Bitmapprzy zachowaniu tego samego współczynnika proporcji, możesz użyć następującej funkcji narzędziowej. Szczegóły użytkowania i objaśnienie funkcji znajdują się pod tym linkiem .

public static Bitmap resizeBitmap(Bitmap source, int maxLength) {
       try {
           if (source.getHeight() >= source.getWidth()) {
               int targetHeight = maxLength;
               if (source.getHeight() <= targetHeight) { // if image already smaller than the required height
                   return source;
               }

               double aspectRatio = (double) source.getWidth() / (double) source.getHeight();
               int targetWidth = (int) (targetHeight * aspectRatio);

               Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
               if (result != source) {
               }
               return result;
           } else {
               int targetWidth = maxLength;

               if (source.getWidth() <= targetWidth) { // if image already smaller than the required height
                   return source;
               }

               double aspectRatio = ((double) source.getHeight()) / ((double) source.getWidth());
               int targetHeight = (int) (targetWidth * aspectRatio);

               Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
               if (result != source) {
               }
               return result;

           }
       }
       catch (Exception e)
       {
           return source;
       }
   }

0
/**
 * Kotlin method for Bitmap scaling
 * @param bitmap the bitmap to be scaled
 * @param pixel  the target pixel size
 * @param width  the width
 * @param height the height
 * @param max    the max(height, width)
 * @return the scaled bitmap
 */
fun scaleBitmap(bitmap:Bitmap, pixel:Float, width:Int, height:Int, max:Int):Bitmap {
    val scale = px / max
    val h = Math.round(scale * height)
    val w = Math.round(scale * width)
    return Bitmap.createScaledBitmap(bitmap, w, h, true)
  }

0

Utrzymanie proporcji,

  public Bitmap resizeBitmap(Bitmap source, int width,int height) {
    if(source.getHeight() == height && source.getWidth() == width) return source;
    int maxLength=Math.min(width,height);
    try {
        source=source.copy(source.getConfig(),true);
        if (source.getHeight() <= source.getWidth()) {
            if (source.getHeight() <= maxLength) { // if image already smaller than the required height
                return source;
            }

            double aspectRatio = (double) source.getWidth() / (double) source.getHeight();
            int targetWidth = (int) (maxLength * aspectRatio);

            return Bitmap.createScaledBitmap(source, targetWidth, maxLength, false);
        } else {

            if (source.getWidth() <= maxLength) { // if image already smaller than the required height
                return source;
            }

            double aspectRatio = ((double) source.getHeight()) / ((double) source.getWidth());
            int targetHeight = (int) (maxLength * aspectRatio);

            return Bitmap.createScaledBitmap(source, maxLength, targetHeight, false);

        }
    }
    catch (Exception e)
    {
        return source;
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.