How to Bitmap scalling and cropping from center?
public class ScalingUtilities {
/**
* Utility function for decoding an image resource. The decoded bitmap will
* be optimized for further scaling to the requested destination dimensions
* and scaling logic.
*
* @param res
* The resources object containing the image data
* @param resId
* The resource id of the image data
* @param dstWidth
* Width of destination area
* @param dstHeight
* Height of destination area
* @param scalingLogic
* Logic to use to avoid image stretching
* @return Decoded bitmap
*/
public static Bitmap decodeResource(Resources res, int resId, int dstWidth,
int dstHeight, ScalingLogic scalingLogic) {
Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inJustDecodeBounds = false;
options.inSampleSize = calculateSampleSize(options.outWidth,
options.outHeight, dstWidth, dstHeight, scalingLogic);
Bitmap unscaledBitmap = BitmapFactory.decodeResource(res, resId,
options);
return unscaledBitmap;
}
/**
* Utility function for creating a scaled version of an existing bitmap
*
* @param unscaledBitmap
* Bitmap to scale
* @param dstWidth
* Wanted width of destination bitmap
* @param dstHeight
* Wanted height of destination bitmap
* @param scalingLogic
* Logic to use to avoid image stretching
* @return New scaled bitmap object
*/
public static Bitmap createScaledBitmap(Bitmap unscaledBitmap,
int dstWidth, int dstHeight, ScalingLogic scalingLogic) {
Rect srcRect = calculateSrcRect(unscaledBitmap.getWidth(),
unscaledBitmap.getHeight(), dstWidth, dstHeight, scalingLogic);
Rect dstRect = calculateDstRect(unscaledBitmap.getWidth(),
unscaledBitmap.getHeight(), dstWidth, dstHeight, scalingLogic);
Bitmap scaledBitmap = Bitmap.createBitmap(dstRect.width(),
dstRect.height(), Config.ARGB_8888);
Canvas canvas = new Canvas(scaledBitmap);
canvas.drawBitmap(unscaledBitmap, srcRect, dstRect, new Paint(
Paint.FILTER_BITMAP_FLAG));
return scaledBitmap;
}
/**
* ScalingLogic defines how scaling should be carried out if source and
* destination image has different aspect ratio.
*
* CROP: Scales the image the minimum amount while making sure that at least
* one of the two dimensions fit inside the requested destination area.
* Parts of the source image will be cropped to realize this.
*
* FIT: Scales the image the minimum amount while making sure both
* dimensions fit inside the requested destination area. The resulting
* destination dimensions might be adjusted to a smaller size than
* requested.
*/
public static enum ScalingLogic {
CROP, FIT
}
/**
* Calculate optimal down-sampling factor given the dimensions of a source
* image, the dimensions of a destination area and a scaling logic.
*
* @param srcWidth
* Width of source image
* @param srcHeight
* Height of source image
* @param dstWidth
* Width of destination area
* @param dstHeight
* Height of destination area
* @param scalingLogic
* Logic to use to avoid image stretching
* @return Optimal down scaling sample size for decoding
*/
public static int calculateSampleSize(int srcWidth, int srcHeight,
int dstWidth, int dstHeight, ScalingLogic scalingLogic) {
if (scalingLogic == ScalingLogic.FIT) {
final float srcAspect = (float) srcWidth / (float) srcHeight;
final float dstAspect = (float) dstWidth / (float) dstHeight;
if (srcAspect > dstAspect) {
return srcWidth / dstWidth;
} else {
return srcHeight / dstHeight;
}
} else {
final float srcAspect = (float) srcWidth / (float) srcHeight;
final float dstAspect = (float) dstWidth / (float) dstHeight;
if (srcAspect > dstAspect) {
return srcHeight / dstHeight;
} else {
return srcWidth / dstWidth;
}
}
}
/**
* Calculates source rectangle for scaling bitmap
*
* @param srcWidth
* Width of source image
* @param srcHeight
* Height of source image
* @param dstWidth
* Width of destination area
* @param dstHeight
* Height of destination area
* @param scalingLogic
* Logic to use to avoid image stretching
* @return Optimal source rectangle
*/
public static Rect calculateSrcRect(int srcWidth, int srcHeight,
int dstWidth, int dstHeight, ScalingLogic scalingLogic) {
if (scalingLogic == ScalingLogic.CROP) {
final float srcAspect = (float) srcWidth / (float) srcHeight;
final float dstAspect = (float) dstWidth / (float) dstHeight;
if (srcAspect > dstAspect) {
final int srcRectWidth = (int) (srcHeight * dstAspect);
final int srcRectLeft = (srcWidth - srcRectWidth) / 2;
return new Rect(srcRectLeft, 0, srcRectLeft + srcRectWidth,
srcHeight);
} else {
final int srcRectHeight = (int) (srcWidth / dstAspect);
final int scrRectTop = (int) (srcHeight - srcRectHeight) / 2;
return new Rect(0, scrRectTop, srcWidth, scrRectTop
+ srcRectHeight);
}
} else {
return new Rect(0, 0, srcWidth, srcHeight);
}
}
/**
* Calculates destination rectangle for scaling bitmap
*
* @param srcWidth
* Width of source image
* @param srcHeight
* Height of source image
* @param dstWidth
* Width of destination area
* @param dstHeight
* Height of destination area
* @param scalingLogic
* Logic to use to avoid image stretching
* @return Optimal destination rectangle
*/
public static Rect calculateDstRect(int srcWidth, int srcHeight,
int dstWidth, int dstHeight, ScalingLogic scalingLogic) {
if (scalingLogic == ScalingLogic.FIT) {
final float srcAspect = (float) srcWidth / (float) srcHeight;
final float dstAspect = (float) dstWidth / (float) dstHeight;
if (srcAspect > dstAspect) {
return new Rect(0, 0, dstWidth, (int) (dstWidth / srcAspect));
} else {
return new Rect(0, 0, (int) (dstHeight * srcAspect), dstHeight);
}
} else {
return new Rect(0, 0, dstWidth, dstHeight);
}
}
}
-----------------------------------------------------------------------------------------------------------------
public class ScalingTutorialActivity extends Activity {
/** Id of image resource to decode */
private int mSourceId;
/** Wanted width of decoded image */
private int mDstWidth;
/** Wanted height of decoded image */
private int mDstHeight;
/** Image view for presenting decoding result */
private ImageView mImageView;
/** Text view for presenting decoding statistics */
private TextView mResultView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Grab resources and layouts
mSourceId = R.drawable.image;
mResultView = (TextView) findViewById(R.id.text_result);
mImageView = (ImageView) findViewById(R.id.image);
mDstWidth = getResources().getDimensionPixelSize(
R.dimen.destination_width);
mDstHeight = getResources().getDimensionPixelSize(
R.dimen.destination_height);
// Register button listeners
findViewById(R.id.button_scaling_bad).setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
badButtonPressed();
}
});
findViewById(R.id.button_scaling_fit).setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
fitButtonPressed();
}
});
findViewById(R.id.button_scaling_crop).setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
cropButtonPressed();
}
});
}
/**
* Invoked when pressing button for showing result of the "Bad" decoding
* method
*/
protected void badButtonPressed() {
final long startTime = SystemClock.uptimeMillis();
// Part 1: Decode image
Bitmap unscaledBitmap = BitmapFactory.decodeResource(getResources(),
mSourceId);
// Part 2: Scale image
Bitmap scaledBitmap = Bitmap.createScaledBitmap(unscaledBitmap,
mDstWidth, mDstHeight, true);
unscaledBitmap.recycle();
// Calculate memory usage and performance statistics
final int memUsageKb = (unscaledBitmap.getRowBytes() * unscaledBitmap
.getHeight()) / 1024;
final long stopTime = SystemClock.uptimeMillis();
// Publish results
mResultView.setText("Time taken: " + (stopTime - startTime)
+ " ms. Memory used for scaling: " + memUsageKb + " kb.");
mImageView.setImageBitmap(scaledBitmap);
}
/**
* Invoked when pressing button for showing result of the "Fit" decoding
* method
*/
protected void fitButtonPressed() {
final long startTime = SystemClock.uptimeMillis();
// Part 1: Decode image
Bitmap unscaledBitmap = ScalingUtilities.decodeResource(getResources(),
mSourceId, mDstWidth, mDstHeight, ScalingLogic.FIT);
// Part 2: Scale image
Bitmap scaledBitmap = ScalingUtilities.createScaledBitmap(
unscaledBitmap, mDstWidth, mDstHeight, ScalingLogic.FIT);
unscaledBitmap.recycle();
// Calculate memory usage and performance statistics
final int memUsageKb = (unscaledBitmap.getRowBytes() * unscaledBitmap
.getHeight()) / 1024;
final long stopTime = SystemClock.uptimeMillis();
// Publish results
mResultView.setText("Time taken: " + (stopTime - startTime)
+ " ms. Memory used for scaling: " + memUsageKb + " kb.");
mImageView.setImageBitmap(scaledBitmap);
}
/**
* Invoked when pressing button for showing result of the "Crop" decoding
* method
*/
protected void cropButtonPressed() {
final long startTime = SystemClock.uptimeMillis();
// Part 1: Decode image
Bitmap unscaledBitmap = ScalingUtilities.decodeResource(getResources(),
mSourceId, mDstWidth, mDstHeight, ScalingLogic.CROP);
// Part 2: Scale image
Bitmap scaledBitmap = ScalingUtilities.createScaledBitmap(
unscaledBitmap, mDstWidth, mDstHeight, ScalingLogic.CROP);
unscaledBitmap.recycle();
// Calculate memory usage and performance statistics
final int memUsageKb = (unscaledBitmap.getRowBytes() * unscaledBitmap
.getHeight()) / 1024;
final long stopTime = SystemClock.uptimeMillis();
// Publish results
mResultView.setText("Time taken: " + (stopTime - startTime)
+ " ms. Memory used for scaling: " + memUsageKb + " kb.");
mImageView.setImageBitmap(scaledBitmap);
}
}
-----------------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:id="@+id/button_panel_scaling"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<Button
android:id="@+id/button_scaling_bad"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="wrap_content"
android:text="Bad" />
<Button
android:id="@+id/button_scaling_fit"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="wrap_content"
android:text="Fit" />
<Button
android:id="@+id/button_scaling_crop"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="wrap_content"
android:text="Crop" />
</LinearLayout>
<TextView
android:id="@+id/text_result"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:text="Choose scaling"
android:layout_above="@id/button_panel_scaling" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/text_result">
<ImageView
android:id="@+id/image"
android:layout_width="@dimen/destination_width"
android:layout_height="@dimen/destination_height"
android:layout_gravity="center"
android:scaleType="center"
android:background="#fff" />
</FrameLayout>
</RelativeLayout>
public class ScalingUtilities {
/**
* Utility function for decoding an image resource. The decoded bitmap will
* be optimized for further scaling to the requested destination dimensions
* and scaling logic.
*
* @param res
* The resources object containing the image data
* @param resId
* The resource id of the image data
* @param dstWidth
* Width of destination area
* @param dstHeight
* Height of destination area
* @param scalingLogic
* Logic to use to avoid image stretching
* @return Decoded bitmap
*/
public static Bitmap decodeResource(Resources res, int resId, int dstWidth,
int dstHeight, ScalingLogic scalingLogic) {
Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inJustDecodeBounds = false;
options.inSampleSize = calculateSampleSize(options.outWidth,
options.outHeight, dstWidth, dstHeight, scalingLogic);
Bitmap unscaledBitmap = BitmapFactory.decodeResource(res, resId,
options);
return unscaledBitmap;
}
/**
* Utility function for creating a scaled version of an existing bitmap
*
* @param unscaledBitmap
* Bitmap to scale
* @param dstWidth
* Wanted width of destination bitmap
* @param dstHeight
* Wanted height of destination bitmap
* @param scalingLogic
* Logic to use to avoid image stretching
* @return New scaled bitmap object
*/
public static Bitmap createScaledBitmap(Bitmap unscaledBitmap,
int dstWidth, int dstHeight, ScalingLogic scalingLogic) {
Rect srcRect = calculateSrcRect(unscaledBitmap.getWidth(),
unscaledBitmap.getHeight(), dstWidth, dstHeight, scalingLogic);
Rect dstRect = calculateDstRect(unscaledBitmap.getWidth(),
unscaledBitmap.getHeight(), dstWidth, dstHeight, scalingLogic);
Bitmap scaledBitmap = Bitmap.createBitmap(dstRect.width(),
dstRect.height(), Config.ARGB_8888);
Canvas canvas = new Canvas(scaledBitmap);
canvas.drawBitmap(unscaledBitmap, srcRect, dstRect, new Paint(
Paint.FILTER_BITMAP_FLAG));
return scaledBitmap;
}
/**
* ScalingLogic defines how scaling should be carried out if source and
* destination image has different aspect ratio.
*
* CROP: Scales the image the minimum amount while making sure that at least
* one of the two dimensions fit inside the requested destination area.
* Parts of the source image will be cropped to realize this.
*
* FIT: Scales the image the minimum amount while making sure both
* dimensions fit inside the requested destination area. The resulting
* destination dimensions might be adjusted to a smaller size than
* requested.
*/
public static enum ScalingLogic {
CROP, FIT
}
/**
* Calculate optimal down-sampling factor given the dimensions of a source
* image, the dimensions of a destination area and a scaling logic.
*
* @param srcWidth
* Width of source image
* @param srcHeight
* Height of source image
* @param dstWidth
* Width of destination area
* @param dstHeight
* Height of destination area
* @param scalingLogic
* Logic to use to avoid image stretching
* @return Optimal down scaling sample size for decoding
*/
public static int calculateSampleSize(int srcWidth, int srcHeight,
int dstWidth, int dstHeight, ScalingLogic scalingLogic) {
if (scalingLogic == ScalingLogic.FIT) {
final float srcAspect = (float) srcWidth / (float) srcHeight;
final float dstAspect = (float) dstWidth / (float) dstHeight;
if (srcAspect > dstAspect) {
return srcWidth / dstWidth;
} else {
return srcHeight / dstHeight;
}
} else {
final float srcAspect = (float) srcWidth / (float) srcHeight;
final float dstAspect = (float) dstWidth / (float) dstHeight;
if (srcAspect > dstAspect) {
return srcHeight / dstHeight;
} else {
return srcWidth / dstWidth;
}
}
}
/**
* Calculates source rectangle for scaling bitmap
*
* @param srcWidth
* Width of source image
* @param srcHeight
* Height of source image
* @param dstWidth
* Width of destination area
* @param dstHeight
* Height of destination area
* @param scalingLogic
* Logic to use to avoid image stretching
* @return Optimal source rectangle
*/
public static Rect calculateSrcRect(int srcWidth, int srcHeight,
int dstWidth, int dstHeight, ScalingLogic scalingLogic) {
if (scalingLogic == ScalingLogic.CROP) {
final float srcAspect = (float) srcWidth / (float) srcHeight;
final float dstAspect = (float) dstWidth / (float) dstHeight;
if (srcAspect > dstAspect) {
final int srcRectWidth = (int) (srcHeight * dstAspect);
final int srcRectLeft = (srcWidth - srcRectWidth) / 2;
return new Rect(srcRectLeft, 0, srcRectLeft + srcRectWidth,
srcHeight);
} else {
final int srcRectHeight = (int) (srcWidth / dstAspect);
final int scrRectTop = (int) (srcHeight - srcRectHeight) / 2;
return new Rect(0, scrRectTop, srcWidth, scrRectTop
+ srcRectHeight);
}
} else {
return new Rect(0, 0, srcWidth, srcHeight);
}
}
/**
* Calculates destination rectangle for scaling bitmap
*
* @param srcWidth
* Width of source image
* @param srcHeight
* Height of source image
* @param dstWidth
* Width of destination area
* @param dstHeight
* Height of destination area
* @param scalingLogic
* Logic to use to avoid image stretching
* @return Optimal destination rectangle
*/
public static Rect calculateDstRect(int srcWidth, int srcHeight,
int dstWidth, int dstHeight, ScalingLogic scalingLogic) {
if (scalingLogic == ScalingLogic.FIT) {
final float srcAspect = (float) srcWidth / (float) srcHeight;
final float dstAspect = (float) dstWidth / (float) dstHeight;
if (srcAspect > dstAspect) {
return new Rect(0, 0, dstWidth, (int) (dstWidth / srcAspect));
} else {
return new Rect(0, 0, (int) (dstHeight * srcAspect), dstHeight);
}
} else {
return new Rect(0, 0, dstWidth, dstHeight);
}
}
}
-----------------------------------------------------------------------------------------------------------------
public class ScalingTutorialActivity extends Activity {
/** Id of image resource to decode */
private int mSourceId;
/** Wanted width of decoded image */
private int mDstWidth;
/** Wanted height of decoded image */
private int mDstHeight;
/** Image view for presenting decoding result */
private ImageView mImageView;
/** Text view for presenting decoding statistics */
private TextView mResultView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Grab resources and layouts
mSourceId = R.drawable.image;
mResultView = (TextView) findViewById(R.id.text_result);
mImageView = (ImageView) findViewById(R.id.image);
mDstWidth = getResources().getDimensionPixelSize(
R.dimen.destination_width);
mDstHeight = getResources().getDimensionPixelSize(
R.dimen.destination_height);
// Register button listeners
findViewById(R.id.button_scaling_bad).setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
badButtonPressed();
}
});
findViewById(R.id.button_scaling_fit).setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
fitButtonPressed();
}
});
findViewById(R.id.button_scaling_crop).setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
cropButtonPressed();
}
});
}
/**
* Invoked when pressing button for showing result of the "Bad" decoding
* method
*/
protected void badButtonPressed() {
final long startTime = SystemClock.uptimeMillis();
// Part 1: Decode image
Bitmap unscaledBitmap = BitmapFactory.decodeResource(getResources(),
mSourceId);
// Part 2: Scale image
Bitmap scaledBitmap = Bitmap.createScaledBitmap(unscaledBitmap,
mDstWidth, mDstHeight, true);
unscaledBitmap.recycle();
// Calculate memory usage and performance statistics
final int memUsageKb = (unscaledBitmap.getRowBytes() * unscaledBitmap
.getHeight()) / 1024;
final long stopTime = SystemClock.uptimeMillis();
// Publish results
mResultView.setText("Time taken: " + (stopTime - startTime)
+ " ms. Memory used for scaling: " + memUsageKb + " kb.");
mImageView.setImageBitmap(scaledBitmap);
}
/**
* Invoked when pressing button for showing result of the "Fit" decoding
* method
*/
protected void fitButtonPressed() {
final long startTime = SystemClock.uptimeMillis();
// Part 1: Decode image
Bitmap unscaledBitmap = ScalingUtilities.decodeResource(getResources(),
mSourceId, mDstWidth, mDstHeight, ScalingLogic.FIT);
// Part 2: Scale image
Bitmap scaledBitmap = ScalingUtilities.createScaledBitmap(
unscaledBitmap, mDstWidth, mDstHeight, ScalingLogic.FIT);
unscaledBitmap.recycle();
// Calculate memory usage and performance statistics
final int memUsageKb = (unscaledBitmap.getRowBytes() * unscaledBitmap
.getHeight()) / 1024;
final long stopTime = SystemClock.uptimeMillis();
// Publish results
mResultView.setText("Time taken: " + (stopTime - startTime)
+ " ms. Memory used for scaling: " + memUsageKb + " kb.");
mImageView.setImageBitmap(scaledBitmap);
}
/**
* Invoked when pressing button for showing result of the "Crop" decoding
* method
*/
protected void cropButtonPressed() {
final long startTime = SystemClock.uptimeMillis();
// Part 1: Decode image
Bitmap unscaledBitmap = ScalingUtilities.decodeResource(getResources(),
mSourceId, mDstWidth, mDstHeight, ScalingLogic.CROP);
// Part 2: Scale image
Bitmap scaledBitmap = ScalingUtilities.createScaledBitmap(
unscaledBitmap, mDstWidth, mDstHeight, ScalingLogic.CROP);
unscaledBitmap.recycle();
// Calculate memory usage and performance statistics
final int memUsageKb = (unscaledBitmap.getRowBytes() * unscaledBitmap
.getHeight()) / 1024;
final long stopTime = SystemClock.uptimeMillis();
// Publish results
mResultView.setText("Time taken: " + (stopTime - startTime)
+ " ms. Memory used for scaling: " + memUsageKb + " kb.");
mImageView.setImageBitmap(scaledBitmap);
}
}
-----------------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:id="@+id/button_panel_scaling"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<Button
android:id="@+id/button_scaling_bad"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="wrap_content"
android:text="Bad" />
<Button
android:id="@+id/button_scaling_fit"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="wrap_content"
android:text="Fit" />
<Button
android:id="@+id/button_scaling_crop"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="wrap_content"
android:text="Crop" />
</LinearLayout>
<TextView
android:id="@+id/text_result"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:text="Choose scaling"
android:layout_above="@id/button_panel_scaling" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/text_result">
<ImageView
android:id="@+id/image"
android:layout_width="@dimen/destination_width"
android:layout_height="@dimen/destination_height"
android:layout_gravity="center"
android:scaleType="center"
android:background="#fff" />
</FrameLayout>
</RelativeLayout>
Comments
Post a Comment