在Android中,提供了一个BitmapFactory类,该类为一个工其类,用于从不同的数据源来解析、创建Bitmap对象,
BitmapFactory类提供的创建Bitmap对象,它提供了如下的方法:
static Bitmap decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts)
Decode an immutable bitmap from the specified byte array.
static Bitmap decodeByteArray(byte[] data, int offset, int length)
Decode an immutable bitmap from the specified byte array.
static Bitmap decodeFile(String pathName)
Decode a file path into a bitmap.
static Bitmap decodeFile(String pathName, BitmapFactory.Options opts)
Decode a file path into a bitmap.
static Bitmap decodeFileDescriptor(FileDescriptor fd)
Decode a bitmap from the file descriptor.
static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, BitmapFactory.Options opts)
Decode a bitmap from the file descriptor.
static Bitmap decodeResource(Resources res, int id, BitmapFactory.Options opts)
Synonym for opening the given resource and calling decodeResourceStream(Resources, TypedValue, InputStream, Rect, BitmapFactory.Options).
static Bitmap decodeResource(Resources res, int id)
Synonym for decodeResource(Resources, int, android.graphics.BitmapFactory.Options) with null Options.
static Bitmap decodeResourceStream(Resources res, TypedValue value, InputStream is, Rect pad, BitmapFactory.Options opts)
Decode a new Bitmap from an InputStream.
static Bitmap decodeStream(InputStream is)
Decode an input stream into a bitmap.
static Bitmap decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts)
Decode an input stream into a bitmap.
例如,要解析SD卡上的图片文件img01.jpg并创建对应的Bitmap对象,可以使用下面的代码:
String path="/sdcard/pictures/abc/img01.jpg";
Bitmap bm=BitmapFactory.decodeFile(path);
要解析Drawable资源中保存的图片文件并创建对应的Bitmep对象。可以使用下面的代码:
Bitmap bm=BitmapFactory.decodeResource(getResources(),R.drawable.xxx);
可以看到此工具类非常方便,但是加载和显示图片是很消耗内存的一件事,BitmapFactory.Options 类允许我们定义图
片以何种方式如何读到内存。
inJustDecodeBounds:如果值设为true,那么将不返回实际的bitmap,也不给其分配内存空间,这样就避免了内存
溢出。但是允许我们查询图片的信息,这其中就包括图片的大小信息(options.outHeight(图片的原始高度)和
options.outWidth(图片的原始宽度))。
inSampleSize:我们可以充分利用它,实现缩放。如果设置为>1,要求解码器解码出原始图片的一个子样本,返回
一个较小的bitmap,以节省空间。例如,inSampleSize==2,则取出的缩略图的宽和高都是原始图片的1/2,图片的大
小就是原始图片的1/4。对于任何值<=1的同样处置为1.
看下面的例子:
import android.graphics.BitmapFactory;
import android.widget.Toast;
public class Decodenewbitmap {
public Bitmap decodebitmap(Context context, int imageid) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;// 如果值设为true,那么将不返回实际的bitmap,也不给其分配内存空间 这样就避免了内存溢出。
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),imageid, options);
if (bitmap == null) {
Toast.makeText(context, "bitmap为空", 2).show();//这里能出来,是因为options.inJustDecodeBou nds = true;
}
int realwidth = options.outWidth;
int realheight = options.outHeight;
System.out.println("图片真实高度" + realheight + "宽度" + realwidth);
// 计算缩放。
int scal = (int) ((realheight > realwidth ? realwidth : realheight) / 100);
if (scal <= 0) {
scal = 1;
}
options.inSampleSize = scal;
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeResource(context.getResources(), imageid,
options);
int w = bitmap.getWidth();
int h = bitmap.getHeight();
if (bitmap == null) {
Toast.makeText(context, "bitmap为空222", 3).show();
}
System.out.println("图片缩略图高度" + h + "宽度" + w);
return bitmap;
}
}
在Android 3.0开始,可设置BitmapFactory.options.inBitmap值,(从缓存中获取)达到重用Bitmap的目的。如果设
置,则inPreferredConfig属性值会被重用的Bitmap该属性值覆盖。
Options.inPurgeable和inInputShareable:inPurgeable:设置为True,则使用BitmapFactory创建的Bitmap用于存
储Pixel的内存空间,在系统内存不足时可以被回收,当应用需要再次访问该Bitmap的Pixel时,系统会再次调用
BitmapFactory 的decode方法重新生成Bitmap的Pixel数组。设置为False时,表示不能被回收。inInputShareable:
设置是否深拷贝,与inPurgeable结合使用,inPurgeable为false时,该参数无意义。
inTempStorage:当在android设备中载入较大图片资源时,可以创建一些临时空间,将载入的资源载入到临时空间
中。opts.inTempStorage = new byte[16 * 1024];
注意:decodeFileDescriptor()来生成bimap比decodeFile()省内存
原因:查看BitmapFactory的源码,对比一下两者的实现,可以发现decodeFile()最终是以流的方式生成bitmap
public static Bitmap decodeFile(String pathName, Options opts) {
Bitmap bm = null;
InputStream stream = null;
try {
stream = new FileInputStream(pathName);
bm = decodeStream(stream, null, opts);
} catch (Exception e) {
/* do nothing.
If the exception happened on open, bm will be null.
*/
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
// do nothing here
}
}
}
return bm;
}
ublic static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
if (nativeIsSeekable(fd)) {
Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
if (bm == null && opts != null && opts.inBitmap != null) {
throw new IllegalArgumentException("Problem decoding into existing bitmap");
}
return finishDecode(bm, outPadding, opts);
} else {
FileInputStream fis = new FileInputStream(fd);
try {
return decodeStream(fis, outPadding, opts);
} finally {
try {
fis.close();
} catch (Throwable t) {/* ignore */}
}
}
}
private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,Rect padding, Options opts);
public static OutputStream decodeBitmap(String path) {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;// 设置成了true,不占用内存,只获取bitmap宽高
BitmapFactory.decodeFile(path, opts);
opts.inSampleSize = computeSampleSize(opts, -1, 1024 * 800);
opts.inJustDecodeBounds = false;// 这里一定要将其设置回false,因为之前我们将其设置成了true
opts.inPurgeable = true;
opts.inInputShareable = true;
opts.inDither = false;
opts.inPurgeable = true;
opts.inTempStorage = new byte[16 * 1024];
FileInputStream is = null;
Bitmap bmp = null;
InputStream ins = null;
ByteArrayOutputStream baos = null;
try {
is = new FileInputStream(path);
bmp = BitmapFactory.decodeFileDescriptor(is.getFD(), null, opts); double scale = getScaling(opts.outWidth * opts.outHeight, 1024 * 600);
Bitmap bmp2 = Bitmap.createScaledBitmap(bmp,
(int) (opts.outWidth * scale),
(int) (opts.outHeight * scale), true);
bmp.recycle();
baos = new ByteArrayOutputStream();
bmp2.compress(Bitmap.CompressFormat.JPEG, 100, baos);
bmp2.recycle();
return baos;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
ins.close();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
System.gc();
}
return baos;
}
private static double getScaling(int src, int des) {
/**
* 目标尺寸÷原尺寸 sqrt开方,得出宽高百分比
*/
double scale = Math.sqrt((double) des / (double) src);
return scale;
}