Android中的图像裁剪和调整大小

4
我按照下面的指示来裁剪一张图片: http://coderzheaven.com/index.php/2011/03/crop-an-image-in-android/ 最终裁剪出的位图的高度和宽度都比屏幕大。在调整大小和裁剪的过程中,会抛出内存溢出错误并强制退出应用程序。
错误日志:
04-09 11:37:28.658: ERROR/dalvikvm-heap(4003): 435176-byte external allocation too large for this process.
04-09 11:37:28.658: ERROR/GraphicsJNI(4003): VM won't let us allocate 435176 bytes    
04-09 11:37:28.668: WARN/dalvikvm(4003): threadid=1: thread exiting with uncaught exception (group=0x4001d800)    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): FATAL EXCEPTION: main    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): java.lang.OutOfMemoryError: bitmap size exceeds VM budget    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at android.graphics.Bitmap.nativeCreate(Native Method)    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at android.graphics.Bitmap.createBitmap(Bitmap.java:468)    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at android.graphics.Bitmap.createBitmap(Bitmap.java:435)    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at com.test.Test.onCreate(Test.java:57)    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)   
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)  
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at android.app.ActivityThread.access$2300(ActivityThread.java:125)    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)   
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at android.os.Handler.dispatchMessage(Handler.java:99)   
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at android.os.Looper.loop(Looper.java:123)    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at android.app.ActivityThread.main(ActivityThread.java:4627)    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at java.lang.reflect.Method.invokeNative(Native Method)    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at java.lang.reflect.Method.invoke(Method.java:521)    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)    
04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at dalvik.system.NativeStart.main(Native Method)

有人知道如何解决这个问题吗?

谢谢。

======

更新:我已经解决了这个问题。


发布错误,展示一些代码!如果我们不知道问题是什么,我们怎么能帮助你!!! - user432209
错误是应用程序强制退出。 - user403015
运行“adb logcat AndroidRuntime:* *:S”以获取崩溃日志。将其与您的代码一起发布,我们可以提供帮助。 - Chase
8个回答

15
你可以使用以下代码来裁剪图像,这可以解决你的问题。
Matrix matrix = new Matrix();
matrix.postScale(0.5f, 0.5f);
Bitmap croppedBitmap = Bitmap.createBitmap(bitmapOriginal, 100, 100,100, 100, matrix, true);

上述方法在裁剪之前对图像进行了后缩放,因此您可以在获取裁剪后的最佳结果时避免OOM错误。

更多详细信息,请参考此博客


1
最佳答案,感谢 @Hitesh。请注意,在某些情况下,这是一种非常简单和可靠的解决方案:https://dev59.com/Cmw05IYBdhLWcg3w_Guw#17733530 - Fattie

10

找到了! - Gyome

2
如果你的代码与示例不同,你需要发布它以获得精确的帮助。否则,仅基于日志,这是一个答案:
在你使用的示例中,开发人员正在将应用程序资源文件夹中的图像(可能相对较小)裁剪为300x300位图图像。首先,请尝试在您自己的应用程序中裁剪较小的图像,以获得较小的输出大小,以查看是否存在代码问题,或者您是否在使用过大的图像。
由于你说最终要裁剪的图片比屏幕还大,这很可能是问题所在,你遇到了在Android中使用位图的基本挑战。位图文件大小是像素宽度乘以高度的函数-它们增长得非常快。
你可以通过谷歌搜索日志的其他部分,例如“bitmap size exceeds VM budget”,并且你会发现几个stackoverflow线程将帮助你解决问题,例如这个。 Strange out of memory issue while loading an image to a Bitmap object 你可以通过使用位图选项和inSampleSize等技术来解决这个问题。

1

04-09 11:37:28.708: ERROR/AndroidRuntime(4003): at com.test.Test.onCreate(Test.java:57)

如果我没记错,在

class Test extends Activity ....

在第57行,你有

Bitmap bitmapOrg = BitmapFactory.decodeResource(getResources(),R.drawable.image);

如果是这样,所引用的图像太大了,当Android尝试将其解码为位图时,它会消耗所有可用的VM堆并抛出错误。您无法使用此方法解码大型位图。
private Bitmap decodeFile(){
    try {
        //Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(getResources(),R.drawable.image,o);

        //The new size we want to scale to
        final int REQUIRED_SIZE=100;

        //Find the correct scale value. It should be the power of 2.
        int width_tmp=o.outWidth, height_tmp=o.outHeight;
        int scale=1;
        while(true){
            if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
                break;
            width_tmp/=2;
            height_tmp/=2;
            scale*=2;
        }

        //Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize=scale;
        return BitmapFactory.decodeResource(getResources(),R.drawable.image, o2);
    } catch (FileNotFoundException e) {}
    return null;
}

我从用户699618推荐的链接中复制了代码,之前我也用过它并解决了问题。

之后你可以在ImageView.setScaleType()上使用CENTER_CROP或其他你需要的选项。

你可以在这里找到比例类型选项,并在这里找到setScaleType的详细信息。

希望这能帮到你。

我还建议在资源中不要放置太大的图片。在将它们保存到资源文件夹之前,请将它们缩小。


1
//solution for bit map resizing  
 Bitmap targetBitmap = Bitmap.createBitmap(targetWidth, targetHeight,Bitmap.Config.ARGB_8888);

 RectF rectf = new RectF(0, 0, 800, 400);

 Canvas canvas = new Canvas(targetBitmap);
 Path path = new Path();

 path.addRect(rectf, Path.Direction.CW);
 canvas.clipPath(path);
 int xaxis=bm.getWidth();
 int yaxis=bm.getHeight();
 canvas.drawBitmap( bm, new Rect(0, 0, bm.getWidth(), bm.getHeight()),
                      new Rect(0, 0, targetWidth, targetHeight), paint);
 Matrix matrix = new Matrix();
 matrix.postScale(1f, 1f);
 resizedBitmap = Bitmap.createBitmap(targetBitmap, 0, 0, width, height, matrix, true);

 BitmapDrawable bd = new BitmapDrawable(resizedBitmap);

1
    //get screen resolution;
    WindowManager display = getWindowManager();
    Point size = new Point();
    display.getDefaultDisplay().getSize(size);      
    int width = size.x;
    int height = size.y;
    // scale the bitmap according to the screen resolution  .
    Bitmap bMap = BitmapFactory.decodeResource(getResources(), .drawable.ima1);
    bMap = Bitmap.createScaledBitmap(bMap, width, height, true);
    // then crop under value of the screen size and bitmap! 
    bMap = Bitmap.createBitmap(bMap, 0, 0, width/2, height);
    Drawable drawa = new BitmapDrawable(getResources(),bMap);

我希望有用。

1

看看类似的讨论这里,他们似乎遇到了相同的byte external allocation too large for this process错误。


1
我进一步验证了以下指示。

http://coderzheaven.com/index.php/2011/03/crop-an-image-in-android/

我发现这些代码不够好,有些是冗余的。

裁剪大位图图片时,没有必要使用矩阵来完成任务。

只需使用canvas.drawBitmap方法即可裁剪大图片!

而且不需要修改BitmapFactory.Options。

现在我只需简单地裁剪图片并让ImageView调整大小。再也没有内存溢出错误了。太棒了!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接