[Android]修改Bitmap的Config格式设置及其Config参数源码阅读
2015-12-12 21:24
1171 查看
关于修改Bitmap的Config设置
原创博客,转载请注明出处:http://blog.csdn.net/u011035622/article/details/50277565
Bitmap.Config介绍
首先先介绍一下Config设置里面的参数吧,一方面让读者清楚,另一方面也是给自己加深印象。Bitmap.Config一共有四个参数如下:
(这些参数决定了Bitmap位图的配置,会影响到bitmap的像素如何、色彩、以及是否有透明度的能力)
Bitmap.Config ALPHA_8
这个参数每个像素占用1字节的空间。
它代表每个像素点被存储为单个透明度的通道,这对于设置遮罩的图片用例十分有用,它不存储颜色信息。
Bitmap.Config RGB_565
这个参数每个像素占用2字节的空间。
它代表只有RGB通道的编码,其中红色占用5位地址,绿色占用6位地址,蓝色占用5位地址。没有透明度的通道。
使用不透明的位图时,不要求高的色彩保真度使用此配置是不错的选择。
Bitmap.Config ARGB_4444
这个参数每个像素占用2字节的空间。
它一共有四个通道,顾名思义,分别是透明度、红、绿、蓝。每个通道分别占用四位地址,所以一共2字节。
当应用需要节省内存(对色彩质量要求低),同时又需要存储透明度信息,这个配置可以作为选择,但官方比较推荐用ARGB_8888的设置,因为这个的色彩质量差。
Bitmap.Config ARGB_8888
这个参数每个像素占用4字节的空间。
这也是一共4个通道,但不一样的是每个通道站8位地址,因而色彩质量比上一个设置高了特别特别多(16倍)。
能够满足最好的位图质量,在内存充足的情况下,十分推荐使用这个。
以下附参考的官方源码解释:
/** * Possible bitmap configurations. A bitmap configuration describes * how pixels are stored. This affects the quality (color depth) as * well as the ability to display transparent/translucent colors. */ public enum Config { // these native values must match up with the enum in SkBitmap.h /** * Each pixel is stored as a single translucency (alpha) channel. * This is very useful to efficiently store masks for instance. * No color information is stored. * With this configuration, each pixel requires 1 byte of memory. */ ALPHA_8 (1), /** * Each pixel is stored on 2 bytes and only the RGB channels are * encoded: red is stored with 5 bits of precision (32 possible * values), green is stored with 6 bits of precision (64 possible * values) and blue is stored with 5 bits of precision. * * This configuration can produce slight visual artifacts depending * on the configuration of the source. For instance, without * dithering, the result might show a greenish tint. To get better * results dithering should be applied. * * This configuration may be useful when using opaque bitmaps * that do not require high color fidelity. */ RGB_565 (3), /** * Each pixel is stored on 2 bytes. The three RGB color channels * and the alpha channel (translucency) are stored with a 4 bits * precision (16 possible values.) * * This configuration is mostly useful if the application needs * to store translucency information but also needs to save * memory. * * It is recommended to use {@link #ARGB_8888} instead of this * configuration. * * Note: as of {@link android.os.Build.VERSION_CODES#KITKAT}, * any bitmap created with this configuration will be created * using {@link #ARGB_8888} instead. * * @deprecated Because of the poor quality of this configuration, * it is advised to use {@link #ARGB_8888} instead. */ @Deprecated ARGB_4444 (4), /** * Each pixel is stored on 4 bytes. Each channel (RGB and alpha * for translucency) is stored with 8 bits of precision (256 * possible values.) * * This configuration is very flexible and offers the best * quality. It should be used whenever possible. */ ARGB_8888 (5); final int nativeInt; @SuppressWarnings({"deprecation"}) private static Config sConfigs[] = { null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888 }; Config(int ni) { this.nativeInt = ni; } static Config nativeToConfig(int ni) { return sConfigs[ni]; } }
以上第一部分只是介绍,而接下来的内容才是我想记录的内容。
修改Bitmap的Config设置
修改时遇到的问题
如果是本地图片路径的话,我们可以直接通过这样的方法得到一张bitmap并通过Options.inPreferredConfig来设置他的Config参数(如果你看一下BitmapFactory的源码,就会发现默认的就是Config.ARGB_8888格式)。Bitmap bitmap = null; File file = new File(path); if(file.exists()) { BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inPreferredConfig = Bitmap.Config.ARGB_8888; try { bitmap = BitmapFactory.decodeFile(path, opts); } catch (OutOfMemoryError error) { bitmap = null; } }
这并没有什么问题。
但是当我们已经有一张Bitmap了,如何修改他的Config设置呢,大家去看Bitmap里面的方法会发现有类似于setConfig或这reconfigure的方法(事实上前者调用的是后者的方法,后者调用的是native方法-nativeReconfigure)。
当看到这个方法时我直接的调用了它。
bitmap.setConfig(Bitmap.Config.ARGB_8888);
当然跪了。。
***AndroidRuntime: FATAL EXCEPTION:
main java.lang.NoSuchMethodError:android.graphics.Bitmap.reconfigure***
问题解决方法
折腾好一会不知道错哪里,点看源码看下才知道:setConfig、reconfigure方法不能用于目前使用的位图!!!=。=
(最后贴官方源码读者可以参考看看)
思考了一下,我们就只能先将当前的bitmap转位字节流,然后通过Bitmapfactory中的方法将这个字节流根据设置重新生成bitmap。
果然,问题解决:
/*传入bitmap参数,返回bitmap。*/ ByteArrayOutputStream dataByte = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, dataByte); BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inSampleSize = OPT_INSAMPLE_SIZE; opts.inPreferredConfig = Bitmap.Config.ARGB_8888; bitmap = BitmapFactory.decodeByteArray(dataByte.toByteArray(), 0, dataByte.size(), opts);
多次经历告诉我,学习时常常点进去看看源码和介绍真的很重要。决定找个时间把Bitmap和BitmapFactory的源码走一遍!
最后贴上setConfig的官方源码部分:
/** * <p>Convenience method for calling {@link #reconfigure(int, int, Config)} with the current height and width.</p> *(警告不能用于当前bitmap=。=) * <p>WARNING: this method should not be used on bitmaps currently used by the view system, see {@link #reconfigure(int, int, Config)} for more details. */ public void setConfig(Config config) { reconfigure(getWidth(), getHeight(), config); }
reconfigure:
这里还讲到:
1、修改Bitmap可能会影响到hasalpha,即格式转变可能有或没有透明通道。
2、如果位图的配置不够大,支持新的配置,IllegalArgumentException将抛出,位图将不被修改。
/** * <p>Modifies the bitmap to have a specified width, height, and {@link * Config}, without affecting the underlying allocation backing the bitmap. * Bitmap pixel data is not re-initialized for the new configuration.</p> * * <p>This method can be used to avoid allocating a new bitmap, instead * reusing an existing bitmap's allocation for a new configuration of equal * or lesser size. If the Bitmap's allocation isn't large enough to support * the new configuration, an IllegalArgumentException will be thrown and the * bitmap will not be modified.</p> * * <p>The result of {@link #getByteCount()} will reflect the new configuration, * while {@link #getAllocationByteCount()} will reflect that of the initial * configuration.</p> * * <p>Note: This may change this result of hasAlpha(). When converting to 565, * the new bitmap will always be considered opaque. When converting from 565, * the new bitmap will be considered non-opaque, and will respect the value * set by setPremultiplied().</p> * * <p>WARNING: This method should NOT be called on a bitmap currently used * by the view system. It does not make guarantees about how the underlying * pixel buffer is remapped to the new config, just that the allocation is * reused. Additionally, the view system does not account for bitmap * properties being modifying during use, e.g. while attached to * drawables.</p> * * @see #setWidth(int) * @see #setHeight(int) * @see #setConfig(Config) */ public void reconfigure(int width, int height, Config config) { checkRecycled("Can't call reconfigure() on a recycled bitmap"); if (width <= 0 || height <= 0) { throw new IllegalArgumentException("width and height must be > 0"); } if (!isMutable()) { throw new IllegalStateException("only mutable bitmaps may be reconfigured"); } if (mBuffer == null) { throw new IllegalStateException("native-backed bitmaps may not be reconfigured"); } nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length, mRequestPremultiplied); mWidth = width; mHeight = height; }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories