Android中将bitmap转换成单色的BMP图片
2015-06-26 18:46
525 查看
最近想把bitmap转成单色的BMP图片,没有找到现成的方法,经过一番努力最终成功转换.
首先找到一篇文章,把bitmap转换成BMP图片 /article/4076286.html
发现博主转换的BMP图片为24位色的,而我需要的单色的.我看到博主转换成24位色的BMP图片时,给bitmap增加了一些数据,这些数据貌似是BMP图片的一些信息,所以找到一篇了BMP文件结构的文章
/article/6972367.html。发现在位图信息头里面有一个表示BMP图像的色深的字段。前面博主使用的是0x18
0x00 0x18转换成十进制为24所以生成的图片为24位的,想要生成单色的图片话把0x18改成0x01,图片就成了单色。又看到BMP文件结构里面有句话“彩色表/调色板(color table)是单色、16色和256色图像文件所特有的,相对应的调色板大小是2、16和256,调色板以4字节为单位,每4个字节存放一个颜色值,图像 的数据是指向调色板的索引。“因为24位色的BMP图片不存在调色板。如果我要改成单色的话就得加上一个大小为2的调色板,每个调色板的大小为4字节。在24位色中每3个字节表示一个点,而在单色中每个bit表示一个点。所以循环取到bitmap中每个像素点,(ps:在bitmap中每4个字节表示点),将每个点用1bit来表示。由于我在使用bitmap之前先将bitmap变成黑白色的,所以我只需要判断哪些像素点为黑色就将那个bit置为1。如此转换就将24位色的BMP图片转成了单色的BMP图片.
PS:原博主转换成BMP图片有个bug,BMP文件头中3-6字节表示BMP图像文件的大小,而原博主使用的是BMP图像数据大小,而位图信息头中21-24表示BMP图像数据大小而博主给的是0。这种情况下WINDOWS显示没问题,但是android系统识别文件大小为0。
以下附上源码,但是我的代码存在一个问题,BMP图像的宽度只能为N*8*4,BMP文件结构说明有这么一句话"
BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足",但是我补0了转换出来的BMP文件还是有问题,如果有知道原因的,还请留言告知...
附源码:
/**将bitmap转换成bmp格式图片
* @param bitmap 要转换的bitmap
* @param fos bmp文件输出流
*/
private void FormatBMP(Bitmap bitmap,FileOutputStream fos)
{
if (bitmap != null) {
int w = bitmap.getWidth(), h = bitmap.getHeight();
int[] pixels=new int[w*h];
bitmap.getPixels(pixels, 0, w, 0, 0, w, h);//取得BITMAP的所有像素点
byte[] rgb = addBMP_RGB_888(pixels,w,h);
byte[] header = addBMPImageHeader(62+rgb.length);
byte[] infos = addBMPImageInfosHeader(w, h,rgb.length);
byte[] colortable = addBMPImageColorTable();
byte[] buffer = new byte[62 + rgb.length];
System.arraycopy(header, 0, buffer, 0, header.length);
System.arraycopy(infos, 0, buffer, 14, infos.length);
System.arraycopy(colortable, 0, buffer, 54, colortable.length);
System.arraycopy(rgb, 0, buffer, 62, rgb.length);
try {
fos.write(buffer);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// BMP文件头
private byte[] addBMPImageHeader(int size) {
byte[] buffer = new byte[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[10] = 0x3E;
buffer[11] = 0x00;
buffer[12] = 0x00;
buffer[13] = 0x00;
return buffer;
}
// BMP文件信息头
private byte[] addBMPImageInfosHeader(int w, int h, int size) {
Log.i("_DETEST_", "size="+size);
byte[] buffer = new byte[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] = 0x01;
buffer[15] = 0x00;
buffer[16] = 0x00;
buffer[17] = 0x00;
buffer[18] = 0x00;
buffer[19] = 0x00;
buffer[20] = (byte) (size >> 0);
buffer[21] = (byte) (size >> 8);
buffer[22] = (byte) (size >> 16);
buffer[23] = (byte) (size >> 24);
// buffer[24] = (byte) 0xE0;
// buffer[25] = 0x01;
buffer[24] = (byte) 0xC3;
buffer[25] = 0x0E;
buffer[26] = 0x00;
buffer[27] = 0x00;
// buffer[28] = 0x02;
// buffer[29] = 0x03;
buffer[28] = (byte) 0xC3;
buffer[29] = 0x0E;
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;
return buffer;
}
private byte[] addBMPImageColorTable() {
byte[] buffer = new byte[8];
buffer[0] = (byte) 0xFF;
buffer[1] = (byte) 0xFF;
buffer[2] = (byte) 0xFF;
buffer[3] = 0x00;
buffer[4] = 0x00;
buffer[5] = 0x00;
buffer[6] = 0x00;
buffer[7] = 0x00;
return buffer;
}
private byte[] addBMP_RGB_888(int[] b, int w, int h) {
int len = w*h;
int bufflen = 0;
byte[] tmp = new byte[3];
int index = 0,bitindex = 1;
if (w*h % 8 != 0)//将8字节变成1个字节,不足补0
{
bufflen = w*h/ 8 + 1;
}
else
{
bufflen = w*h/ 8;
}
if (bufflen % 4 != 0)//BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足
{
bufflen = bufflen + bufflen%4;
}
byte[] buffer = new byte[bufflen];
for (int i = len - 1; i >= w; i -= w) {
// DIB文件格式最后一行为第一行,每行按从左到右顺序
int end = i, start = i - w + 1;
for (int j = start; j <= end; j++) {
tmp[0] = (byte) (b[j] >> 0);
tmp[1] = (byte) (b[j] >> 8);
tmp[2] = (byte) (b[j] >> 16);
String hex = "";
for (int g = 0; g < tmp.length; g++) {
String temp = Integer.toHexString(tmp[g] & 0xFF);
if (temp.length() == 1) {
temp = "0" + temp;
}
hex = hex + temp;
}
if (bitindex > 8)
{
index += 1;
bitindex = 1;
}
if (!hex.equals("ffffff"))
{
buffer[index] = (byte) (buffer[index] | (0x01 << 8-bitindex));
}
bitindex++;
}
}
return buffer;
}
首先找到一篇文章,把bitmap转换成BMP图片 /article/4076286.html
发现博主转换的BMP图片为24位色的,而我需要的单色的.我看到博主转换成24位色的BMP图片时,给bitmap增加了一些数据,这些数据貌似是BMP图片的一些信息,所以找到一篇了BMP文件结构的文章
/article/6972367.html。发现在位图信息头里面有一个表示BMP图像的色深的字段。前面博主使用的是0x18
0x00 0x18转换成十进制为24所以生成的图片为24位的,想要生成单色的图片话把0x18改成0x01,图片就成了单色。又看到BMP文件结构里面有句话“彩色表/调色板(color table)是单色、16色和256色图像文件所特有的,相对应的调色板大小是2、16和256,调色板以4字节为单位,每4个字节存放一个颜色值,图像 的数据是指向调色板的索引。“因为24位色的BMP图片不存在调色板。如果我要改成单色的话就得加上一个大小为2的调色板,每个调色板的大小为4字节。在24位色中每3个字节表示一个点,而在单色中每个bit表示一个点。所以循环取到bitmap中每个像素点,(ps:在bitmap中每4个字节表示点),将每个点用1bit来表示。由于我在使用bitmap之前先将bitmap变成黑白色的,所以我只需要判断哪些像素点为黑色就将那个bit置为1。如此转换就将24位色的BMP图片转成了单色的BMP图片.
PS:原博主转换成BMP图片有个bug,BMP文件头中3-6字节表示BMP图像文件的大小,而原博主使用的是BMP图像数据大小,而位图信息头中21-24表示BMP图像数据大小而博主给的是0。这种情况下WINDOWS显示没问题,但是android系统识别文件大小为0。
以下附上源码,但是我的代码存在一个问题,BMP图像的宽度只能为N*8*4,BMP文件结构说明有这么一句话"
BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足",但是我补0了转换出来的BMP文件还是有问题,如果有知道原因的,还请留言告知...
附源码:
/**将bitmap转换成bmp格式图片
* @param bitmap 要转换的bitmap
* @param fos bmp文件输出流
*/
private void FormatBMP(Bitmap bitmap,FileOutputStream fos)
{
if (bitmap != null) {
int w = bitmap.getWidth(), h = bitmap.getHeight();
int[] pixels=new int[w*h];
bitmap.getPixels(pixels, 0, w, 0, 0, w, h);//取得BITMAP的所有像素点
byte[] rgb = addBMP_RGB_888(pixels,w,h);
byte[] header = addBMPImageHeader(62+rgb.length);
byte[] infos = addBMPImageInfosHeader(w, h,rgb.length);
byte[] colortable = addBMPImageColorTable();
byte[] buffer = new byte[62 + rgb.length];
System.arraycopy(header, 0, buffer, 0, header.length);
System.arraycopy(infos, 0, buffer, 14, infos.length);
System.arraycopy(colortable, 0, buffer, 54, colortable.length);
System.arraycopy(rgb, 0, buffer, 62, rgb.length);
try {
fos.write(buffer);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// BMP文件头
private byte[] addBMPImageHeader(int size) {
byte[] buffer = new byte[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[10] = 0x3E;
buffer[11] = 0x00;
buffer[12] = 0x00;
buffer[13] = 0x00;
return buffer;
}
// BMP文件信息头
private byte[] addBMPImageInfosHeader(int w, int h, int size) {
Log.i("_DETEST_", "size="+size);
byte[] buffer = new byte[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] = 0x01;
buffer[15] = 0x00;
buffer[16] = 0x00;
buffer[17] = 0x00;
buffer[18] = 0x00;
buffer[19] = 0x00;
buffer[20] = (byte) (size >> 0);
buffer[21] = (byte) (size >> 8);
buffer[22] = (byte) (size >> 16);
buffer[23] = (byte) (size >> 24);
// buffer[24] = (byte) 0xE0;
// buffer[25] = 0x01;
buffer[24] = (byte) 0xC3;
buffer[25] = 0x0E;
buffer[26] = 0x00;
buffer[27] = 0x00;
// buffer[28] = 0x02;
// buffer[29] = 0x03;
buffer[28] = (byte) 0xC3;
buffer[29] = 0x0E;
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;
return buffer;
}
private byte[] addBMPImageColorTable() {
byte[] buffer = new byte[8];
buffer[0] = (byte) 0xFF;
buffer[1] = (byte) 0xFF;
buffer[2] = (byte) 0xFF;
buffer[3] = 0x00;
buffer[4] = 0x00;
buffer[5] = 0x00;
buffer[6] = 0x00;
buffer[7] = 0x00;
return buffer;
}
private byte[] addBMP_RGB_888(int[] b, int w, int h) {
int len = w*h;
int bufflen = 0;
byte[] tmp = new byte[3];
int index = 0,bitindex = 1;
if (w*h % 8 != 0)//将8字节变成1个字节,不足补0
{
bufflen = w*h/ 8 + 1;
}
else
{
bufflen = w*h/ 8;
}
if (bufflen % 4 != 0)//BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足
{
bufflen = bufflen + bufflen%4;
}
byte[] buffer = new byte[bufflen];
for (int i = len - 1; i >= w; i -= w) {
// DIB文件格式最后一行为第一行,每行按从左到右顺序
int end = i, start = i - w + 1;
for (int j = start; j <= end; j++) {
tmp[0] = (byte) (b[j] >> 0);
tmp[1] = (byte) (b[j] >> 8);
tmp[2] = (byte) (b[j] >> 16);
String hex = "";
for (int g = 0; g < tmp.length; g++) {
String temp = Integer.toHexString(tmp[g] & 0xFF);
if (temp.length() == 1) {
temp = "0" + temp;
}
hex = hex + temp;
}
if (bitindex > 8)
{
index += 1;
bitindex = 1;
}
if (!hex.equals("ffffff"))
{
buffer[index] = (byte) (buffer[index] | (0x01 << 8-bitindex));
}
bitindex++;
}
}
return buffer;
}
相关文章推荐
- 在Windows下搭建Android开发环境
- Android(Lollipop/5.0) Material Design(二) 入门指南
- Android 仿美团网,大众点评购买框悬浮效果之修改版
- android EditText控制光标的位置
- Android 控件的显示隐藏上下左右移动动画
- Android的monkey测试
- android 中一个工程引用另一个工程
- Android开发的一些坑
- android菜鸟学习笔记3----关于AndroidMainfest.xml
- Android 中LruCache 原理与编程
- 初用Android studio出现的问题
- android 巧妙利用反射机制得到ListView中的view
- Android基于wheelView的自定义日期选择器(可拓展样式)
- Android自定义对话框实现QQ退出界面
- android4.0蓝牙使能的详细解析 (转载)
- Android开发性能优化大总结
- Android之TextView的样式类Span的使用详解
- java代码中实现android背景选择的selector-StateListDrawable的应用
- Android 使用ViewPager和RadioGroup配合Fragment实现标签页,可点击按钮切换、滑动切换。
- Android ViewStub 布局延迟加载