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 图片操作相关推荐

  1. android 图片操作,Android图片操作(Bitmap)

    [java]  /** * 将多个Bitmap合并成一个图片. * * @param int 将多个图合成多少列 * @param Bitmap... 要合成的图片 * @return */ publ ...

  2. Android 图片文件操作、屏幕相关、.9图片的理解

     一:Android图片操作 1.存储bitmap到本地文件系统 public static void bitmapToFile(Bitmap bitmap, String uri) {if(!ext ...

  3. Android图片缓存之Lru算法

    前言: 上篇我们总结了Bitmap的处理,同时对比了各种处理的效率以及对内存占用大小.我们得知一个应用如果使用大量图片就会导致OOM(out of memory),那该如何处理才能近可能的降低oom发 ...

  4. Android图片处理

    相信做Android开发的小伙伴对于Android图片压缩.裁剪一定有很深的印象,今天我将带领大家一起学习一下这个看着高深莫测的知识,以便再以后的学习.工作中可以帮助到大家. 首先我们看一下这个问题出 ...

  5. FaceBook推出的Android图片载入库-Fresco

    欢迎关注ndroid-tech-frontier开源项目,定期翻译国外Android优质的技术.开源库.软件架构设计.測试等文章 原文链接:Introducing Fresco: A new imag ...

  6. android 图片分析,Android图片处理实例分析

    本文实例讲述了Android图片处理的方法.分享给大家供大家参考,具体如下: package cn.szbw.util; import Android.content.Context; import ...

  7. Android 图片异步加载的体会,SoftReference已经不再适用

    在网络上搜索Android图片异步加载的相关文章,目前大部分提到的解决方案,都是采用Map<String, SoftReference<Drawable>>  这样软引用的方式 ...

  8. android 图片拍照,Android获取图片拍照时间

    为什么写这篇文章是因为今早有个需求需要获取图片拍照时的时间进行一些处理,有些方法参数名忘记了,所以谷歌百度了一下,Android 图片 时间,Android 图片 拍照 时间,这几个关键字居然无法搜索 ...

  9. Android系统(74)--- 从零实现灵活且可高度定制的Android图片选择架构

    从零实现灵活且可高度定制的Android图片选择架构 https://www.jianshu.com/u/df76f81fe3ff 前言 这是我花费了数月闲暇时间从零开始写的一个库,在这期间,我学习到 ...

最新文章

  1. 自己录制的Oracle 相关视频(陆续更新)
  2. linux: convmv =-======pkgs.org
  3. vCenter功能基本介绍
  4. 【转】面向GC的Java编程
  5. 5g理论速度_5G网络相当于500M宽带是真的吗?
  6. javascript php 性能,浅谈页面装载js及性能分析方法_javascript技巧
  7. DataList分页访问FooterTemplate模板里的控件
  8. php分享十七:http状态码
  9. RHEL7及CentOS7的语言、字符编码、键盘映射、X11布局设置(localectl)-系统管理(1)...
  10. CentOS 6.5设置静态IP教程 并且可以ping通
  11. Redis内存数据库必读的4本书
  12. C语言编程学习gotoxy()与clrscr()函数
  13. 华为数通笔记-DHCPv6原理与实验
  14. 中国象棋马走日 — 递归
  15. web前端入门到实战:CSS 网格布局:网格线
  16. ENOVIA SmarTeam-CEO演讲PPT
  17. matlab中plot函数画线时 颜色和类型
  18. Centos 7 如何关闭提示(You have new mail in /var/spool/mail/root)
  19. 让人面到崩溃的特斯拉.NET工程师面试题
  20. 一次java.lang.ClassNotFoundException: org.apache.ibatis.session.SqlSession异常解决

热门文章

  1. layui根据name获取对象_JavaScript对象 - 初识
  2. Qt中多线程间的互斥
  3. 用java和汇编开发一个Hello World系统内核
  4. 同事查询多行_从零学会SQL-简单查询
  5. Java:继承之super关键字,继承之私有权限,继承之方法重写,继承之object类,继承之简单工厂模式
  6. dailykt爬取tushare 数据存入本地mysql
  7. 小农民在深山树林里发现古墓_河南周口一个县,总人口125万,境内有27处古墓群...
  8. access sql 取余_计算机二级ACCESS模拟题库2016最新
  9. 分计算iv值_S71200PLC模拟量编程方法与计算原理
  10. Leetcode 739. 每日温度 (每日一题 20211014)