Tuesday, August 27, 2013

Fine tune scaled down bitmap to exact size

Last post genarate a scaled down bitmaps, approximate but not exact size. In order to fine tune bitmap to exact size, we can re-create another bitmap from this scaled bitmap using Bitmap.createScaledBitmap() method with expected width and height.

Scale down bitmap to exact size

Modify MainActivity.java from Last post to fine tune bitmap after scaled.
package com.test.androidimageprocessing;

import java.io.FileNotFoundException;

import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.example.androidimageprocessing.R;

public class MainActivity extends Activity {

 Button btnLoadImage1, btnLoadImage2;
 TextView textSource1, textSource2;
 Button btnProcessing;
 ImageView imageResult;
 Spinner spinnerMode;

 final int RQS_IMAGE1 = 1;
 final int RQS_IMAGE2 = 2;

 Uri source1, source2;

 String[] arrayModeName = { "ADD", "CLEAR", "DARKEN", "DST", "DST_ATOP",
   "DST_IN", "DST_OUT", "DST_OVER", "LIGHTEN", "MULTIPLY", "OVERLAY",
   "SCREEN", "SRC", "SRC_ATOP", "SRC_IN", "SRC_OUT", "SRC_OVER", "XOR" };

 /*
  * To use Mode.ADD and Mode.OVERLAY, android:minSdkVersion have to be set
  * "11" or higher.
  */
 PorterDuff.Mode[] arrayMode = { Mode.ADD, Mode.CLEAR, Mode.DARKEN,
   Mode.DST, Mode.DST_ATOP, Mode.DST_IN, Mode.DST_OUT, Mode.DST_OVER,
   Mode.LIGHTEN, Mode.MULTIPLY, Mode.OVERLAY, Mode.SCREEN, Mode.SRC,
   Mode.SRC_ATOP, Mode.SRC_IN, Mode.SRC_OUT, Mode.SRC_OVER, Mode.XOR };

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  setContentView(R.layout.activity_main);
  btnLoadImage1 = (Button) findViewById(R.id.loadimage1);
  btnLoadImage2 = (Button) findViewById(R.id.loadimage2);
  textSource1 = (TextView) findViewById(R.id.sourceuri1);
  textSource2 = (TextView) findViewById(R.id.sourceuri2);
  btnProcessing = (Button) findViewById(R.id.processing);
  imageResult = (ImageView) findViewById(R.id.result);

  spinnerMode = (Spinner) findViewById(R.id.mode);
  ArrayAdapter<String> adapter = new ArrayAdapter<String>(
    MainActivity.this, android.R.layout.simple_spinner_item,
    arrayModeName);
  adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
  spinnerMode.setAdapter(adapter);

  btnLoadImage1.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View arg0) {
    Intent intent = new Intent(
      Intent.ACTION_PICK,
      android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(intent, RQS_IMAGE1);
   }
  });

  btnLoadImage2.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View arg0) {
    Intent intent = new Intent(
      Intent.ACTION_PICK,
      android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(intent, RQS_IMAGE2);
   }
  });

  btnProcessing.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {

    if (source1 != null && source2 != null) {
     Bitmap processedBitmap = ProcessingBitmap();
     if (processedBitmap != null) {
      imageResult.setImageBitmap(processedBitmap);
      Toast.makeText(getApplicationContext(), "Done",
        Toast.LENGTH_LONG).show();
     } else {
      Toast.makeText(getApplicationContext(),
        "Something wrong in processing!",
        Toast.LENGTH_LONG).show();
     }
    } else {
     Toast.makeText(getApplicationContext(),
       "Select both image!", Toast.LENGTH_LONG).show();
    }

   }
  });
 }

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (resultCode == RESULT_OK) {
   switch (requestCode) {
   case RQS_IMAGE1:
    source1 = data.getData();
    textSource1.setText(source1.toString());
    break;
   case RQS_IMAGE2:
    source2 = data.getData();
    textSource2.setText(source2.toString());
    break;
   }
  }
 }

 private Bitmap ProcessingBitmap() {
  Bitmap bm1 = null;
  Bitmap bm2 = null;
  Bitmap newBitmap = null;

  try {
   /*
    * bm1 = BitmapFactory.decodeStream(getContentResolver()
    * .openInputStream(source1)); 
    * bm2 = BitmapFactory.decodeStream(getContentResolver()
    * .openInputStream(source2));
    */

   bm1 = loadScaledBitmap(source1);
   Toast.makeText(getApplicationContext(),
     "bm1: " + bm1.getWidth() + " x " + bm1.getHeight(),
     Toast.LENGTH_LONG).show();

   bm2 = loadScaledBitmap(source2);
   Toast.makeText(getApplicationContext(),
     "bm2: " + bm2.getWidth() + " x " + bm2.getHeight(),
     Toast.LENGTH_LONG).show();

   int w;
   if (bm1.getWidth() >= bm2.getWidth()) {
    w = bm1.getWidth();
   } else {
    w = bm2.getWidth();
   }

   int h;
   if (bm1.getHeight() >= bm2.getHeight()) {
    h = bm1.getHeight();
   } else {
    h = bm2.getHeight();
   }

   Config config = bm1.getConfig();
   if (config == null) {
    config = Bitmap.Config.ARGB_8888;
   }

   newBitmap = Bitmap.createBitmap(w, h, config);
   Canvas newCanvas = new Canvas(newBitmap);

   newCanvas.drawBitmap(bm1, 0, 0, null);

   Paint paint = new Paint();

   int selectedPos = spinnerMode.getSelectedItemPosition();
   PorterDuff.Mode selectedMode = arrayMode[selectedPos];

   paint.setXfermode(new PorterDuffXfermode(selectedMode));
   newCanvas.drawBitmap(bm2, 0, 0, paint);

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

  return newBitmap;
 }

 private Bitmap loadScaledBitmap(Uri src) throws FileNotFoundException {

  // required max width/height
  final int REQ_WIDTH = 1024;
  final int REQ_HEIGHT = 1024;

  Bitmap bm = null;

  // First decode with inJustDecodeBounds=true to check dimensions
  final BitmapFactory.Options options = new BitmapFactory.Options();
  options.inJustDecodeBounds = true;
  BitmapFactory.decodeStream(getContentResolver().openInputStream(src),
    null, options);

  // Calculate inSampleSize
  options.inSampleSize = calculateInSampleSize(options, REQ_WIDTH,
    REQ_HEIGHT);

  // Decode bitmap with inSampleSize set
  options.inJustDecodeBounds = false;
  bm = BitmapFactory.decodeStream(
    getContentResolver().openInputStream(src), null, options);
  
  /*
   * Up to here, bm will be scaled down, but not exactly expected size!
   * 
   * To fine tune the size, re-create another bitmap from this scaled bitmap
   * using Bitmap.createScaledBitmap() method with expected width and height.
   */
  final int LONGEST_LENGTH = 1024;
  int dstWidth, dstHeight;
  
  if(options.outWidth >= options.outHeight){
   //Landscape orientation
   dstWidth = LONGEST_LENGTH;
   dstHeight = LONGEST_LENGTH * options.outHeight/options.outWidth;
  }else{
   //portrait orientation
   dstHeight = LONGEST_LENGTH;
   dstWidth = LONGEST_LENGTH * options.outWidth/options.outHeight;
  }
  
  //To save memory, re-use bm
  bm = Bitmap.createScaledBitmap(bm, dstWidth, dstHeight, false);

  return bm;
 }

 private int calculateInSampleSize(BitmapFactory.Options options,
   int reqWidth, int reqHeight) {
  // Raw height and width of image
  final int height = options.outHeight;
  final int width = options.outWidth;
  int inSampleSize = 1;

  if (height > reqHeight || width > reqWidth) {

   // Calculate ratios of height and width to requested height and
   // width
   final int heightRatio = Math.round((float) height
     / (float) reqHeight);
   final int widthRatio = Math.round((float) width / (float) reqWidth);

   // Choose the smallest ratio as inSampleSize value, this will
   // guarantee
   // a final image with both dimensions larger than or equal to the
   // requested height and width.
   inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
  }

  Toast.makeText(getApplicationContext(),
    "inSampleSize: " + inSampleSize, Toast.LENGTH_LONG).show();

  return inSampleSize;
 }

}


download filesDownload the files.



more: Something about processing images in Android

No comments: