原创博客,转载请注明出处:
http://blog.csdn.net/u011035622/article/details/50277565
首先先介绍一下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并通过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的官方源码部分:
/**
* Convenience method for calling {@link #reconfigure(int, int, Config)} with the current height and width.
*(警告不能用于当前bitmap=。=)
* 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将抛出,位图将不被修改。
/**
* 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.
*
* 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.
*
* The result of {@link #getByteCount()} will reflect the new configuration,
* while {@link #getAllocationByteCount()} will reflect that of the initial
* configuration.
*
* 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().
*
* 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.
*
* @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;
}