Scale bitmap with inDither and inPreferQualityOverSpeed

The exercise "Load scaled bitmap" demonstrate a simple and standard method to scale bitmap. Additionally, we can set inDither and inPreferQualityOverSpeed options to improve quality of the scaled bitmap.
  • inDither:
    If set, the decoder will attempt to dither the decoded image.
    Dithering is a technique used in computer graphics to create the illusion of color depth in images with a limited color palette (color quantization). ~ reference: Wikipedia, Dither in Digital photography and image processing.
  • inPreferQualityOverSpeed (Added in API level 10) : 
    If set, the decoder will try to decode the reconstructed image to a higher quality even at the expense of the decoding speed. Currently the field only affects JPEG decode, in the case of which a more accurate, but slightly slower, IDCT method will be used instead.

In this exercise, we can set options of inDither and inPreferQualityOverSpeed in scaling bitmap. And also display the INACCURACY processing duration of scaling bitmap in millisecond, for reference only.

Scale bitmap with inDither and inPreferQualityOverSpeed

package com.example.androidscalebitmap;

import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Date;

import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.ToggleButton;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class MainActivity extends Activity {

final int RQS_IMAGE1 = 1;

Button btnLoadImage;
ToggleButton optBtnInDither, optBtnInPreferQualityOverSpeed;
TextView textInfo;
ImageView imageResult;

Uri source1;
Date startTime;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnLoadImage = (Button) findViewById(R.id.loadimage);
optBtnInDither = (ToggleButton) findViewById(R.id.optInDither);
optBtnInPreferQualityOverSpeed = (ToggleButton) findViewById(R.id.optInPreferQualityOverSpeed);
textInfo = (TextView) findViewById(R.id.info);
imageResult = (ImageView) findViewById(R.id.result);

btnLoadImage.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);
}
});

optBtnInDither.setOnCheckedChangeListener(
optBtnOnCheckedChangeListener);
optBtnInPreferQualityOverSpeed.setOnCheckedChangeListener(
optBtnOnCheckedChangeListener);
}

OnCheckedChangeListener optBtnOnCheckedChangeListener =
new OnCheckedChangeListener(){

@Override
public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
doScale(source1);
}};

@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();
optBtnInDither.setChecked(false);
optBtnInPreferQualityOverSpeed.setChecked(false);
doScale(source1);
break;
}
}
}

private void doScale(Uri src){

try {
Bitmap bm = loadScaledBitmap(source1);
imageResult.setImageBitmap(bm);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

private Bitmap loadScaledBitmap(Uri src) throws FileNotFoundException {

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

Bitmap bm = null;

if (src != 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;

//set options according to RadioButton setting
options.inDither = optBtnInDither.isChecked();
//inPreferQualityOverSpeed require API Level 10
options.inPreferQualityOverSpeed = optBtnInPreferQualityOverSpeed.isChecked();

InputStream inputStream = getContentResolver().openInputStream(src);
startTime = new Date();

bm = BitmapFactory.decodeStream(inputStream, null, options);

//INACCURACY processing duration of scaling bitmap in millisecond
long duration = new Date().getTime() - startTime.getTime();
textInfo.setText("duration in ms: " + duration);
}

return bm;
}

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

return inSampleSize;
}
}


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://arteluzevida.blogspot.com/"
android:textStyle="bold" />

<Button
android:id="@+id/loadimage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Load Image 1" />
<ToggleButton
android:id="@+id/optInDither"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="false"
android:textOn="inDither ON"
android:textOff="inDither OFF"/>
<ToggleButton
android:id="@+id/optInPreferQualityOverSpeed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="false"
android:textOn="inPreferQualityOverSpeed ON"
android:textOff="inPreferQualityOverSpeed OFF"/>
<TextView
android:id="@+id/info"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<ImageView
android:id="@+id/result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:background="@android:color/background_dark"
android:scaleType="center" />

</LinearLayout>


download filesDownload the files.


download filesDownload and try the APK.



more: Something about processing images in Android