Android中图片的读取,修改,显示和保存涉及到的类大致如图所示。

在读取图片文件时,先将图片文件转换为InputStream对象,然后通过BitmapFactory将其转换为Bitmap对象。 
在图片保存时,先将Bitmap对象转换为OutputStream对象,然后再将OutputStream输出到文件中。 
如果要对图片进行修改,可以通过将Bitmap对象转换为颜色数组(int[])来修改,也可以通过Canvas来修改。此外Bitmap类提供了一个createBitmap的静态方法,可以对Bitmap对象做一些转换。 
显示图片时,可以将Bitmap对象转换为Drawable对象,然后设置给ImageView。 
本文介绍图片文件的读取。

Android支持的图片格式

目前在Android中支持的图片文件格式如下。其中WebP格式是从Android4.0开始支持,但在Android4.0到Android4.2.1之间的Android系统不支持无损压缩和有透明度的WebP格式图片,Android4.2.1之后才开始支持所有的WebP格式图片。 
下图截取自http://developer.android.com/guide/appendix/media-formats.html 

读取图片文件到InputStream

1、读取SD卡中的图片到InputStream 
对SD卡中的文件,获取到文件的路径之后便可以通过FileInputStream类来生成InputStream。FileInputStream类是InputStream类的派生类。代码示例如下。

FileInputStream stream = new FileInputStream(fileName);
  • 1
  • 1

2、读取resource中的图片到InputStream 
对resource/drawable目录下的图片,每个文件都会在R文件中生成一个对应的整数id,通过“R.drawable.文件名”来得到id值,然后通过Resource类的openRawResource()来得到该文件对应的InputStream对象。代码示例如下。

InputStream strem = getResources().openRawResource(R.drawable.name);
  • 1
  • 1

3、读取assets中的图片到InputStream 
对assets目录中的图片,先通过getAssets()得到AssetManager对象,然后通过AssetManager对象的open方法来打开文件,得到该文件对应的InputStream对象。代码示例如下。

InputStream strem = getAssets().open("apple.png");
  • 1
  • 1

注意:如果图片在assets根目录,读取时只需要加图片文件名,不需要加/assets/,图片文件名需要包含扩展名。如果图片在assets的子目录中,需要加上子目录的路径,例如apple.png在/assert/fruit/spring/目录中,则open参数为”/fruit/spring/apple.png”。

4、 通过Uri读取图片到InputStream 
Uri全写是Universal Resource Identifier(通用资源标志符),Android系统中所有资源都可以用Uri来表示。在获取到资源的Uri后可以通过ContentResolver将其解析成InputStream对象。代码示例如下。

InputStream strem = getContentResolver().openInputStream(uri);
  • 1
  • 1

openInputStream()核心代码如下。

String scheme = uri.getScheme();
if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {OpenResourceIdResult r = getResourceId(uri);InputStream stream = r.r.openRawResource(r.id);return stream;
} else if (SCHEME_FILE.equals(scheme)) {return new FileInputStream(uri.getPath());
} else {AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r", null);return fd.createInputStream();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

这里openInputStream()内先判断Uri的scheme类型,如果是resource类型,则先调用getResourceId()得到该Uri对应的资源id,然后调用openRawResource()读取文件到InputStream对象。如果是文件类型,则调用uri.getPath()得到文件路径,然后调用FileInputStream()读取文件到InputStream对象。对其他类型(即assets类型)则调用openAssetFileDescriptor()先得到一个AssetFileDescriptor对象,然后再得到一个InputStream对象。 
可以看到,通过Uri读取图片的流程和上述根据类型直接读取大体是一样的(assets类型稍有不同)。

将InputStream转换为Bitmap

通过BitmapFactory的decodeStream()方法可以将InputStream转换为Bitmap对象。代码示例如下。

Bitmap bitmap = BitmapFactory.decodeStream(stream);
  • 1
  • 1

直接读取图片文件到Bitmap

上述流程是先将图片文件读取到InputStream中,然后将InputStream转换为Bitmap对象,需要两步。BitmapFactory提供了一些静态类可以直接将图片文件转换为Bitmap对象。 
直接读取SD卡中的图片到Bitmap示例代码如下。

Bitmap bitmap = BitmapFactory.decodeFile(fileName);
  • 1
  • 1

直接读取resource中的图片到Bitmap示例代码如下。

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), id);
  • 1
  • 1

BitmapFactory并没有提供直接读取assets中图片的api。 
查看BitmapFactory源码可以看到,BitmapFactory.decodeFile()和BitmapFactory.decodeResource()两个api都是先将SD卡或resource中的图片读取到InputStream,然后再调用BitmapFactory.decodeStream()来解析。由此可以看出,直接读取图片到Bitmap和先读取图片到InputStream,然后将InputStream转换为Bitmap本质上是一样的,只是BitmapFactory将这两步封装在一起。因此,如果要将非assets中的图片文件转换为Bitmap,一般就直接使用BitmapFactory即可。

BitmapFactory.Options

BitmapFactory在decode时可以传递一个Options参数,用来设置转换到Bitmap时的一些参数。 
BitmapFactory.Options中包含了一系列的public成员变量,每个成员变量代表一个转换参数。这里列出了BitmapFactory.Options类中定义的全部public成员变量。在BitmapFactory.Options类的注释中详细的描述了每个成员变量的含义。这里只介绍几个常用的成员变量的用法。

    public static class Options {public Bitmap inBitmap;public boolean inMutable;public boolean inJustDecodeBounds;public int inSampleSize;public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;public boolean inPremultiplied;public boolean inDither;public int inDensity;public int inTargetDensity;public int inScreenDensity;public boolean inScaled;public boolean inPurgeable;public boolean inInputShareable;public boolean inPreferQualityOverSpeed;public int outWidth;public int outHeight;public String outMimeType;public byte[] inTempStorage;public boolean mCancel;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

inJustDecodeBounds:此变量默认为false。当此变量被设置为true时,表示只对图片的Bound(图片的范围,也就是长宽包含的像素大小)进行解析,不生成Bitmap对象。在BitmapFactory.Options定义中可以看到有三个out开头的成员变量,outWidth,outHeight和outMimeType。当inJustDecodeBounds设置为true时,会分别将图片的宽度,高度和Mime类型保存到这三个成员变量中。 
inSampleSize:inSampleSize是一个整数,表示对图片像素的取样比例,即图片中每inSampleSize个像素取样后对应Bitmap中的一个像素。例如inSampleSize=2,表示图片中每两个像素对应Bitmap中的一个像素,转换后Bitmap的宽和高包含的像素个数是原图片的1/2,总像素个数是原图的1/4。inSampleSize=4,表示图片中每四个像素对应Bitmap中的一个像素,转换后Bitmap的宽和高包含的像素个数是原图片的1/4,总像素个数是原图的1/16。如果它小于1等于1,则表示完全取样,即图片中每个像素都会被提取保存到Bitmap中,转换后Bitmap的宽和高包含的像素个数和原图片相等。图片取样时只能按照2的整数次幂来取样,比如1,2,4,8,16……,如果inSampleSize不是2的整数次幂,则实际取样时使用和inSampleSize最接近的2的整数次幂来取样,比如inSampleSize= 10,和10最接近的2的整数次幂是8,因此会每8个像素取样一次。 
inPreferredConfig:表示图片中每个像素的保存方式。默认为Bitmap.Config.ARGB_8888,表示每个像素需要包含Alpha,R,G,B四个通道的信息,每个通道用8位来表示,也就是需要4个字节来保存一个像素。

图片文件读取注意事项

1、WebP图片格式问题 
虽然Android官方描述是在4.0之后开始支持WebP格式,但在4.0到4.2.1不支持有透明度设置和无损压缩的WebP格式图片。所以如果简单的判断,图片如果是WebP格式,且是4.0以上的系统,就通过BitmapFactory来解析,很可能会出现有些图片能解析,有些又不能解析的情况。此外,还有一些特殊机型,例如NokiaXL虽然是Android4.1的系统,但并不支持WebP编解码。因此,最好是从4.2系统开始用BitmapFactory来解析WebP格式的图片。 
2、解析大图时的OOM问题 
Android为每个应用分配的堆内存空间是有限的,如果应用请求的内存超过了限制,就会导致OOM。根据手机内存大小的不同,一般应用能够使用的堆内存在几十兆到两三百兆之间。然后应用在读取图片文件时非常消耗内存的,一张手机相机拍出的照片都有3M左右,如果每张图都直接读取,即使不造成OOM,也会导致频繁GC。还有些超大图一张就有几个G,如果直接读取肯定会导致OOM。为了避免读取大图时造成的OOM问题,并减少内存消耗,一般在读取图片时都需要根据图片尺寸来取样。也就是设置BitmapFactory.Options的inSampleSize属性。示例代码如下。

    Options options = new BitmapFactory.Options();//设置inJustDecodeBounds为true表示只获取大小,不生成Btimapoptions.inJustDecodeBounds = true;//解析图片大小InputStream stream = getContentResolver().openInputStream(uri);BitmapFactory.decodeStream(stream, null, options);stream.close();int width = options.outWidth;int height = options.outHeight;int ratio = 0;//如果宽度大于高度,交换宽度和高度if (width > height) {int temp = width;width = height;height = temp;}//计算取样比例it sampleRatio = Math.max(width/900, height/1600);//定义图片解码选项Options options = new Options();options.inSampleSize = sampleRatio;//读取图片,并将图片缩放到指定的目标大小InputStream stream = getContentResolver().openInputStream(uri);Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);stream.close();

android bitmap FileInputStream File转化相关推荐

  1. Android 将图片网址url转化为bitmap,drawable转bitmap,file转bitmap,bitmap转file

    file转bitmap File param = new File(); Bitmap bitmap= BitmapFactory.decodeFile(param.getPath()); drawa ...

  2. android Bitmap类方法属性 详细说明

    (转:http://blog.csdn.net/ymangu666/article/details/37729109) 1.  BitMap类 public void recycle()--回收位图占 ...

  3. android Bitmap 处理踩坑记

    吐槽 新项目用到外接的摄像头,摄像头抓拍后调用opencv做算法分析,总是运行一会直接jni error导致程序crash,试了好多方法结果发现是对接的摄像头多的原因(200万像素的3个摄像头一直开着 ...

  4. android bitmap 饱和度 demo,Android GPUImage实现多种图像滤镜效果

    前言 GPUImage 是iOS下一个开源的基于GPU的图像处理库,提供各种各样的图像处理滤镜,并且支持照相机和摄像机的实时滤镜.GPUImage for Android是它在Android下的实现, ...

  5. Android—Bitmap图片大小计算、压缩与三级缓存

    Bitmap对象占用内存大小: bitmap.getByteCount() 图片所占内存大小计算方式:图片长度 x 图片宽度 x 一个像素点占用的字节数. Android Bitmap使用的三种颜色格 ...

  6. android bitmap string,Android Bitmap到Base64字符串(Android Bitmap to Base64 String)

    Android Bitmap到Base64字符串(Android Bitmap to Base64 String) 如何将一个大的Bitmap(用手机相机拍摄的照片)转换为Base64 String? ...

  7. android 数据持久化——File

    在使用Java SE平台开发C/S结构的软件中,File 的IO输入输出流的使用率是非常高的,通过使用IO输入输出流可以对存储介质上的文件进行读写操作,下面的代码就是实现一个在Android平台上使用 ...

  8. Android文件存储编程实验,Android编程中File文件常见存储与读取操作demo示例

    本文实例讲述了Android编程中File文件常见存储与读取操作.分享给大家供大家参考,具体如下: MainActivity文件代码如下: package example.com.myapplicat ...

  9. (4.6.31)Android Bitmap 详解

    文章目录 一.从相册加载一张图片 1.1 打开相册加载图片 1.2 根据Uri得到Bitmap 二.Bitmap 内存计算方式 2.1 density 和 densityDpi 2.2 getByte ...

最新文章

  1. EdgeGallery — OpenStack VIM
  2. 少儿python编程培训-厦门在线儿童编程课
  3. C++继承机制下的析构函数
  4. 背包问题(动态规划)
  5. LeetCode MySQL 1543. Fix Product Name Format(trim去空格+upper/lower大小写)
  6. c语言 多文件 学生系统,编的学生成绩管理系统 从文件中读取保存数据总会多读入一组乱码数据...
  7. JDDroppableView
  8. java中soo_soo_ - SegmentFault 思否
  9. 区块链和加密货币产业_区块链:不仅仅用于加密货币
  10. pc控制iphone的软件_哪个备忘录便签app可以和PC电脑一块儿用
  11. HDU4675【GCD of scequence】【组合数学、费马小定理、取模】
  12. mysql writing to net_mysql 提示 Writing to net_MySQL
  13. 【应用安全技术】浅谈安卓开发代码混淆技术
  14. 阶段3 3.SpringMVC·_05.文件上传_4 文件上传之Springmvc方式上传代码
  15. C# 对IOC的理解 依赖的转移
  16. 前后端分离的思考与实践(四)
  17. 微信禁止模拟器登录怎么办?
  18. 算法笔记 A+B 输入输出练习VIII
  19. c语言用质因数分解法求最大公约数,分解质因数法求最大公约数(javascrip实现)
  20. 转 做自己的m3u8点播系统使用HTTP Live Streaming HLS技术)

热门文章

  1. 联想计算机电源维修,台式联想电脑,主机电源灯不亮是怎么回事,应该怎么维修...
  2. 电脑横机服务器维修,国产电脑横机操作和维修方法
  3. WML语言基础(WAP建站)一(转)
  4. 母牛python_使用Python解决母牛问题
  5. 批处理修改注册表调整输入法
  6. 计算机应用技术办公室自动化,办公室自动化的计算机处理技术应用研究
  7. 原生JS 实现投掷骰子效果
  8. 研究2:如何快速区分出游戏美术风格
  9. java 遍历阿斯克吗_java学习笔记
  10. kakfa的维护:Brock停止