Android Reduce Size Of Camera Picture

Matt picture Matt · Jan 6, 2012 · Viewed 16.7k times · Source

UPDATE maybe changing the Bitmap size in the new Activity may fix the problem

String myRef = this.getIntent().getStringExtra("filepath");
    File imgFile = new  File(myRef);

    Log.e("BeatEmUp", myRef);
    if(imgFile.exists()){

        Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
        ImageView myImage = (ImageView) findViewById(R.id.imagepunch);
        myImage.setImageBitmap(myBitmap);

    }

Something like this maybe?

Bitmap scaled = Bitmap.createScaledBitmap(bit, 200, 200, true);

Or Maybe this is the best way below

So far I have my app which is taking a picture and then using an Intent to carry the picture over and display in a new Activity. Once I have done this I have some code which displays images over the top with the onClick. The problem is when the image is took it is being taken at a maximum size I think so my app is force closing.

In my logcat I am getting java.lang.OutOfMemoryError: bitmap size exceeds VM budget(Heap Size=7431KB, Allocated=2956KB, Bitmap Size=19764KB) which I think means that the image is too large.

I have tested by putting a smaller image in the code instead of the camera image that was took and that works which also leads me back to the problem that it is the size of the camera picture.

So I am trying to implement This From CommonsWare but with no luck so far. Looking through the code I think it searches for the smallest resouloution/size and then takes the camera using those settings am I right in thinking that and if so how can I implement that into my code?

public class AndroidCamera extends Activity implements SurfaceHolder.Callback{

Camera camera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
boolean previewing = false;
LayoutInflater controlInflater = null;

final int RESULT_SAVEIMAGE = 0;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);



    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

    getWindow().setFormat(PixelFormat.UNKNOWN);
    surfaceView = (SurfaceView)findViewById(R.id.camerapreview);
    surfaceHolder = surfaceView.getHolder();
    surfaceHolder.addCallback(this);
    surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    controlInflater = LayoutInflater.from(getBaseContext());
    View viewControl = controlInflater.inflate(R.layout.control, null);
    LayoutParams layoutParamsControl 
        = new LayoutParams(LayoutParams.FILL_PARENT, 
        LayoutParams.FILL_PARENT);
    this.addContentView(viewControl, layoutParamsControl);

    Button buttonTakePicture = (Button)findViewById(R.id.takepicture);
    buttonTakePicture.setOnClickListener(new Button.OnClickListener(){

        public void onClick(View arg0) {
            // TODO Auto-generated method stub
            camera.takePicture(myShutterCallback, 
                    myPictureCallback_RAW, myPictureCallback_JPG);



        }});

}

ShutterCallback myShutterCallback = new ShutterCallback(){

    public void onShutter() {
        // TODO Auto-generated method stub

    }};

PictureCallback myPictureCallback_RAW = new PictureCallback(){

    public void onPictureTaken(byte[] arg0, Camera arg1) {
        // TODO Auto-generated method stub

    }};

PictureCallback myPictureCallback_JPG = new PictureCallback(){

    public void onPictureTaken(byte[] arg0, Camera arg1) {
        // TODO Auto-generated method stub
        /*Bitmap bitmapPicture 
            = BitmapFactory.decodeByteArray(arg0, 0, arg0.length);  */
        int imageNum = 0;
        Intent imageIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        File imagesFolder = new File(Environment.getExternalStorageDirectory(), "Punch");
        imagesFolder.mkdirs(); // <----
        String fileName = "image_" + String.valueOf(imageNum) + ".jpg";
        File output = new File(imagesFolder, fileName);
        while (output.exists()){
            imageNum++;
            fileName = "image_" + String.valueOf(imageNum) + ".jpg";
            output = new File(imagesFolder, fileName);
        }

        Uri uriSavedImage = Uri.fromFile(output);
        imageIntent.putExtra(MediaStore.EXTRA_OUTPUT, uriSavedImage);


        OutputStream imageFileOS;
        try {
            imageFileOS = getContentResolver().openOutputStream(uriSavedImage);
            imageFileOS.write(arg0);
            imageFileOS.flush();
            imageFileOS.close();

            Toast.makeText(AndroidCamera.this, 
                    "Image saved", 
                    Toast.LENGTH_LONG).show();

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        Intent intent = new Intent(getBaseContext(), Punch.class);
        intent.putExtra("filepath",Uri.parse(output.getAbsolutePath()).toString());
        //just using a request code of zero
        int request=0;
        startActivityForResult(intent,request); 
    }};

public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    // TODO Auto-generated method stub
    if(previewing){
        camera.stopPreview();
        previewing = false;
    }

    if (camera != null){
        try {
            camera.setPreviewDisplay(surfaceHolder);
            camera.startPreview();
            previewing = true;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            camera.release();
            e.printStackTrace();
        }
    }
}





public void surfaceCreated(SurfaceHolder holder) {
    // TODO Auto-generated method stub

    camera = Camera.open();
    try {
           Camera.Parameters parameters = camera.getParameters();

           if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
              // This is an undocumented although widely known feature
              parameters.set("orientation", "portrait");
              // For Android 2.2 and above
              camera.setDisplayOrientation(90);
              // Uncomment for Android 2.0 and above
              parameters.setRotation(90);
           } else {
              // This is an undocumented although widely known feature
              parameters.set("orientation", "landscape");
              // For Android 2.2 and above
              camera.setDisplayOrientation(0);
              // Uncomment for Android 2.0 and above
              parameters.setRotation(0);
           }


          camera.setParameters(parameters);
          camera.setPreviewDisplay(holder);
      } catch (IOException exception) {
         camera.release();


       }
        camera.startPreview();

    }


public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO Auto-generated method stub
    if(previewing && camera != null) {
        if(camera!=null) {
            camera.stopPreview();
            camera.release();  
            camera = null;
        }
        previewing = false;
    }
}


}

Answer

CommonsWare picture CommonsWare · Jan 6, 2012

So far I have my app which is taking a picture and then using an Intent to carry the picture over and display in a new Activity.

In most cases, passing data between activities using Intent extras is a fine solution. Large bitmaps, though, cause problems that way due to memory consumption. This is one case where I would carefully use a static data member.

In my logcat I am getting java.lang.OutOfMemoryError: bitmap size exceeds VM budget(Heap Size=7431KB, Allocated=2956KB, Bitmap Size=19764KB) which I think means that the image is too large.

It means that you do not have enough memory for whatever it is you are trying to do.

Looking through the code I think it searches for the smallest resouloution/size and then takes the camera using those settings am I right in thinking that

Yes.

if so how can I implement that into my code?

Copy and paste usually works. :-)

To tell the camera what size picture to take, use setPictureSize() on Camera.Parameters. However, you have to choose a size it supports, and not all devices will support arbitrary sizes. Calling getSupportedPictureSizes() will tell you which sizes are supported. It is up to you to determine which of those sizes to use. In the example I linked to from your other question, I iterate over those sizes and find the smallest one in terms of area.

That being said, if the only issue with image size is passing it from activity to activity, I would go the static data member route first. Just be sure to null out that static data member when you no longer need the image.

Something like this maybe?

Again, that depends on what your objective is. You seem to be flailing around looking for solutions, when you have only articulated one problem (and, even there, you have not told us where you are getting the out of memory error).

If your goal is to take a full-resolution picture, save it in a file, and then hold in memory a thumbnail, createScaledBitmap() is a fine solution.

If your goal is to take a thumbnail-ish picture in the first place (i.e., you do not need or want a full-resolution image), use setPictureSize().

If your goal is to use a full-resolution picture throughout, carefully use a static data member to eliminate any unnecessary copies of the Bitmap and see if that is sufficient. It might not be, depending on what you are trying to do with the image.