Trung tâm cắt xén Android của Bitmap


150

Tôi có bitmap là hình vuông hoặc hình chữ nhật. Tôi đi về phía ngắn nhất và làm một cái gì đó như thế này:

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

Sau đó, tôi chia tỷ lệ thành Bitmap 144 x 144 bằng cách sử dụng:

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

Vấn đề là nó cắt góc trên cùng bên trái của bitmap gốc, Bất cứ ai cũng có mã để cắt trung tâm của bitmap?

Câu trả lời:


354

nhập mô tả hình ảnh ở đây

Điều này có thể đạt được với: Bitmap.createBitmap (nguồn, x, y, chiều rộng, chiều cao)

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
Chỉnh sửa câu trả lời sao cho bitmap đích thực tế là một hình vuông.
Joram van den Boezem

1
@Lumis: Tại sao bạn lại rollback phiên bản 3? Nó dường như là một chính xác hợp lệ. Phiên bản hiện tại của bạn tạo điểm bắt đầu chính xác nhưng sau đó bao gồm phần còn lại của bên quá dài. Ví dụ, đưa ra một 100x1000hình ảnh bạn nhận lại một 100x550hình ảnh.
Guvante

Cảm ơn, bạn đã đúng, định dạng là Bitmap.createBitmap (nguồn, x, y, chiều rộng, chiều cao)
Lumis

11
Xem câu trả lời của tôi về việc sử dụng phương thức ThumbnailUtils.extractThumbnail () tích hợp. Tại sao phải phát minh lại bánh xe ??? stackoverflow.com/a/17733530/1103584
DiscDev

1
giải pháp này ngắn hơn so với việc tạo ra một khung vẽ và sau đó vẽ một bức vẽ có thể vẽ được. nó cũng xử lý ít hơn so với giải pháp ThumbnailUtils (tính toán kích thước mẫu để tìm ra cách chia tỷ lệ).
yincrash

319

Mặc dù hầu hết các câu trả lời ở trên cung cấp một cách để làm điều này, nhưng đã có một cách tích hợp sẵn để thực hiện điều này và đó là 1 dòng mã ( 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());
}

Nếu bạn muốn đối tượng bitmap được tái chế, bạn có thể vượt qua các tùy chọn khiến nó trở nên như vậy:

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

Từ: Tài liệu ThumbnailUtils

công khai Bitmap tĩnhThumbnail (nguồn Bitmap, int width, int height)

Đã thêm vào API cấp 8 Tạo một bitmap trung tâm có kích thước mong muốn.

Tham số nguồn gốc bitmap chiều rộng nguồn chiều rộng được nhắm mục tiêu chiều cao chiều cao được nhắm mục tiêu

Đôi khi tôi đã thoát khỏi lỗi bộ nhớ khi sử dụng câu trả lời được chấp nhận và sử dụng ThumbnailUtils đã giải quyết những vấn đề đó cho tôi. Thêm vào đó, điều này là sạch sẽ hơn và tái sử dụng nhiều hơn.


6
+1 Tôi nghĩ rằng bạn sẽ phải cải thiện mã này và thay vì sử dụng 400px, hãy vượt qua kích thước bmp ngắn nhất để cung cấp giải pháp thay thế cho bài đăng gốc ở trên. Nhưng cảm ơn bạn đã chú ý đến điều này, nó có vẻ là một chức năng rất hữu ích. Đáng tiếc tôi đã không nhìn thấy nó trước đây ...
Lumis

Đúng vậy, tôi chỉ mã hóa 400 để đưa ra một ví dụ cụ thể ... các chi tiết tùy thuộc vào người triển khai :)
DiscDev

4
@DiscDev - đây sẽ phải là một trong những câu trả lời hữu ích nhất trên toàn bộ trang web này. Nghiêm túc. Thật kỳ lạ với các câu hỏi của Android - bạn thường có thể tìm kiếm trong hai giờ trước khi tìm thấy câu trả lời rõ ràng đơn giản. Không biết làm thế nào để cảm ơn bạn đủ. Bounty trên đường!
Fattie

2
Bạn thậm chí có thể sử dụng một hàm khác nhau, để tái chế bitmap cũ: = ThumbnailUtils.extractThumbnail (bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
nhà phát triển Android

1
Đây là câu trả lời mạnh mẽ nhất tôi từng thấy cho đến nay cho câu hỏi Android. Tôi đã thấy như 20 giải pháp khác nhau về cách chia tỷ lệ / cắt / thu nhỏ / thay đổi kích thước và trên Bitmap trên Android. Tất cả các câu trả lời là khác nhau. Và cái này chỉ mất 1 dòng và hoạt động chính xác như mong đợi. Cảm ơn bạn.
Alex Sorokoletov

12

Bạn đã xem xét làm điều này từ layout.xml? Bạn có thể đặt cho ImageViewcác ScaleType đến android:scaleType="centerCrop"và thiết lập kích thước của hình ảnh trong ImageViewbên trong layout.xml.


Tôi đã thử ý tưởng này với lỗi OpenGLRenderer sau: "Bitmap quá lớn để được tải lên kết cấu (2432x4320, max = 4096x4096)" Vì vậy, tôi đoán chiều cao 4320 không thể xử lý được.
GregM

1
Tất nhiên đây là một câu trả lời đúng và trả lời câu hỏi hoàn hảo! Tối ưu hóa chất lượng / kích thước hình ảnh cho hình ảnh lớn ... Chà, đó là một câu hỏi khác!
ichalos

@ichalos Có lẽ bạn đã tìm thấy những gì bạn đang tìm kiếm, nhưng điều này không trả lời câu hỏi ban đầu. Câu hỏi ban đầu là về kết xuất thủ công trên canvas .. thực sự, tôi không chắc lần đầu tiên ai đó cố gắng cắt ảnh sẽ được kết xuất thủ công trên canvas, nhưng này, thật tốt khi bạn tìm thấy giải pháp ở đây :)
milosmns

@milosmns Có lẽ bạn đúng. Có lẽ đây chỉ là cách người dùng cố gắng tiếp cận vấn đề cắt xén thủ công đến trung tâm. Tất cả phụ thuộc vào nhu cầu chính xác của người dùng ban đầu.
ichalos

9

Bạn có thể sử dụng mã sau đây có thể giải quyết vấn đề của bạn.

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

Phương pháp trên thực hiện postScalling hình ảnh trước khi cắt, để bạn có thể có kết quả tốt nhất với hình ảnh được cắt mà không gặp lỗi OOM.

Để biết thêm chi tiết, bạn có thể tham khảo blog này


1
E / AndroidR.78 (30010): Nguyên nhân bởi: java.lang.IllegalArgumentException: x + width phải là <= bitmap. Thong () và điều này vì 4 lần 100px
Stan

9

Ở đây một đoạn hoàn chỉnh hơn sẽ cắt ra trung tâm của [bitmap] có kích thước tùy ý và chia tỷ lệ kết quả cho [IMAGE_SIZE] mong muốn của bạn . Vì vậy, bạn sẽ luôn có được một hình vuông tỷ lệ [croppingBitmap] của trung tâm hình ảnh với kích thước cố định. lý tưởng cho hình thu nhỏ và như vậy.

Nó là sự kết hợp đầy đủ hơn của các giải pháp khác.

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

Có lẽ là giải pháp dễ nhất cho đến nay:

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

nhập khẩu:

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

3

Để sửa giải pháp @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);
            }

đây là một sửa chữa cho giải pháp WillSteel. Trong trường hợp này, tempBitmap chỉ là một bản sao của Bitmap gốc (không thay đổi) hoặc chính nó.
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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.