简体   繁体   中英

Image crop and resize in Android

I followed the instructions below to crop an image.

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

The height and width of the final cropped bitmap image are both larger than those of the screen.

During the resize and crop process, out of memory error was thrown and the app is forced to quit.

The error log:

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)

Does anyone know how to solve the problem ?

Thanks.

======

Update: I solved the problem.

You can used crop image using following code that can solve your problem.

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

Above method do postScalling of image before cropping, so you can get best result with cropped image without getting OOM error.

For more detail you can refer this blog

My co-worker just hipped me to this Android API... see ThumbnailUtils.

It does resizing and cropping for you.

http://developer.android.com/reference/android/media/ThumbnailUtils.html#extractThumbnail(android.graphics.Bitmap , int, int)

If your code varies from the example, you will have to post it to get precise help. Otherwise, based only on the log - here is an answer:

In the example you are using, the developer is cropping an image in his app's resources folder (which could be relatively small to start) to a 300x300 bitmap image. First, try cropping a smaller size image in your own app, to a smaller output size, to see if there is a problem with the code, or if you are using an image that is too large for your code or device.

Since you are saying the final image you are cropping is larger that the screen, that is probably the issue, and you are encountering a basic challenge of using bitmaps in Android. Bitmap file size is a function of pixel width times height - they get bigger fast.

You can solve by googling other parts of your log, like "bitmap size exceeds VM budget" and you will find several threads on stackoverflow that will help, like this one.

Strange out of memory issue while loading an image to a Bitmap object

You may solve it by using bitmap options and inSampleSize, and other techniques.

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

看看here类似的讨论,他们似乎有相同的byte external allocation too large for this process错误byte external allocation too large for this process

I further verified the following instructions.

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

I found that the codes are not good enough and some of them are redundant.

To crop a big bitmap image, there is no need to use matrix to do the task.

Just use canvas.drawBitmap method can crop the big image !

Also no need to touch the BitmapFactory.Options.

Now I simply crop the image and let the imageview resize it. No more out-of-memory error. Bingo !

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

If I'm not mistaken, in

class Test extends Activity ....

on line 57, you have

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

If so, the referenced image is so big that when Android tries to decode it into a bitmap, it cosumes all the free VM heap and throws theerror. You cant decode big bitmaps with

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

I copied the code from the link that user699618 recommended, i ve used it before and it solves the problem).

After that you can just use CENTER_CROP or whatever you need on ImageView.setScaleType() .

You can find the Scale Type options in here and setScaleType details in hete .

Hope this helps.

i'd also recommend not to have such heavy pictures in resources. Make them smaller before saving them in the resorce forder.

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

i hope to be usefull

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM