Android Crop Center Bitmap


150

У мене є растрові карти, які є квадратами або прямокутниками. Я приймаю найкоротший бік і роблю щось подібне:

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

Потім я масштабую її до 144-144 бітової карти за допомогою цього:

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

Проблема полягає в тому, що він обрізає верхній лівий кут оригінальної растрової карти. Хтось має код, щоб обрізати центр растрової карти?

Відповіді:


354

введіть тут опис зображення

Цього можна досягти за допомогою: Bitmap.createBitmap (джерело, x, y, ширина, висота)

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
Відповідь відредагували так, що фактична растрова карта призначення - це квадрат.
Joram van den Boezem

1
@Lumis: Чому ти відмовив версію 3? Це виявилося дійсним правильним. Ваша поточна версія створює правильну вихідну точку, але потім містить залишок занадто довгої сторони. Наприклад, давши 100x1000зображення, ви отримуєте назад 100x550зображення.
Гуванте

Дякую, ви праві, формат - Bitmap.createBitmap (джерело, х, у, ширина, висота)
Lumis

11
Дивіться мою відповідь про використання вбудованого методу ThumbnailUtils.extractThumbnail (). Навіщо винаходити колесо ??? stackoverflow.com/a/17733530/1103584
DiscDev

1
це рішення коротше, ніж створити полотно, а потім намалювати на ньому малюнок. він також обробляє менше, ніж рішення ThumbnailUtils (який робить розмір вибірки, обчислюючи, щоб зрозуміти, як масштабувати).
yincrash

319

Хоча більшість вищезазначених відповідей дають спосіб це зробити, для цього вже є вбудований спосіб, і це 1 рядок коду ( 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 = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);

Від: Документація ThumbnailUtils

загальнодоступний статичний витяг BitmapThumbnail (джерело растрового зображення, int ширина, int висота)

Додано в рівні API 8. Створює централізовану растрову карти потрібного розміру.

Параметри джерела вихідного растрового зображення, ширина джерела, орієнтована ширина, задана висота

Я часом виходив із помилок пам'яті, коли використовував прийняту відповідь, і за допомогою ThumbnailUtils вирішував ці проблеми для мене. Плюс це набагато чистіше і багаторазове використання.


6
+1 Я думаю, що вам доведеться вдосконалити цей код і замість того, щоб використовувати 400px, передайте найменший розмір bmp, щоб запропонувати альтернативу для початкової публікації вище. Але дякую, що ви звернули це на нашу увагу, це здається дуже корисною функцією. Шкода, що я його раніше не бачив ...
Луміс

Право, я просто зашифрував 400, щоб навести конкретний приклад ... деталі залежать від виконавця :)
DiscDev

4
@DiscDev - це повинно бути буквально однією з найкорисніших відповідей на всьому цьому сайті. Серйозно. Дивно з питаннями щодо Android - ви часто можете шукати дві години, перш ніж знайти просту очевидну відповідь. Не знаю, як вам подякувати. Баунті на шляху!
Fattie

2
Ви можете навіть використовувати трохи іншу функцію, щоб також переробити стару растрову карту: = ThumbnailUtils.extractThumbnail (растрова, ширина, висота, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
андроїд розробник

1
Це найпотужніша відповідь, яку я бачив поки що на питання щодо Android. Я бачив, як 20 різних рішень, як масштабувати / обрізати / зменшувати масштаби / змінювати розмір і так далі, Bitmap на Android. Усі відповіді різні. А цей просто займає 1 рядок і працює точно так, як очікувалося. Дякую.
Олексій Сороколетов

12

Ви думали зробити це з боку layout.xml? Ви можете встановити для вашого ImageViewна ScaleType до android:scaleType="centerCrop"і встановити розміри зображення в ImageViewвсередині layout.xml.


Я спробував цю ідею із такою помилкою OpenGLRenderer: "Бітова карта занадто велика для завантаження в текстуру (2432x4320, max = 4096x4096)" Отже, я здогадуюсь, висоту 4320 неможливо обробити.
ГрегМ

1
Звичайно, це правильна відповідь і відповідає на питання просто ідеально! Оптимізація якості / розміру зображення для великих зображень ... Ну, це вже інше питання!
ichalos

@ichalos Можливо, ви знайшли те, що шукали, але це не відповідає на початкове запитання. Оригінальне питання стосувалося рендерінгу на полотні .. насправді я не впевнений, як би хтось намагався обрізати фотографію вручну на полотні, але еге, добре, що ви знайшли рішення тут :)
milosmns

@milosmns Можливо, ти маєш рацію. Можливо, саме так користувач намагався підійти до проблеми ручного обрізання до центру. Все залежить від точних потреб оригінального користувача.
ichalos

9

Ви можете використовувати наступний код, який може вирішити вашу проблему.

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

Вищенаведений метод виконайте постсканування зображення перед обрізанням, щоб ви могли отримати найкращий результат із обрізаним зображенням, не отримуючи помилки OOM.

Більш детально ви можете посилатися на цей блог


1
E / AndroidRuntime (30010): Викликано: java.lang.IllegalArgumentException: x + width має бути <= bitmap.width (), і це через 4 рази 100px
Stan

9

Тут є більш повний фрагмент, який вирізає центр [бітової карти] довільних розмірів і масштабує результат до потрібного [IMAGE_SIZE] . Таким чином, ви завжди отримаєте [croppedBitmap] масштабний квадрат центру зображення з фіксованим розміром. ідеально підходить для ескізів тощо.

Це більш повне поєднання інших рішень.

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

Напевно, найпростіше рішення поки що:

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

імпорт:

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

3

Щоб виправити рішення @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);
            }

це виправлення рішення WillSteel. У цьому випадку tempBitmap - це лише копія оригінального (незмінного) растрового зображення або себе.
Іман

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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.