您的位置:首页 > 移动开发 > Android开发

[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android Bitmap Config 源码