Bitmap,BitmapDrawable,BitmapFactory用法

       Bitmap原意指一种图片文件格式,即bmp图片格式,其他常见的格式有jpg,png和gif等.在android中,Bitmap是指一种用于存储图片数据的对象类型,图片数据包括图片的宽度,高度以及图片上每个像素点所包含的信息等.

       Bitmap所包含的图片数据中,图片的宽度,高度,密度(density的值,表示每英寸包含多少个显示点)以及每个像素点的颜色等信息都是用get方法和set方法来获取和设置的,在API文档中可以方便的查到.

       Bitmap还提供了一些静态方法来创建新的Bitmap对象,例如如下常用方法.

            >  createBitmap(Bitmap source, int x, int y, int width, int height):  从源位图source的指定坐标点(给定x,y)开始,从中"挖取"宽width,高height的一块出来,创建新的Bitmap对象.

            >  createScaledBitmap(Bitmap src, int dstWidth, int dstHeight): 对源位图src进行缩放,缩放成宽dstWidth,高dstHeight的新位图.

            >  createBitmap(int width, int height, Bitmap.Config config): 创建一个宽width,高height的新位图.

            >  createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter): 从源位图source的指定坐标点(给定x,y)开始,从中"挖取"宽width,高height的一块出来,创建新的Bitmap对象.并按Matrix指定的规则进行变换.

       Android为Bitmap提供了两个方法来判断它是否已回收,以及强制Bitmap回收自己.

            > boolean isRecycled(): 返回该Bitmap对象是否已被回收.

            > void recycle(): 强制一个Bitmap对象立即回收自己.

       BitmapFactory是一个工具类,它用于提供大量的方法,这些方法可用于从不同的数据源来解析,创建Bitmap对象.BitmapFactory包含了如下方法.

            > decodeByteArray(byte[] data, int offset, int length): 从指定字节数组的offset位置开始,将长度为length的字节数据解析成Bitmap对象.

            > decodeFile(String pathName): 从pathName指定的文件中解析,创建Bitmap对象.

            > decodeFileDescriptor(FileDescriptor fd): 用于从FileDescriptor对应的文件中解析,创建Bitmap对象.

            > decodeResource(Resources res, int id): 用于根据给定的资源ID从置顶资源中解析,创建Bitmap对象.

            > decodeStream(InputStream is): 用于从指定输入流中解析,创建Bitmap对象.

       大部分时候,我们只要把图片放在/res/drawable-mdpi/目录下,就可以在程序中通过该图片对应的资源ID来获取封装该图片的Drawable对象.但由于手机系统的内存比较下,如果系统不停地去解析,创建Bitmap对象,可能由于前面创建Bitmap所占用的内存还没有回收,而导致程序运行时引发OutOfMemory错误.


     Bitmap.Config可以定义Bitmap的颜色格式,目前仅支持4种格式

 

格式含义
ALPHA_8透明度为8位的位图
ARGB_4444参数A,R,G和B都由4bit表示,是一种16位的位图
ARGB_8888参数A,R,G和B都由4bit表示,是一种32位的位图
RGB_565参数R,G和B分别占5bit,6bit和5bit,是一种三原色通道经过压缩的16位位图






下面是摘取的以下bitmap的用法:

http://www.jb51.net/article/32366.htm

感谢这位


package com.example.bitmapdemo;

import java.io.Externalizable;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
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.view.Menu;
import android.widget.ImageView;

//方法:
//1 生成圆角Bitmap图片
//2 生成Bitmap缩量图
//3 压缩图片场长宽以及kB
//注意:
//以上代码,测试其中一个方法时最好注释掉其余的代码 
public class MainActivity extends Activity {
	private ImageView mImageView;
	private Bitmap copyRawBitmap1;
	private Bitmap copyRawBitmap2;
	private Bitmap copyRawBitmap3;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mImageView = (ImageView) findViewById(R.id.imageview);

		// 第一种方式:从资源文件中得到图片
		Bitmap rawBitmap = BitmapFactory.decodeResource(getResources(),
				R.drawable.ic_launcher);
		copyRawBitmap1 = rawBitmap;
		copyRawBitmap2 = rawBitmap;
		copyRawBitmap3 = rawBitmap;

		// 第二种方式:从SD卡中得到图片(方法1)
		String SDCarePath = Environment.getExternalStorageDirectory()
				.toString();
		String filePaht = SDCarePath + "/" + "head.png";
		Bitmap rawBitmap1 = BitmapFactory.decodeFile(filePaht, null);

		// 第二种方式:从SD卡中得到图片(方法2)
		InputStream is = getBitmapInputStreamFromSDCard("head.png");
		Bitmap rawBitmap2 = BitmapFactory.decodeStream(is);

		// 设置图片的圆角
		Bitmap roundCornerBitmap = this.toRoundCorner(rawBitmap, 40);
		mImageView.setImageBitmap(roundCornerBitmap);

		// 将图片高宽和的大小kB压缩
		toCompressionWidthHeightForSizeKB(rawBitmap);

		// 将图片的kB压缩,宽高不变
		compressAndSaveBitmapToSDCard(rawBitmap1, "head.jpg", 80);

		// 获取SD卡图片的缩略图方法1
		String SDCarePath1 = Environment.getExternalStorageDirectory()
				.toString();
		String filePath1 = SDCarePath1 + "/" + "head.png";
		Bitmap bitmapThumbnail_1 = this.getBitmapThumbnail(filePath1);
		mImageView.setImageBitmap(bitmapThumbnail_1);
		
		// 获取SD卡图片的缩略图方法2
		String SDCarePath2 = Environment.getExternalStorageDirectory()
				.toString();
		String filePath2=SDCarePath2+"/"+"haha.jpg"; 
		Bitmap tempBitmap = BitmapFactory.decodeFile(filePath2);
		Bitmap bitmapThumbnail_2 = ThumbnailUtils.extractThumbnail(tempBitmap, 100, 100);
		mImageView.setImageBitmap(bitmapThumbnail_2);
	}

	/**
	 * 获取图片的缩略图
	 * 
	 * @param filePaht
	 *            图片路径
	 * @return 图片的缩略图
	 */
	private Bitmap getBitmapThumbnail(String filePaht) {
		BitmapFactory.Options options = new BitmapFactory.Options();
		// true那么将不返回实际的bitmap对象,不给其分配内存空间但是可以得到一些解码边界信息即图片大小等信息
		options.inJustDecodeBounds = true;
		// 此时rawBitmap为null
		Bitmap rawBitmap = BitmapFactory.decodeFile(filePaht, options);
		if (rawBitmap == null) {
			System.out.println("此时rawBitmap为null");
		}
		// inSampleSize表示缩略图大小为原始图片大小的几分之一,若该值为3
		// 则取出的缩略图的宽和高都是原始图片的1/3,图片大小就为原始大小的1/9
		// 计算sampleSize
		 int sampleSize = computeSampleSize(options, 150, 200 * 200);
		//为了读到图片,必须把options.inJustDecodeBounds设回false 
		 options.inJustDecodeBounds = false;
		 //设置缩略图的大小
		 options.inSampleSize = sampleSize;
		//原图大小为625x690 90.2kB
		//测试调用computeSampleSize(options, 100, 200*100);
		//得到sampleSize=8
		//得到宽和高位79和87
		//79*8=632 87*8=696 
		 Bitmap thumbnailBitmap = BitmapFactory.decodeFile(filePaht, options);
		//保存到SD卡方便比较 
		 compressAndSaveBitmapToSDCard(thumbnailBitmap, "15.jpg", 80);
		return thumbnailBitmap;
	}

	/**
	 * 计算缩略图的大小
	 * 
	 * @param options
	 *            原本Bitmap的options
	 * @param minSideLength
	 *            希望生成的缩略图的宽高中的较小的值
	 * @param maxNumOfPixels
	 *            希望生成的缩量图的总像素
	 * @return 缩略图的大小
	 */
	// 参考资料:
	// http://my.csdn.net/zljk000/code/detail/18212
	public int computeSampleSize(BitmapFactory.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;
	}

	/**
	 * 计算初始图片的大小
	 * 
	 * @param options
	 *            Bitmap的options
	 * @param minSideLength
	 *            希望生成的缩略图的宽高中的较小的值
	 * @param maxNumOfPixels
	 *            希望生成的缩量图的总像素
	 * @return 缩略图的大小
	 */
	private int computeInitialSampleSize(BitmapFactory.Options options,
			int minSideLength, int maxNumOfPixels) {
		// 原始图片的宽
		double w = options.outWidth;
		// 原始图片的高
		double h = options.outHeight;
		System.out.println("========== w=" + w + ",h=" + h);
		// 图片大小的下限值
		int lowerBound = (int) (maxNumOfPixels == -1 ? 1 : Math.ceil(Math
				.sqrt(w * h / maxNumOfPixels)));
		// 图片大小的上限值
		int upperBound = (int) (minSideLength == -1 ? 128 : 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;
		}
	}

	/**
	 * 图片高宽和的大小kB压缩
	 * 
	 * @param bitmap
	 *            需要压缩的图片
	 */
	private void toCompressionWidthHeightForSizeKB(Bitmap bitmap) {
		// 得到图片原始的高宽
		int rawWidth = bitmap.getWidth();
		int rawHeight = bitmap.getHeight();
		// 设定图片新的高宽
		int newWidth = 100;
		int newHeight = 100;
		// 计算缩放因子
		float heightScale = newHeight / rawHeight;
		float widthScale = newWidth / rawWidth;
		// 新建立矩阵
		Matrix matrix = new Matrix();
		// 设置缩放
		matrix.postScale(newWidth, newHeight);
		// 设置图片的旋转角度
		matrix.setRotate(-30);
		// 设置图片的倾斜
		matrix.postSkew(0.1f, 0.1f);
		// 将图片大小压缩
		// 压缩后图片的宽和高以及kB大小均会变化
		Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, rawWidth,
				rawHeight, matrix, true);
		// 将Bitmap转换为Drawable
		Drawable drawable = new BitmapDrawable(newBitmap);
		mImageView.setImageDrawable(drawable);
		// 然后将Bitmap保存到SDCard中,方便于原图片的比较
		compressAndSaveBitmapToSDCard(newBitmap, "head.jpg", 80);
	}

	/**
	 * 压缩且保存图片到SDCard
	 * 
	 * @param rawBitmap
	 *            需要压缩保存的位图
	 * @param fileName
	 *            图片名称
	 * @param quality
	 *            图像压缩比的值,0-100.0 意味着小尺寸压缩,100意味着高质量压缩
	 */
	private void compressAndSaveBitmapToSDCard(Bitmap rawBitmap,
			String fileName, int quality) {
		String filePath = getSDCardPath() + File.separator + fileName;
		File saveFile = new File(filePath);
		// 判断文件是否存在
		if (!saveFile.exists()) {
			try {
				saveFile.createNewFile();
				FileOutputStream fileOutputStream = new FileOutputStream(
						saveFile);
				if (fileOutputStream != null) {
					// imageBitmap.compress(format, quality, stream);
					// 把位图的压缩信息写入到一个指定的输出流中
					// 第一个参数format为压缩的格式
					// 第二个参数quality为图像压缩比的值,0-100.0 意味着小尺寸压缩,100意味着高质量压缩
					// 第三个参数stream为输出流
					rawBitmap.compress(Bitmap.CompressFormat.JPEG, quality,
							fileOutputStream);
					// 问题:
					// 原图大小为625x690 90.2kB
					// 如果设置图片500x500 压缩后大小为171kB.即压缩后kB反而变大了.
					// 原因是将:compress(Bitmap.CompressFormat.JPEG, quality,
					// fileOutputStream);
					// 第二个参数quality设置得有些大了(比如100).
					// 常用的是80,刚设100太大了造成的.
				}
				fileOutputStream.flush();
				fileOutputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}

		}
	}

	/**
	 * 获取SDCard的目录路径功能
	 * 
	 * @return 路径
	 */
	private String getSDCardPath() {
		String SDCarePath = null;
		// 判断SDCard是否存在
		boolean isSDcardExist = Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED);
		if (isSDcardExist) {
			SDCarePath = Environment.getExternalStorageDirectory().toString();
		}
		return SDCarePath;
	}

	/**
	 * 读取SD卡下的图片
	 * 
	 * @param fileName
	 *            图片路径
	 * @return
	 */
	private InputStream getBitmapInputStreamFromSDCard(String fileName) {
		// 提供访问环境变量
		// Environment
		// 返回主“外部”存储设备的当前状态。
		// Environment.getExternalStorageState()
		// 存储状态,如果媒体是目前安装在其安装点和读/写访问。
		// Environment.MEDIA_MOUNTED
		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			// 外部存储目录
			String SDCarePath = Environment.getExternalStorageDirectory()
					.toString();
			// 使用单独的组件文件系统相关的字符串(“/”)。看到分隔字符。
			// File.separator
			String filePath = SDCarePath + File.separator + fileName;
			File file = new File(filePath);
			try {
				FileInputStream fileInputStream = new FileInputStream(file);
				return fileInputStream;
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 设置bitmap图片圆角
	 * 
	 * @param bitmap
	 *            需要修改的图片
	 * @param pixels
	 *            圆角的弧度
	 * @return 圆角图片
	 */
	// 参考资料:
	// http://blog.csdn.net/c8822882/article/details/6906768
	private Bitmap toRoundCorner(Bitmap bitmap, int pixels) {
		// 创建一个新的位图
		Bitmap roundCornerBitmap = Bitmap.createBitmap(bitmap.getWidth(),
				bitmap.getHeight(), Bitmap.Config.ARGB_8888);
		// 创建一个画布,在上面绘制圆角的bitmap位图
		Canvas canvas = new Canvas(roundCornerBitmap);
		// 创建一个color色值
		int color = 0xff424242;
		// 创建一个画笔,绘画bitmap位图
		Paint paint = new Paint();
		paint.setColor(color);
		// 设置防锯齿
		paint.setAntiAlias(true);
		// 创建一个矩形区域,在这个区域里面绘制圆角bitmap位图
		Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
		// 这个是用于实现一些不规则的矩形
		RectF rectF = new RectF(rect);
		float roundPx = pixels;
		// 相当于清屏
		canvas.drawARGB(0, 0, 0, 0);
		// 使用指定的画笔绘制圆矩形。将填充的圆角矩形或框架基于涂料中的风格,即你设置的paint画笔的属性。
		canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
		// 设置Xfermode
		paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
		// 再把原来的bitmap画到现在的bitmap!!!注意这个理解
		// 理解:rectF相当于Dst,rect相当于Src,使用Xfermode,Mode的SRC_IN属性,
		// 那么最后现实的范围是rectF与rect的交集,也就是rectF的范围,但是显示的内容是rect里面的内容,也就是要显示的图片的内容
		canvas.drawBitmap(bitmap, rect, rect, paint);
		return roundCornerBitmap;
	}

}

上面的例子中,用到了Xfermode,在这里描述一下:

转载:

http://blog.csdn.net/c8822882/article/details/6906768

感谢!

setXfermode 

设置两张图片相交时的模式 

我们知道 在正常的情况下,在已有的图像上绘图将会在其上面添加一层新的形状。 如果新的Paint是完全不透明的,那么它将完全遮挡住下面的Paint; 

而setXfermode就可以来解决这个问题
 


一般来说 用法是这样的 

  1. Canvas canvas = new Canvas(bitmap1);  
  2.   
  3. paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));  
  4.   
  5. canvas.drawBitmap(mask, 0f, 0f, paint);    

就是在图片bitmap1上面绘制图片mask时 处理两者相交时候显示的问题 

canvas原有的图片 可以理解为背景 就是dst 
新画上去的图片 可以理解为前景 就是src






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值