高效地显示Bitmap图片

2024-06-18 02:32
文章标签 高效 显示 图片 bitmap

本文主要是介绍高效地显示Bitmap图片,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Loading Large Bitmaps Efficiently [有效地加载大尺寸位图]

  • 图片有不同的形状与大小。在大多数情况下它们的实际大小都比需要呈现出来的要大很多。例如,系统的Gallery程序会显示那些你使用设备camera拍摄的图片,但是那些图片的分辨率通常都比你的设备屏幕分辨率要高很多。
  • 考虑到程序是在有限的内存下工作,理想情况是你只需要在内存中加载一个低分辨率的版本即可。这个低分辨率的版本应该是与你的UI大小所匹配的,这样才便于显示。一个高分辨率的图片不会提供任何可见的好处,却会占用宝贵的(precious)的内存资源,并且会在快速滑动图片时导致(incurs)附加的效率问。
  • 这一课会介绍如何通过加载一个低版本的图片到内存中去decoding大的bitmaps,从而避免超出程序的内存限制。

Read Bitmap Dimensions and Type [读取位图的尺寸与类型]

  • BitmapFactory 类提供了一些decode的方法 (decodeByteArray()decodeFile()decodeResource(), etc.) 用来从不同的资源中创建一个Bitmap. 根据你的图片数据源来选择合适的decode方法. 那些方法在构造位图的时候会尝试分配内存,因此会容易导致OutOfMemory的异常。每一种decode方法都提供了通过BitmapFactory.Options 来设置一些附加的标记来指定decode的选项。设置 inJustDecodeBounds 属性为true可以在decoding的时候避免内存的分配,它会返回一个null的bitmap,但是 outWidthoutHeight 与 outMimeType 还是可以获取。这个技术可以允许你在构造bitmap之前优先读图片的尺寸与类型。
  1. BitmapFactory.Options options = new BitmapFactory.Options();  
  2. options.inJustDecodeBounds = true;  
  3. BitmapFactory.decodeResource(getResources(), R.id.myimage, options);  
  4. int imageHeight = options.outHeight;  
  5. int imageWidth = options.outWidth;  
  6. String imageType = options.outMimeType;  
  • 为了避免java.lang.OutOfMemory 的异常,我们在真正decode图片之前检查它的尺寸,除非你确定这个数据源提供了准确无误的图片且不会导致占用过多的内存。

Load a Scaled Down Version into Memory [加载一个按比例缩小的版本到内存中]

  • 通过上面的步骤我们已经知道了图片的尺寸,那些数据可以用来决定是应该加载整个图片到内存中还是加一个缩小的版本。下面有一些因素需要考虑:
    • 评估加载完整图片所需要耗费的内存。
    • 程序在加载这张图片时会涉及到其他内存需求。
    • 呈现这张图片的组件的尺寸大小。
    • 屏幕大小与当前设备的屏幕密度。
  • 例如,如果把一个原图是1024*768 pixel的图片显示到ImageView为128*96 pixel的缩略图就没有必要把整张图片都加载到内存中。
  • 为了告诉decoder去加载一个低版本的图片到内存,需要在你的BitmapFactory.Options 中设置 inSampleSize 为 true 。For example, 一个分辨率为2048x1536 的图片,如果设置 inSampleSize 为4,那么会产出一个大概为512x384的bitmap。加载这张小的图片仅仅使用大概0.75MB,如果是加载全图那么大概要花费12MB(前提都是bitmap的配置是 ARGB_8888). 下面有一段根据目标图片大小来计算Sample图片大小的Sample Code:
  1. public static int calculateInSampleSize(  
  2.             BitmapFactory.Options options, int reqWidth, int reqHeight) {  
  3.     // Raw height and width of image  
  4.     final int height = options.outHeight;  
  5.     final int width = options.outWidth;  
  6.     int inSampleSize = 1;  
  7.   
  8.     if (height > reqHeight || width > reqWidth) {  
  9.         if (width > height) {  
  10.             inSampleSize = Math.round((float)height / (float)reqHeight);  
  11.         } else {  
  12.             inSampleSize = Math.round((float)width / (float)reqWidth);  
  13.         }  
  14.     }  
  15.     return inSampleSize;  
  16. }  
  • Note: 设置 inSampleSize 为2的幂对于decoder会更加的有效率,然而,如果你打算把调整过大小的图片Cache到磁盘上,设置为更加接近的合适大小则能够更加有效的节省缓存的空间.
  • 为了使用这个方法,首先需要设置 inJustDecodeBounds 为 true, 把options的值传递过来,然后使用 inSampleSize 的值并设置 inJustDecodeBounds 为 false 来重新Decode一遍。
    1. public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,  
    2.         int reqWidth, int reqHeight) {  
    3.   
    4.     // First decode with inJustDecodeBounds=true to check dimensions  
    5.     final BitmapFactory.Options options = new BitmapFactory.Options();  
    6.     options.inJustDecodeBounds = true;  
    7.     BitmapFactory.decodeResource(res, resId, options);  
    8.   
    9.     // Calculate inSampleSize  
    10.     options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);  
    11.   
    12.     // Decode bitmap with inSampleSize set  
    13.     options.inJustDecodeBounds = false;  
    14.     return BitmapFactory.decodeResource(res, resId, options);  
    15. }  
    • 使用上面这个方法可以简单的加载一个任意大小的图片并显示为100*100 pixel的缩略图形式。像下面演示的一样:
    1. mImageView.setImageBitmap(  
    2.     decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100100));  
    • 你可以通过替换合适的BitmapFactory.decode* 方法来写一个类似的方法从其他的数据源进行decode bitmap。



  • public Bitmap

    inBitmap

    If set, decode methods that take the Options object will attempt to reuse this bitmap when loading content.

    public int

    inDensity

    The pixel density to use for the bitmap.

    public boolean

    inDither

    If dither is true, the decoder will attempt to dither the decoded image.

    public boolean

    inInputShareable

    This field works in conjuction with inPurgeable.

    public boolean

    inJustDecodeBounds

    If set to true, the decoder will return null (no bitmap), but the out…

    public boolean

    inMutable

    If set, decode methods will always return a mutable Bitmap instead of an immutable one.

    public boolean

    inPreferQualityOverSpeed

    If inPreferQualityOverSpeed is set to true, the decoder will try to decode the reconstructed image to a higher quality even at the expense of the decoding speed.

    publicBitmap.Config

    inPreferredConfig

    If this is non-null, the decoder will try to decode into this internal configuration.

    public boolean

    inPurgeable

    If this is set to true, then the resulting bitmap will allocate its pixels such that they can be purged if the system needs to reclaim memory.

    public int

    inSampleSize

    If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory.

    public boolean

    inScaled

    When this flag is set, if inDensity and inTargetDensity are not 0, the bitmap will be scaled to match inTargetDensity when loaded, rather than relying on the graphics system scaling it each time it is drawn to a Canvas.

    public int

    inScreenDensity

    The pixel density of the actual screen that is being used.

    public int

    inTargetDensity

    The pixel density of the destination this bitmap will be drawn to.

    public byte[]

    inTempStorage

    Temp storage to use for decoding.

    public boolean

    mCancel

    Flag to indicate that cancel has been called on this object.

    public int

    outHeight

    The resulting height of the bitmap, set independent of the state of inJustDecodeBounds.

    public String

    outMimeType

    If known, this string is set to the mimetype of the decoded image.

    public int

    outWidth

    The resulting width of the bitmap, set independent of the state of inJustDecodeBounds.

    这个表格是从android sdk文档里摘出来的,简单看一下说明就明白是什么意思了。
    下面我们回到我们的主题上来:怎样获取图片的大小?
    思路很简单:
    首先我们把这个图片转成Bitmap,然后再利用Bitmap的getWidth()和getHeight()方法就可以取到图片的宽高了。
    新问题又来了,在通过BitmapFactory.decodeFile(String path)方法将突破转成Bitmap时,遇到大一些的图片,我们经常会遇到OOM(Out Of Memory)的问题。怎么避免它呢?
    这就用到了我们上面提到的BitmapFactory.Options这个类。

    BitmapFactory.Options这个类,有一个字段叫做 inJustDecodeBounds 。SDK中对这个成员的说明是这样的:
    If set to true, the decoder will return null (no bitmap), but the out…
    也就是说,如果我们把它设为true,那么BitmapFactory.decodeFile(String path, Options opt)并不会真的返回一个Bitmap给你,它仅仅会把它的宽,高取回来给你,这样就不会占用太多的内存,也就不会那么频繁的发生OOM了。
    示例代码如下:

    1. BitmapFactory.Options options = new BitmapFactory.Options();
    2. options.inJustDecodeBounds = true;
    3. Bitmap bmp = BitmapFactory.decodeFile(path, options);

    复制代码

    这段代码之后,options.outWidth 和 options.outHeight就是我们想要的宽和高了。

    有了宽,高的信息,我们怎样在图片不变形的情况下获取到图片指定大小的缩略图呢?
    比如我们需要在图片不变形的前提下得到宽度为200的缩略图。
    那么我们需要先计算一下缩放之后,图片的高度是多少 

    1. int height = options.outHeight * 200 / options.outWidth;
    2. options.outWidth = 200;
    3. options.outHeight = height; 
    4. options.inJustDecodeBounds = false;
    5. Bitmap bmp = BitmapFactory.decodeFile(path, options);
    6. image.setImageBitmap(bmp);

    复制代码

    这样虽然我们可以得到我们期望大小的ImageView
    但是在执行BitmapFactory.decodeFile(path, options);时,并没有节约内存。
    要想节约内存,还需要用到BitmapFactory.Options这个类里的 inSampleSize 这个成员变量。
    我们可以根据图片实际的宽高和我们期望的宽高来计算得到这个值。

    1. inSampleSize = options.outWidth / 200;

    另外,为了节约内存我们还可以使用下面的几个字段:

    1. options.inPreferredConfig = Bitmap.Config.ARGB_4444;    // 默认是Bitmap.Config.ARGB_8888
    2. options.inPurgeable = true;
    3. options.inInputShareable = true;

这篇关于高效地显示Bitmap图片的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1071060

相关文章

C#实现将Excel表格转换为图片(JPG/ PNG)

《C#实现将Excel表格转换为图片(JPG/PNG)》Excel表格可能会因为不同设备或字体缺失等问题,导致格式错乱或数据显示异常,转换为图片后,能确保数据的排版等保持一致,下面我们看看如何使用C... 目录通过C# 转换Excel工作表到图片通过C# 转换指定单元格区域到图片知识扩展C# 将 Excel

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

使用Node.js制作图片上传服务的详细教程

《使用Node.js制作图片上传服务的详细教程》在现代Web应用开发中,图片上传是一项常见且重要的功能,借助Node.js强大的生态系统,我们可以轻松搭建高效的图片上传服务,本文将深入探讨如何使用No... 目录准备工作搭建 Express 服务器配置 multer 进行图片上传处理图片上传请求完整代码示例

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元

基于Python实现高效PPT转图片工具

《基于Python实现高效PPT转图片工具》在日常工作中,PPT是我们常用的演示工具,但有时候我们需要将PPT的内容提取为图片格式以便于展示或保存,所以本文将用Python实现PPT转PNG工具,希望... 目录1. 概述2. 功能使用2.1 安装依赖2.2 使用步骤2.3 代码实现2.4 GUI界面3.效

Python实现AVIF图片与其他图片格式间的批量转换

《Python实现AVIF图片与其他图片格式间的批量转换》这篇文章主要为大家详细介绍了如何使用Pillow库实现AVIF与其他格式的相互转换,即将AVIF转换为常见的格式,比如JPG或PNG,需要的小... 目录环境配置1.将单个 AVIF 图片转换为 JPG 和 PNG2.批量转换目录下所有 AVIF 图

详解如何通过Python批量转换图片为PDF

《详解如何通过Python批量转换图片为PDF》:本文主要介绍如何基于Python+Tkinter开发的图片批量转PDF工具,可以支持批量添加图片,拖拽等操作,感兴趣的小伙伴可以参考一下... 目录1. 概述2. 功能亮点2.1 主要功能2.2 界面设计3. 使用指南3.1 运行环境3.2 使用步骤4. 核

Java图片压缩三种高效压缩方案详细解析

《Java图片压缩三种高效压缩方案详细解析》图片压缩通常涉及减少图片的尺寸缩放、调整图片的质量(针对JPEG、PNG等)、使用特定的算法来减少图片的数据量等,:本文主要介绍Java图片压缩三种高效... 目录一、基于OpenCV的智能尺寸压缩技术亮点:适用场景:二、JPEG质量参数压缩关键技术:压缩效果对比

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整