비트 맵의 ​​안드로이드 자르기 센터


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
실제 대상 비트 맵이 정사각형이되도록 답변을 편집했습니다.
Joram van den Boezem 2016 년

1
@ 루미스 : 왜 개정 3을 롤백 했습니까? 올바른 것으로 보입니다. 현재 버전은 올바른 시작점을 생성하지만 너무 긴 쪽을 포함합니다. 예를 들어 100x1000이미지가 주어지면 이미지가 다시 100x550나타납니다.
Guvante

감사합니다, 당신 말이 맞습니다, 형식은 Bitmap.createBitmap (source, x, y, width, height)
Lumis

11
내장 ThumbnailUtils.extractThumbnail () 메서드 사용에 대한 내 답변을 참조하십시오. 왜 바퀴를 재발 명합니까 ??? stackoverflow.com/a/17733530/1103584
DiscDev

1
이 솔루션은 캔버스를 만든 다음 드로어 블을 그리는 것보다 짧습니다. 또한 ThumbnailUtils 솔루션보다 처리량이 적습니다 (샘플 크기를 계산하여 스케일링 방법을 파악).
yincrash

319

위의 답변 중 대부분 이이 작업을 수행하는 방법을 제공하지만 이미이 작업을 수행하는 기본 방법이 있으며 한 줄의 코드 ( 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 너비, int 높이)

API 레벨 8에 추가됨 원하는 크기의 중앙 비트 맵을 만듭니다.

매개 변수 소스 원래 비트 맵 소스 너비 대상 너비 높이 대상 높이

허용되는 답변을 사용할 때 때때로 메모리 부족 오류가 발생했으며 ThumbnailUtils를 사용하면 이러한 문제가 해결되었습니다. 또한 이것은 훨씬 깨끗하고 재사용이 가능합니다.


6
+1 위의 원래 게시물에 대한 대안을 제공하기 위해이 코드를 개선하고 400px를 사용하는 대신 가장 짧은 bmp 크기를 전달해야한다고 생각합니다. 그러나 이것을 주목 해 주셔서 감사합니다. 매우 유용한 기능인 것 같습니다. 동정 나는 전에 그것을 보지 못했다 ...
Lumis


4
@DiscDev-문자 그대로이 전체 사이트에서 가장 유용한 답변 중 하나 여야합니다. 진심으로. 안드로이드 질문에는 이상합니다. 간단한 대답을 찾기 전에 종종 2 시간 동안 검색 할 수 있습니다. 충분히 감사하는 방법을 모른다. 도중에 현상금!
Fattie

2
오래된 비트 맵을 재활용하기 위해 약간 다른 기능을 사용할 수도 있습니다 : = ThumbnailUtils.extractThumbnail (비트 맵, 너비, 높이, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
안드로이드 개발자

1
이것은 안드로이드 질문에 대해 지금까지 본 가장 강력한 답변입니다. Android의 비트 맵에서 크기 조정 / 자르기 / 축소 / 크기 조정 등의 20 가지 솔루션을 보았습니다. 모든 답변이 다릅니다. 그리고 이것은 하나의 라인을 취하고 예상대로 정확하게 작동합니다. 감사합니다.
Alex Sorokoletov

12

에서이 작업을 고려 했습니까 layout.xml? 당신은 당신을 위해 설정할 수 ScaleType 에 와있는 이미지의 크기를 설정 내부 .ImageViewandroid:scaleType="centerCrop"ImageViewlayout.xml


다음 OpenGLRenderer 오류로이 아이디어를 시도했습니다. "비트 맵이 너무 커서 텍스처 (2432x4320, max = 4096x4096)에 업로드 할 수 없습니다."따라서 4320 높이를 처리 할 수 ​​없습니다.
GregM

1
물론 이것은 정답이며 질문에 완벽하게 대답합니다! 큰 이미지의 이미지 품질 / 크기 최적화 중 ... 다른 질문입니다!
ichalos April

@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 () 여야하며 이는 100px의 4 배이므로
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은 원본 (변경되지 않은) 비트 맵 또는 그 자체의 복사본 일뿐입니다.
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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.