android图片保存,android 加载图片

Android图片压缩-大小与质量压缩以及图片保存

一、前言:

专注于为中小企业提供网站设计制作、成都网站制作服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业南京免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了上千家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。

2.质量压缩

注意:

第二次压缩之前都要先清空 baos.reset(); 再进行压缩 image.compress(Bitmap.CompressFormat.JPEG, quality, baos);

有时候我们采用质量压缩没有效果,有可能是每次压缩的质量过小,所以我们可以尝试修改压缩质量(quality)是10;

quality压缩机提示,0-100。0表示压缩

小尺寸,100意味着最大质量的压缩。一些

格式,如无损的PNG,将忽略质量设定;

3.混合方式压缩

链接:

android图像绘制——画布保存为图片

解释:

1、首先创建一个Bitmap图片,并指定大小;

2、在该图片上创建一个新的画布Canvas,然后在画布上绘制,并保存即可;

3、需要保存的目录File,注意如果写的目录如“/sdcard/akai/”如果不存在的话,要先创建(file.mkdirs()),否则FileOutputStream会报错No found;

4、需要添加权限:uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/

什么是画布呢 其实通过字面意思的理解就是用来绘画的地方,那么android里的画布是神马样子的呢?

在自定义画布中常用到下面3个类

Canvas

这些绘图方法中的每一个都需要指定一个Paint对象来渲染它

Paint

Paint也称为"刷子",Paint可以指定如何将基本图形绘制到位图上。

Paint类相当于一个笔刷和调色板。它可以选择如何使用上面描述的draw方法来渲染绘 制在画布上的基本图形。通过修改Paint对象,可以在绘图的时候控制颜色、样式、字体和特殊效果。最简单地,setColor可以让你选择一个Paint的颜色,而Paint对象的样式(使用setStyle控制)则可以决定是绘制绘图对象的轮廓(STROKE),还是只填充每一部 分(FILL),或者是两者都做(STROKE_AND_FILL)除了这些简单的控制之外,Paint类还支持透明度,另外,它也可以通过使用各种各样的阴影、过滤器和效果进行修改,从而提供由更丰富的、复杂的画笔和颜料组成的调色板。

从继承View类(或其子类)开始,并定义onDraw()回调方法。系统会调用该方法来完 成View对象自己的绘制请求。这也是通过Canvas对象来执行所有的图形绘制调用的地方,这个Canvas对象是由onDraw()回调方法传入的。

Android框架只在必要的时候才会调用onDraw()方法,每次请求应用程序准备完成图形 绘制任务时,必须通过调用invalidate()方法让该View对象失效。这表明可以在该View 对象上进行图形绘制处理了,然后Android系统会调用该View对象的onDraw()方(尽 管不保证该回调方法会立即被调用)。

在定制的View组件的onDraw()方法内部,使用给定的Canvas对象来完成所有的图形绘制处理(如Canvas.draw…()方法或把该Canvas对象作为参数传递给其他类的draw() 方法)。一旦onDraw()方法被执行完成,Android框架就会使用这个Canvas对象来绘制一个有系统处理的Bitmap对象。

下面是Paint一些常用方法:

Bitmap

Bitmap绘图的表面也称位图(这里详细说哈位图的功能)。

从资源中获取位图:

通过Resource的函数:InputStream openRawResource(int id)获取得到资源文件的数据流后,可以通过2种方式获得bitmap

使用BitmapDrawable :

使用BitmapDrawable(InputStream is)构造一个BitmapDrawable;

使用BitmapDrawable类的getBitmap()获取得到位图;

使用BitmapFactory使用BitmapFactory类decodeStream(InputStream is)解码位 图资源,获取位图BitmapFactory的所有函数都是static,这个辅助类可以通过资 源ID、路径、文件、数据流等方式来获取位图。

获取位图的信息

一般获取位图信息包括:位图大小、透明度、颜色格式等等,这些信息呢可以通过 三-一方法获取得到Bitmap就迎刃而解了,Android SDK中对Bitmap有详细说明,大家可以去详细了解哈。

显示位图

显示位图需要使用核心类Canvas,可以直接通过Canvas类的drawBirmap()显示位图,或者借助于BitmapDrawable来将Bitmap绘制到Canvas,下面的实例中会详细列举到

位图的缩放

位图的缩放,在Android SDK中提供了2种方法:

1:将一个位图按照需求重画一遍,画后的位图就是我们需要的了,与位图的显示几乎 一样:

drawBitmap(Bitmap bitmap, Rect src, Rectdst, Paint paint)

2:在原有位图的基础上,缩放原位图,创建一个新的位图:

createBitmap(Bitmap source, int x, int y,int width, int height, Matrix m, boolean filter)

位图旋转

位图的旋转,离不开Matrix。Android SDK提供了Matrix类,可以通过各种接口来设置 矩阵

android 处理图片工具

截取视频帧并转化为Bitmap

Android 保存图片到本地。

这里只介绍按下“保存”后如何将一个Bitmap对象保存为图片文件的执行步骤,对图片的下载,图片到Bitmap对象的转换,Bitmap对象的格式转换和压缩,以及界面设计部分全部都忽略了。

确定存储路径

获取外部存储权限

确定外部存储状态

确定文件名

保存到文件中

发送广播,通知系统扫描保存后的文件

确定存储路径

在Android中文件存储路径包括内部存储和外部存储两种类型。

对内部存储,当一个app被安装到手机后,Android系统会在内部存储的/data/data/目录下创建一个以包名称命名的文件夹。例如/data/data/com.sohu.inputmethod.sogou/。一个应用对内部存储的所有访问都被限制在这个文件夹中,也就是说Android应用只能在该目录中读取,创建,修改文件。对该目录之外的其他内部存储中的目录都没有任何操作的权限。因此,如果将图片保存在内部存储中,只能被应用自身读取,其他应用均无法读取。如果需要让系统图库,相册或其他应用能够找到保存的图片,必须将图片保存到外部存储中。

对外部存储,当一个app被安装到手机后,Android系统会在外部存储的/Android/data/目录下创建一个以包名命名的文件夹(这里第一个/不是根路径,而是相对外部存储所挂载路径的相对路径)。例如/storage/emulated/0/Android/data/com.sohu.inputmethod/。这个路径同样只能被应用自身读取,其他应用不能访问。因此,也不能将图片保存在这个目录中。

除外部存储的/Android目录之外的其他目录一般都是可以被其他应用访问的。目前,大多数应用都会在外部存储的根路径下建立一个类似包名的多层目录,以存储需要共享的文件。例如/storage/emulated/0/sogou/image/。还需要注意的是,很多查看图片的应用都支持按照文件夹来查看图片。如果将图片所在的文件夹取名为image,photo之类的,就无法和其他文件夹区分开,用户也不能识别该文件夹的用途。因此最好取一个有区分度的文件夹名字,例如百度贴吧就保存在/tieba目录,微信是保存在/tencent/MicroMsg/WeiXin目录。

由于Android系统的碎片化问题,不同设备上外部存储的路径很可能会不同,因此,不能直接使用/storage/emulated/0/作为外部存储的根路径。

Android SDK中 Environment类 提供了getExternalStorageDirectory()方法来获取外部存储的根路径。示例如下:

[java] view plain copy

String dir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tencent/MicroMsg/WeiXin/"

需要注意的是Environment.getExternalStorageDirectory()返回的路径中最后一个字符不是/,如果需要创建子目录,需要在子目录的前后都加上/。

获取外部存储权限

由于需要在外部存储中写文件,需要在AndroidManifest.xml中增加如下的权限声明。

[java] view plain copy

uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/

确定外部存储状态

由于外部存储需要被挂载,也可以被卸载,在写入文件之前,需要先判断外部存储的状态是否正常。只有状态正常情况下才可以执行保存文件的操作。获取外部存储状态同样是通过Environment类,通过Environment.getExternalStorageState()可以得到一个字符串,来表示外部存储的状态。同时在Environment类中定义了一系列的String常量表示不同的状态。在所有的状态中只有内部存储处于Environment.MEDIA_MOUNTED状态时才可以读写文件,因此,需要将获取到的状态和Environment.MEDIA_MOUNTED做比较,如果不是Environment.MEDIA_MOUNTED状态,就返回保存失败。示例如下。

[java] view plain copy

//获取内部存储状态

String state = Environment.getExternalStorageState();

//如果状态不是mounted,无法读写

if (!state.equals(Environment.MEDIA_MOUNTED)) {

return;

}

确定文件名

保存的图片文件名可以由应用根据自身需要自行确定,一般来说需要有一个命名规则,然后根据命名规则计算得到文件名。

这里列举几种常见的命名规则。

随机命名

这种命名规则是随机生成一个字符串或一组数字来对图片命名。

字符串可以通过UUID来生成,数字可以通过Random()类来生成,例如:

[java] view plain copy

//通过UUID生成字符串文件名

String fileName1 = UUID.randomUUID().toString();

//通过Random()类生成数组命名

Random random = new Random();

String fileName2 = String.valueOf(random.nextInt(Integer.MAX_VALUE));

这种命名规则是按照数字从小到大的顺序来对图片命名。

在程序启动时先获取图片文件名中当前最大数字的文件名,之后每保存一张图片就将数字加1即可。

时间命名

这种命名规则是根据保存图片的当前系统时间来对图片命名。

系统时间可以通过System.currentTimeMillis()来获取,不过System.currentTimeMillis()获取到的时间是一个long型的整数,如果用它做文件名,无法通过文件名直接看出文件的具体保存时间。可以通过SimpleDateFormat先对当前时间做格式化,然后再将其作为文件名来使用。例如:

[java] view plain copy

使用这种命名规则来命名需要注意的是同一秒钟可能会有多张图片需要保存,在得到当前系统时间对应的文件名后,需要判断该文件是否存在。如果文件已经存在,需要重新生成文件名。重新生成的文件名可以在之前的文件名后加上一个随机数后缀,或者是用毫秒数做后缀。

Calendar now = new GregorianCalendar();

SimpleDateFormat simpleDate = new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault());

String fileName = simpleDate.format(now.getTime());

文件URL命名

每张网络图片都有一个对应的图片URL,可以根据图片的URL来对图片命名。

不过URL中会包含一些不能用作文件名的特殊字符,此外直接用URL来命名可能会带来安全问题。为了避免这两个问题,可以将图片URL的MD5值作为文件名来使用。由于MD5是不可逆的,也就无法通过MD5值反向得到图片URL,同时MD5值对应的字符串只包含[0-9A-Z],不包含特殊字符,可是作为文件名使用。

由于每张图片的URL是唯一的,其对应的文件名也就是唯一的。如果需要每张网络图片只能生成一个文件,不允许保存为多份拷贝,可以用这种命名规则。在得到URL对应的文件名后,先判断文件是否已经存在,如果已经存在,直接覆盖或不处理。

保存到文件中

保存图片文件时,通过Bitmap的compress()方法将Bitmap对象压缩到一个文件输出流中,然后flush()即可。示例如下。

[java] view plain copy

try {

File file = new File(dir + fileName + ".jpg");

FileOutputStream out = new FileOutputStream(file);

mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);

out.flush();

out.close();

} catch (Exception e) {

e.printStackTrace();

}

发送广播,通知系统扫描保存后的文件

至此,已经实现将Bitmap对象保存成外部存储中的一个jpg格式的文件。但此时该文件只是保存在外部存储的一个目录中,必须进入其所在的目录中才可以看到。在系统图库,相册和其他应用中无法看到新建的图片文件。为了让其他应用能够知道图片文件被创建,必须通知MediaProvider服务将新建的文件添加到图片数据库中。

Android系统中常驻一个MediaProvider服务,对应的进程名为android.process.media,此服务用来管理本机上的媒体文件,提供媒体管理服务。在系统开机或者收到外部存储的挂载消息后,MediaProvider会调用MediaScanner,MediaScanner会扫描外部存储中的所有文件,根据文件类型的后缀将文件信息保存到对应的数据库中,供其他APP使用。

MediaScannerReceiver是一个广播接收者,当它接收到特定的广播请求后,就会去扫描指定的文件,并根据文件信息将其添加到数据库中。当图片文件被创建后,就可以发送广播给MediaScannerReceiver,通知其扫描新建的图片文件。示例如下。

[java] view plain copy

try {

File file = new File(dir + fileName + ".jpg");

FileOutputStream out = new FileOutputStream(file);

mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);

out.flush();

out.close();

//保存图片后发送广播通知更新数据库

Uri uri = Uri.fromFile(file);

sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));

} catch (Exception e) {

e.printStackTrace();

}

图片的异步保存

保存图片文件时,如果图片很大,或需要同时保存多张图片时,就需要较多的时间。为了避免阻塞UI线程,出现帧率下降或ANR,通常需要将图片保存操作放到线程中去执行。当图片保存完毕后通过sendMessage()方法通知UI线程保存结果。

将图片保存放到后台线程去执行需要增加一些同步机制避免一些多线程问题。例如有两张图片需要保存,分别放到两个线程中去执行,保存图片时文件名以数字顺序增加。第一个线程选中文件名为125.jpg,但此时文件还未创建,第二个线程判断125.jpg不存在,于是也选取125.jpg作为文件名,两张图片就保存到同一个文件中了。


本文题目:android图片保存,android 加载图片
本文路径:http://myzitong.com/article/dscgssg.html