android Bitmap 存储为 bmp

来源:互联网 发布:手机看淘宝实名认证了 编辑:程序博客网 时间:2024/05/18 03:59

最近的项目,做图片的另存为功能,需要把图片存成jpg,png,bmp。对于jpg和png来说相对简单,android提供了bitmap.compress()方法可以马上解决。但是对于BMP这种格式,没有很好的支持。我花了几天时间在网上找了很久,都没有找到有用的答案,同样也发了疑问,没有合适的解答。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
packagecom.test.bitmap;
 
importjava.io.FileNotFoundException;
importjava.io.FileOutputStream;
importjava.io.IOException;
 
importandroid.app.Activity;
importandroid.graphics.Bitmap;
importandroid.os.Bundle;
importandroid.os.Environment;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.ImageView;
 
publicclass Mainactivity extendsActivity {
ImageView img;
 
@Override
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn = (Button) findViewById(R.id.sd);
img = (ImageView) findViewById(R.id.img1);
btn.setOnClickListener(newOnClickListener() {
 
@Override
publicvoid onClick(View v) {
// TODO Auto-generated method stub
View view = v.getRootView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
if(bitmap != null) {
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
// bitmap.compress(CompressFormat.PNG, 90, bos); 只能转成PNG、JPEG
// byte[] data = bos.toByteArray();
// img.setImageBitmap(BitmapFactory.decodeByteArray(data, 0,
// data.length));
intw = bitmap.getWidth(), h = bitmap.getHeight();
int[] pixels=newint[w*h];
bitmap.getPixels(pixels,0, w, 0,0, w, h);
 
 
// ByteBuffer dst = ByteBuffer.allocate(bitmap.getRowBytes()
// * h);
// bitmap.copyPixelsToBuffer(dst);
 
 
// IntBuffer dst=IntBuffer.allocate(w*h);
// bitmap.copyPixelsToBuffer(dst);
 
 
byte[] rgb = addBMP_RGB_888(pixels,w,h);
byte[] header = addBMPImageHeader(rgb.length);
byte[] infos = addBMPImageInfosHeader(w, h);
 
 
byte[] buffer = newbyte[54+ rgb.length];
System.arraycopy(header,0, buffer, 0, header.length);
System.arraycopy(infos,0, buffer, 14, infos.length);
System.arraycopy(rgb,0, buffer, 54, rgb.length);
try{
FileOutputStream fos = newFileOutputStream(Environment
.getExternalStorageDirectory().getPath()
+"/hello.bmp");
fos.write(buffer);
}catch(FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
}
 
 
//BMP文件头
privatebyte[] addBMPImageHeader(intsize) {
byte[] buffer = newbyte[14];
buffer[0] = 0x42;
buffer[1] = 0x4D;
buffer[2] = (byte) (size >> 0);
buffer[3] = (byte) (size >> 8);
buffer[4] = (byte) (size >> 16);
buffer[5] = (byte) (size >> 24);
buffer[6] = 0x00;
buffer[7] = 0x00;
buffer[8] = 0x00;
buffer[9] = 0x00;
buffer[10] = 0x36;
buffer[11] = 0x00;
buffer[12] = 0x00;
buffer[13] = 0x00;
returnbuffer;
}
 
 
//BMP文件信息头
privatebyte[] addBMPImageInfosHeader(intw, inth) {
byte[] buffer = newbyte[40];
buffer[0] = 0x28;
buffer[1] = 0x00;
buffer[2] = 0x00;
buffer[3] = 0x00;
buffer[4] = (byte) (w >> 0);
buffer[5] = (byte) (w >> 8);
buffer[6] = (byte) (w >> 16);
buffer[7] = (byte) (w >> 24);
buffer[8] = (byte) (h >> 0);
buffer[9] = (byte) (h >> 8);
buffer[10] = (byte) (h >> 16);
buffer[11] = (byte) (h >> 24);
buffer[12] = 0x01;
buffer[13] = 0x00;
buffer[14] = 0x18;
buffer[15] = 0x00;
buffer[16] = 0x00;
buffer[17] = 0x00;
buffer[18] = 0x00;
buffer[19] = 0x00;
buffer[20] = 0x00;
buffer[21] = 0x00;
buffer[22] = 0x00;
buffer[23] = 0x00;
buffer[24] = (byte)0xE0;
buffer[25] = 0x01;
buffer[26] = 0x00;
buffer[27] = 0x00;
buffer[28] = 0x02;
buffer[29] = 0x03;
buffer[30] = 0x00;
buffer[31] = 0x00;
buffer[32] = 0x00;
buffer[33] = 0x00;
buffer[34] = 0x00;
buffer[35] = 0x00;
buffer[36] = 0x00;
buffer[37] = 0x00;
buffer[38] = 0x00;
buffer[39] = 0x00;
returnbuffer;
}
 
 
privatebyte[] addBMP_RGB_888(int[] b,intw, inth) {
intlen = b.length;
System.out.println(b.length);
byte[] buffer = newbyte[w*h * 3];
intoffset=0;
for(inti = len-1; i>=w; i-=w) {
//DIB文件格式最后一行为第一行,每行按从左到右顺序
intend=i,start=i-w+1;
for(intj=start;j<=end;j++){
buffer[offset]=(byte)(b[j]>>0);
buffer[offset+1]=(byte)(b[j]>>8);
buffer[offset+1]=(byte)(b[j]>>16);
offset += 3;
}
}
returnbuffer;
}
}

但是我按照这种方法使用之后,保存之后的图片与原来的相比会有很大的颜色差距,详细看附件。
所以我就遇到了新的麻烦,下载了一个UltraEdit软件,然后把保存前的bmp图片 和 保存后的bmp图片 使用UltraEdit打开。分析bmp图片的格式。我从网上找到了一份非常好的说明,详细中文版分析请看附件。提供两个网址,关于bmp格式的分析的:
http://www.jb51.net/article/78186.htm
http://www.jb51.net/article/78187.htm
图像文件头
  1)1-2:(这里的数字代表的是"字",即两个字节,下同)图像文件头。0x4d42='BM',表示是Windows支持的BMP格式。(注意:查ascii表B 0x42,M0x4d,bfType 为两个字节,B为low字节,M为high字节所以bfType=0x4D42,而不是0x424D,但注意)
  2)3-6:整个文件大小。4690 0000,为00009046h=36934。
  3)7-8:保留,必须设置为0。
  4)9-10:保留,必须设置为0。
  5)11-14:从文件开始到位图数据之间的偏移量(14+40+4*(2^biBitCount))。4600 0000,为00000046h=70,上面的文件头就是35字=70字节。

位图信息头

  6)15-18:位图图信息头长度。
  7) 19-22:位图宽度,以像素为单位。8000 0000,为00000080h=128。
  8)23-26:位图高度,以像素为单位。9000 0000,为00000090h=144。
  9)27-28:位图的位面数,该值总是1。0100,为0001h=1。
  10)29-30:每个像素的位数。有1(单色),4(16色),8(256色),16(64K色,高彩色),24(16M色,真彩色),32(4096M色,增强型真彩色)。1000为0010h=16。
  11)31-34:压缩说明:有0(不压缩),1(RLE 8,8位RLE压缩),2(RLE 4,4位RLE压缩,3(Bitfields,位域存放)。RLE简单地说是采用像素数+像素值的方式进行压缩。T408采用的是位域存放方式,用两个字节表示一个像素,位域分配为r5b6g5。图中0300 0000为00000003h=3。
  12)35-38:用字节数表示的位图数据的大小,该数必须是4的倍数,数值上等于(≥位图宽度的最小的4的倍数)×位图高度×每个像素位数。0090 0000为00009000h=80×90×2h=36864。
  13)39-42:用象素/米表示的水平分辨率。A00F 0000为0000 0FA0h=4000。
  14)43-46:用象素/米表示的垂直分辨率。A00F 0000为0000 0FA0h=4000。
  15)47-50:位图使用的颜色索引数。设为0的话,则说明使用所有调色板项。
  16)51-54:对图象显示有重要影响的颜色索引的数目。如果是0,表示都重要。 

这54位信息非常重要,所以我做了一个尝试,验证是否是因为bmp图片的头信息的不同,造成了颜色的偏差呢?实验方法如下:其实很简单,第一步把保存前和保存后的bmp图片使用UltraEdit打开,把保存前的bmp图片的头即前54位的值,复制,粘贴到保存后的图片的头部,这样两张图的头信息都是保存前的那张图片的头。然后ctrl+s一下保存后的那张图片,再打开发现图片并没有变化。第一步,这回做相反的操作,即把保存后的bmp图片的头即前54位的值,复制,粘贴到保存前的图片的头部,发现也是没有变化,说明文件头不是影响颜色差异的原因。
此时只剩下 代码中: byte[] rgb = addBMP_RGB_888(pixels,w,h);此处的问题了,进入这个函数,仔细阅读,发现正是存储颜色信息的地方。 读下代码发现,原作者的代码有个bug。此处: buffer[offset+1]=(byte)(b[j]>>16); 应该是buffer[offset+2]=(byte)(b[j]>>16); 即offset应该是+2,而非加1。更正错误之后,重新运行一下,发现保存后的图片颜色恢复正常,与原图片颜色相同,问题解决。

总结:不知道为什么经常遇到一些,网上很常见,但是却找不到合适我的问题的解决办法,很郁闷,网上很多的链接都是指向这个地址,但是进去了却没有更详细的说明。很遗憾,也很懊恼。希望网上能多分享些有用的,可行的解决方案,这对大家都有好处,免得浪费大家的搜索时间。

这里珍惜感谢csdn的那个博主,解决了我的问题。当然,使用别人的代码,也要多思考,不要轻易完全相信。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 几天几夜睡不着觉没有睡意怎么办 辣的吃多了胃疼怎么办 喉咙痛怎么办有最好即简单好得快 减肥过后皮肤留下的肥胖纹怎么办 用了完美玛丽艳脸上长痘痘怎么办 腰疼怎么办8方法解决腰疼 红米3x开不了机怎么办 苹果手机忘记了锁屏密码怎么办 小米5的4g网速慢怎么办 红米4a卡机了怎么办 信而富逾期3个月怎么办 苹果6锁屏密码忘了怎么办 孕8个月咳嗽有痰怎么办 微信红包输了6万怎么办 红米3s开不了机怎么办 核载5人载了6人怎么办 我欠支付宝2万6怎么办 我47岁这个月经不来怎么办 两个月不来月经了也没怀孕怎么办 婴儿不吃奶粉母乳又不够吃怎么办 怀孕39周了还没反应怎么办 脸过敏了又红又痒怎么办 刚开的淘宝店没生意怎么办 我22岁长得显老怎么办 卡的钱被qq转走怎么办 招行u盾密码忘了怎么办 孩子上五年级了成绩非常差怎么办 红米3s开不开机怎么办 皮肤被虫子咬了红肿痒怎么办 微信被骗了1万多怎么办 6个月宝宝吃了纸怎么办 农行k宝扣了50块怎么办 4g流量用的太快怎么办 怀疑老公有外遇最明智的怎么办 咽喉疼怎么办最简单的方法如下 生完孩子后腰疼的厉害怎么办 眼睛进东西了弄不出来怎么办 18k金不给换黄金怎么办 我22岁欠了10万怎么办 1岁宝宝又吐又拉怎么办 月经10天了还没干净怎么办