package com.testbitmapscale;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.ThumbnailUtils;
import android.os.Bundle;
import android.os.Environment;
import android.widget.ImageView;
/**
* Demo描述:
* 1 生成圆角Bitmap图片
* 2 利用Bitmap.compress()方法将Bitmap保存到指定位置.
* 该方法可减少原Bitmap的KB值,但不一定会减少原Bitmap宽和高的pixel.
* 3 利用Google提供的方法计算出合适的options.inSampleSize,从而获取缩略图
* 4 利用系统自带方法ThumbnailUtils.extractThumbnail()获取缩略图
* 5 利用Bitmap.createBitmap(...matrix...)获取缩略图
* 该方法主要是利用了矩阵Matrix的postScale()设置缩放比
*
*
* 注意事项:
* 测试其中一个方法时最好注释掉其余的代码
*
* 参考资料:
* 1 http://blog.csdn.net/c8822882/article/details/6906768
* 2 http://www.5yijia.com/?p=173
* 3 http://blog.csdn.net/t12x3456/article/details/10432935
* 4 http://blog.csdn.net/edisonlg/article/details/7084977
* 5 http://blog.csdn.net/superfpe/article/details/8750938
* Thank you very much
*/
public class MainActivity extends Activity {
private ImageView mImageView;
private Bitmap copyRawBitmap;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mImageView = (ImageView) findViewById(R.id.imageView);
//------>以下为生成Bitmap的几种方式
//第一种方式:从资源文件中得到图片
Bitmap rawBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.haha);
copyRawBitmap=rawBitmap;
//第二种方式:从SD卡中得到图片(方法1)
String SDCarePath=Environment.getExternalStorageDirectory().toString();
String filePath=SDCarePath+"/"+"haha.jpg";
Bitmap rawBitmap1 = BitmapFactory.decodeFile(filePath, null);
//第二种方式:从SD卡中得到图片(方法2)
InputStream inputStream=getBitmapInputStreamFromSDCard("haha.jpg");
Bitmap rawBitmap2 = BitmapFactory.decodeStream(inputStream);
//------>以上为生成Bitmap的几种方式
// //------>以下为将设置图片的圆角
// Bitmap roundCornerBitmap=this.getRoundCornerBitmap(rawBitmap, 60);
// mImageView.setImageBitmap(roundCornerBitmap);
// //------>以上为将设置图片的圆角
// //------>以下为将图片的kB压缩即KB会变小,但宽高(pixel像素)可能变大或者变小
// this.compressAndSaveBitmapToSDCard(copyRawBitmap,"haha_new70.jpg",70);
// this.compressAndSaveBitmapToSDCard(copyRawBitmap,"haha_new80.jpg",80);
// this.compressAndSaveBitmapToSDCard(copyRawBitmap,"haha_new90.jpg",90);
// //------>以上为将图片的kB压缩即KB会变小,但宽高(pixel像素)可能变大或者变小
// //------>以下为获取SD卡图片的缩略图方法1
// String SDCarePath1=Environment.getExternalStorageDirectory().toString();
// String filePath1=SDCarePath1+"/"+"haha.jpg";
// Bitmap bitmapThumbnail1=this.getBitmapThumbnail(filePath1);
// mImageView.setImageBitmap(bitmapThumbnail1);
// //------>以上为获取SD卡图片的缩略图方法1
// //------>以下为获取SD卡图片的缩略图方法2
// //利用系统自带方法ThumbnailUtils.extractThumbnail(Bitmap source,int width,int height)
// //第二,三个参数表示压缩后的宽和高
// String SDCarePath2=Environment.getExternalStorageDirectory().toString();
// String filePath2=SDCarePath2+"/"+"xixi.jpg";
// Bitmap tempBitmap=BitmapFactory.decodeFile(filePath2);
// Bitmap bitmapThumbnail2=ThumbnailUtils.extractThumbnail(tempBitmap, 200, 200);
// mImageView.setImageBitmap(bitmapThumbnail2);
// //------>以上为获取SD卡图片的缩略图方法2
// //------>以下为利用Bitmap.createBitmap()获取缩略图
// // 第一步:得到图片原始的高宽
// int rawHeight = rawBitmap.getHeight();
// int rawWidth = rawBitmap.getWidth();
// // 第二步:设定图片新的高宽
// int newHeight = 500;
// int newWidth = 500;
// // 第三步:计算缩放因子
// float heightScale = ((float) newHeight) / rawHeight;
// float widthScale = ((float) newWidth) / rawWidth;
// // 第四步:利用Matrix设置宽和高的缩放Scale
// Matrix matrix = new Matrix();
// matrix.postScale(widthScale, heightScale);
// // 设置图片的旋转角度
// //matrix.postRotate(-30);
// // 设置图片的倾斜
// //matrix.postSkew(0.1f, 0.1f);
// // 第五步:获取缩略图
// Bitmap newBitmap = Bitmap.createBitmap(rawBitmap, 0, 0, rawWidth,rawHeight, matrix, true);
// mImageView.setImageBitmap(newBitmap);
// //------>以上为利用Bitmap.createBitmap()获取缩略图
}
/**
* 压缩且保存图片到SDCard
*
* Bitmap.compress(CompressFormat format, int quality, OutputStream stream)
* 把位图的压缩信息写入到一个指定的输出流中
* 第一个参数format为压缩的格式
* 第二个参数quality为图像压缩比的值,0-100.0 意味着小尺寸压缩,100意味着高质量压缩
* 第三个参数stream为输出流
*
* 注意事项:
* 1 Bitmap.compress()该方法不一定会变小图片的宽和高(pixel像素),有时反而会变大
* 但一定会减小图片的KB值
* 2 Bitmap.compress()该方法不适用于压缩PNG格式,因为它是无损的.
* 所以在Android开发中推荐使用PNG格式的图片.jpg格式有什么问题呢?
* jpg格式经过反复的编辑和保存会造成图片失真,请参见资料5
*/
private void compressAndSaveBitmapToSDCard(Bitmap rawBitmap,String fileName,int quality){
String saveFilePaht=this.getSDCardPath()+File.separator+fileName;
File saveFile=new File(saveFilePaht);
if (!saveFile.exists()) {
try {
saveFile.createNewFile();
FileOutputStream fileOutputStream=new FileOutputStream(saveFile);
if (fileOutputStream!=null) {
rawBitmap.compress(Bitmap.CompressFormat.JPEG, quality, fileOutputStream);
}
fileOutputStream.flush();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 获取图片的缩略图
// 测试分析:
// 原图大小为宽和高的像素值为:625x690,KB大小值为90.2kB.
// 该图片在res中备份,作为测试图片
// 调用方法computeSampleSize(options, 100, 100*200);
// 表示希望得到的图片宽和高两者的最小值为100pixel,图片的总大小为100*200pixel.
// 该方法返回的insampleSize=8,最终生成的图片宽和高分别为79和87
// 在此做一个小验证:
// 79*8=632 87*8=696 即为632x696,该值接近于原本的625x690
private Bitmap getBitmapThumbnail(String filePath) {
BitmapFactory.Options options = new BitmapFactory.Options();
// 将options.inJustDecodeBounds设置为true
// 那么利用BitmapFactory.decodeXXX(...options...)将不返回实际的bitmap对象
// 不给其分配内存空间但是可以得到图片的一些解码边界信息即图片大小等
options.inJustDecodeBounds = true;
// 此时rawBitmap为null
Bitmap rawBitmap = BitmapFactory.decodeFile(filePath, options);
if (rawBitmap == null) {
System.out.println("---> 验证了上面的解释");
}
// 计算insampleSize
// inSampleSize表示缩略图大小为原始图片大小的几分之一,若该值为3
// 则取出的缩略图的宽和高的pixel均为原始图片的1/3,图片大小就为原始大小的1/9
int insampleSize = computeSampleSize(options, 100, 100 * 200);
options.inSampleSize = insampleSize;
// 为BitmapFactory.decodeXXX(...options...)获取到实际的bitmap对象读到图片
// 必须把options.inJustDecodeBounds设回false
options.inJustDecodeBounds = false;
Bitmap thumbnailBitmap = BitmapFactory.decodeFile(filePath, options);
System.out.println("---> insampleSize="+insampleSize+",width="+
thumbnailBitmap.getWidth()+",height="+thumbnailBitmap.getHeight());
return thumbnailBitmap;
}
//Android提供的一种动态计算的方法,得到恰当的inSampleSize
//第一个参数:原本Bitmap的options
//第二个参数:希望生成的缩略图的宽高中的pixel较小的值
//第三个参数:希望生成的缩量图的总像素pixel
public static int computeSampleSize(Options options,int minSideLength, int maxNumOfPixels) {
int initialSize = computeInitialSampleSize(options, minSideLength,maxNumOfPixels);
int roundedSize;
if (initialSize <= 8) {
roundedSize = 1;
while (roundedSize < initialSize) {
roundedSize <<= 1;
}
} else {
roundedSize = (initialSize + 7) / 8 * 8;
}
return roundedSize;
}
private static int computeInitialSampleSize(Options options,int minSideLength, int maxNumOfPixels) {
double w = options.outWidth;
double h = options.outHeight;
int lowerBound = (maxNumOfPixels == -1) ? 1 :
(int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
int upperBound = (minSideLength == -1) ? 128 :
(int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));
if (upperBound < lowerBound) {
// return the larger one when there is no overlapping zone.
return lowerBound;
}
if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
return 1;
} else if (minSideLength == -1) {
return lowerBound;
} else {
return upperBound;
}
}
/**
* @param bitmap 需要修改的图片
* @param pixels 圆角的弧度
* @return 圆角图片
*
* 步骤如下:
* 1 新建一个Canvas,注意其构造方法为
* Canvas canvas = new Canvas(roundCornerBitmap);
* 即构造方法传入的参数是一个Bitmap
* 2 在画布上画一个圆角矩形
* 3 设置Paint的模式Mode.SRC_IN
* 4 在画布上画原图
* 最终的结果就是圆角图片即为roundCornerBitmap
*
* 注意事项:
* 在new一个Canvas需要一个Bitmap作为参数,然后需要画什么东西就利用
* Canvas的drawXXX()方法即可.在这个画的过程中实际上是画到了这个
* Bitmap上,即在该Bitmap上涂鸦.所以画的东西和结果都在这个Bitmap上.
*
*/
public Bitmap getRoundCornerBitmap(Bitmap bitmap, float pixels) {
int width=bitmap.getWidth();
int height=bitmap.getHeight();
Bitmap roundCornerBitmap = Bitmap.createBitmap(width,height, Config.ARGB_8888);
//第一步:利用Bitmap生成Canvas
Canvas canvas = new Canvas(roundCornerBitmap);
int color = 0xff424242;
Paint paint = new Paint();
paint.setColor(color);
//防止锯齿
paint.setAntiAlias(true);
Rect rect = new Rect(0, 0, width, height);
RectF rectF = new RectF(rect);
//相当于清屏
canvas.drawARGB(0, 0, 0, 0);
//第二步:画圆角矩形
canvas.drawRoundRect(rectF, pixels, pixels, paint);
//第三步:为画笔Paint设置模式
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
//第四步:画原图
canvas.drawBitmap(bitmap, rect, rect, paint);
return roundCornerBitmap;
}
//获取SDCard路径
private String getSDCardPath() {
String SDCardPath = null;
boolean IsSDcardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
if (IsSDcardExist) {
SDCardPath = Environment.getExternalStorageDirectory().toString();
}
return SDCardPath;
}
// 读取SD卡下的图片
private InputStream getBitmapInputStreamFromSDCard(String fileName) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String SDCarePath = Environment.getExternalStorageDirectory().toString();
String filePath = SDCarePath + File.separator + fileName;
File file = new File(filePath);
try {
FileInputStream fileInputStream = new FileInputStream(file);
return fileInputStream;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}