1

I am trying to compress a bitmap that is picked from gallery or captured by camera before sending to server. Now I do it following these steps:

1) get the path of the image.

2) get bitmap from this path.

3) check initial width and height of bitmap, and compare them to the max width and height and then use a ratio factor to adjust width and height.

4) check and rotate bitmap correctly using exif.

5) finaly lower the quality to get a final compressed bitmap.

The code:

    private static final float max_width = 1280.0f;
    private static final float max_height = 1280.0f;
    private static final float max_ratio = max_width/max_height; 

    private void CompressImage(String path , Bitmap bitmap_original){



     //get width and height of original bitmap

     int original_width = bitmap_original.getWidth();
     int original_height = bitmap_origianl.getHeight();

     float original_ratio = (float)width/(float)height;

     if(original_height > max_height || original_width > max_width){
      //adjust bitmap dimensions

       int width = 0;
       int height = 0;

       if(original_ratio<max_ratio){
       width= (int)((max_height/original_height)*original_width);
       height=(int) max_height;  

       }else if(original_ratio>max_ratio){
        height= (int)((max_width/original_width)*original_height);
        width= (int)max_width;
       }else{
         height = max_height; 
         width = max_width;  
       }

       //adjust the bitmap 
        Bitmap adjusted_bitmap = Bitmap.createScaledBitmap(bitmap_original,width,height,false);


       //check rotation
       Matrix matrix = new Matrix();  
       try{
       ExifInterface exif = new ExifInterface(path);
       int original_orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION , ExifInterface.ORIENTATION_UNDEFINED);

         if(original_orientation == ExifInterface.ORIENTATION_ROTATE_90){

          matrix.setRotate(90);

         }else if(original_orientation == ExifInterface.ORIENTATION_180){

          matrix.setRotate(180);

         }else if(original_orientation == ExifInterface.ORIENTATION_270){

          matrix.setRotate(270);
         }

         Bitmap rotated_adjusted_bitmap = Bitmap.createBitmap(adjusted_bitmap , 0 , 0 , adjusted_bitmap.getWidth(), adjusted_bitmap.getHeight(),matrix,true);


         //lower the quality

          ByteArrayOutputStream out = new ByteArrayOutputStream();
          adjusted_rotated_bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out);
          Bitmap adjusted_rotated_lowquality_bitmap = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));  

       }catch(IOException e){


        }


      }else{
      //keep bitmap as is
      Bitmap adjusted_bitmap = bitmap_original;
      }



     }

The problem

Everything above works fine, but the problem is that in some cases the app will crash with an Out Of Memory exception.

Is there something wrong with my code?

I don't know a lot concerning bitmaps and compression.

Thanks for your help.

  • Possible duplicate of https://stackoverflow.com/questions/477572/strange-out-of-memory-issue-while-loading-an-image-to-a-bitmap-object?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa – Maddy Blacklisted May 04 '18 at 19:19
  • Is it crashes while displaying the image? Or you sending the image to server without displaying? – Md Sufi Khan May 04 '18 at 19:38
  • @MdSufiKhan just the compressing part is sometimes blocking UI with out of memory error. –  May 04 '18 at 19:47
  • 1
    @MdSufiKhan the displaying is handled by glide, but I dont know why the compressing is sometimes failing... maybe its because the bitmap is high res. –  May 04 '18 at 19:48
  • That's for sure the bitmap is in high res. Did you try to compress in separate Thread? – Md Sufi Khan May 04 '18 at 19:51
  • @MdSufiKhan yes it is handled on background thread (async) task....but I just want to ask you is there something wrong with the above code. How to make sure I dont get out of memory for any kind of image? –  May 04 '18 at 19:53
  • You load the bitmap before compressing. I think this is the root cause of Out of memory error. You can have a look into this https://stackoverflow.com/a/31612736/2728085 – Md Sufi Khan May 04 '18 at 20:01
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/170396/discussion-between-md-sufi-khan-and-database). – Md Sufi Khan May 04 '18 at 20:03
  • @MdSufiKhan what do you mean to load bitmap before compressing? Otherwise what is the correct way? Thanks. –  May 04 '18 at 20:03

2 Answers2

0

Bitmap usually takes time and sometimes blocking I/O. So it's not good practice to call imageWithText on the UI thread.

Glide is designed to be flexible and this problem demonstrates that trait extremely well.

"Glide way" below, which I highly recommend.

ByteArrayOutputStream stream = new ByteArrayOutputStream(); 
yourBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); 
Glide.with(this).load(stream.toByteArray())
     .asBitmap() .error(R.drawable.ic_thumb_placeholder) 
     .transform(new CircleTransform(this)).into(imageview);

For further details check the link below

Is there a way to load image as bitmap to Glide

Fazal Hussain
  • 1,129
  • 12
  • 28
0

You can get the image uri when you select image from gallery as:

Uri myUri = data.getData();

Before sending the image to server you need to convert that uri to byteArray[]

as below:

    Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(),myUri);

   ByteArrayOutputStream baos = new ByteArrayOutputStream();

   bitmap.compress(Bitmap.CompressFormat.PNG,0,baos);
                        byteArray[] bArray = baos.toByteArray();
    If you want you can get the name of image as:
     try (Cursor returnCursor = getContentResolver().query(myUri, null, null, null, null)) {
                        int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                        int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
                        returnCursor.moveToFirst();
                           String FileName = returnCursor.getString(nameIndex);}
PRATEEK BHARDWAJ
  • 2,364
  • 2
  • 21
  • 35
Deepya
  • 107
  • 1
  • 4