Android-центр растровых изображений Android


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 x 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
Отредактировал ответ так, чтобы фактическое изображение назначения было квадратом.
— Йорам ван ден Бозем

1
@Lumis: Почему вы откатили ревизию 3? Это оказалось правильным. Ваша текущая версия создает правильную отправную точку, но затем включает в себя остаток слишком длинной стороны. Например, учитывая 100x1000изображение, вы получаете 100x550изображение обратно .
— Гуванте

Спасибо, вы правы, формат Bitmap.createBitmap (источник, x, y, ширина, высота)
— Lumis

11
Смотрите мой ответ об использовании встроенного метода ThumbnailUtils.extractThumbnail (). Зачем изобретать велосипед ??? stackoverflow.com/a/17733530/1103584
— DiscDev

1
это решение короче, чем создание холста, а затем рисование на нем рисунка. он также выполняет меньше операций, чем решение ThumbnailUtils (которое вычисляет размер выборки, чтобы выяснить, как масштабировать).
— Инкраш

320

Хотя большинство из приведенных выше ответов обеспечивают способ сделать это, уже есть встроенный способ сделать это, и это 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 Документация

общедоступная статическая растровая карта extractThumbnail (источник растрового изображения, int width, int height)

Добавлено на уровне API 8 Создает центрированное растровое изображение нужного размера.

Параметры исходный исходный растровое изображение ширина источника целевая ширина высота целевая высота

Иногда я получал ошибки памяти при использовании принятого ответа, и использование ThumbnailUtils решало эти проблемы для меня. Плюс, это намного чище и более многоразово.


6
+1 Я думаю, вам нужно улучшить этот код и вместо 400px передать самый короткий размер bmp, чтобы обеспечить альтернативу исходному посту выше. Но спасибо, что обратили на это наше внимание, это кажется очень полезной функцией. Жаль, что я не видел это раньше ...
— Lumis

Правильно, я просто жестко запрограммировал 400, чтобы привести конкретный пример ... детали до разработчика :)
— DiscDev

4
@DiscDev - это должен быть буквально один из самых полезных ответов на всем этом сайте. Шутки в сторону. Это странно с вопросами об Android - вы можете часто искать в течение двух часов, прежде чем найдете простой очевидный ответ. Не знаю, как тебя отблагодарить. Баунти в пути!
— Толстяк

2
Вы могли бы даже использовать немного другую функцию, чтобы также утилизировать старую битовую карту: = ThumbnailUtils.extractThumbnail (bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
— разработчик Android

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

Вышеупомянутый метод делает postScalling изображения перед кадрированием, так что вы можете получить лучший результат с кадрированным изображением без ошибки OOM.

Для более подробной информации вы можете обратиться к этому блогу


1
E / AndroidRuntime (30010): вызвано: java.lang.IllegalArgumentException: x + width должно быть <= bitmap.width (), и это из-за 4-кратного 100px
— Стан

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 - это просто копия исходного (неизмененного) Bitmap или самого себя.
— Иман

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.