Android Crop Center的位图


149

我有正方形或矩形的位图。我站在最短的一边,做这样的事情:

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

问题是它会裁剪原始位图的左上角,有人有代码来裁剪位图的中心吗?

Answers:


353

在此处输入图片说明

这可以通过以下方式实现: Bitmap.createBitmap(source,x,y,width,height)

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 2013年

1
@Lumis:为什么要回滚修订版3?它似乎是正确的。您当前的版本创建了正确的起点,但随后包括了过长边的其余部分。例如,给定100x1000图像,您将获得100x550图像。
Guvante

谢谢,您是对的,格式为Bitmap.createBitmap(source,x,y,width,height)
Lumis

11
请参阅有关使用内置ThumbnailUtils.extractThumbnail()方法的答案。为什么要重新发明轮子??? stackoverflow.com/a/17733530/1103584
DiscDev

1
该解决方案比创建画布然后在其上绘制可绘制对象要短。它也比ThumbnailUtils解决方案(后者进行样本量计算以找出如何缩放)的处理要少。
yincrash 2014年

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(位图源,整数宽度,整数高度)

API级别8中已添加创建所需大小的居中位图。

参数源原始位图源宽度目标宽度目标高度目标高度

使用接受的答案时,有时会出现内存不足错误,并且使用ThumbnailUtils为我解决了这些问题。另外,这更干净更可重用。


6
+1我认为您必须对此代码进行改进,而不是使用400px,而是传递最短的bmp大小,以便为上面的原始帖子提供替代方法。但是感谢您引起我们的注意,它似乎是一个非常有用的功能。可惜我以前没看过……
Lumis

是的,我只是硬编码400以给出一个具体示例...细节由实现者决定:)
DiscDev

4
@DiscDev-从字面上看,这必须是整个网站上最有用的答案之一。说真的 Android问题很奇怪-您通常可以搜索两个小时才能找到简单的明显答案。不知道该如何感谢你。赏金途中!
Fattie

2
您甚至可以使用一些不同的功能来回收旧的位图:= ThumbnailUtils.extractThumbnail(bitmap,width,height,ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
android开发者

1
这是迄今为止我对android问题最有力的回答。我已经看到20种不同的解决方案,如何在Android上的位图上进行缩放/裁剪/缩小/调整大小等操作。所有答案都不同。而这只需要1条线,并且完全按预期工作。谢谢。
Alex Sorokoletov 2014年

12

您是否考虑过从这样做layout.xml?你可以设置你ImageViewScaleTypeandroid:scaleType="centerCrop",并在设定的图像的尺寸ImageViewlayout.xml


我尝试了以下OpenGLRenderer错误,尝试了这种方法:“位图太大,无法上载到纹理中(2432x4320,max = 4096x4096)”因此,我猜测无法处理4320高度。
GregM 2014年

1
当然,这是一个正确的答案,并且可以完美地回答问题!为大图像优化图像质量/尺寸...好吧,这是一个不同的问题!
ichalos 2015年

@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只是原始(未更改)位图或其本身的副本。
Yman 2013年

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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.