`
功夫小当家
  • 浏览: 186134 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android中如何把bitmap存成BMP格式的图片

阅读更多

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

 

不过,无意间发现了一篇blog , http://blog.csdn.net/zhaokaidong3/article/details/7776238,代码如下:

 

package com.test.bitmap;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;


public class Mainactivity extends Activity {
ImageView img;


@Override
public void 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(new OnClickListener() {


@Override
public void 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));
int w = bitmap.getWidth(), h = bitmap.getHeight();
int[] pixels=new int[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 = new byte[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 = new FileOutputStream(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文件头
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[11] = 0x00;
buffer[12] = 0x00;
buffer[13] = 0x00;
return buffer;
}


//BMP文件信息头
private byte[] addBMPImageInfosHeader(int w, int h) {
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] = 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;
return buffer;
}


private byte[] addBMP_RGB_888(int[] b,int w, int h) {
int len = b.length;
System.out.println(b.length);
byte[] buffer = new byte[w*h * 3];
int offset=0;
for (int i = len-1; i>=w; i-=w) {
//DIB文件格式最后一行为第一行,每行按从左到右顺序
int end=i,start=i-w+1;
for(int j=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;
}
}
return buffer;
}
}

 

 

但是我按照这种方法使用之后,保存之后的图片与原来的相比会有很大的颜色差距,详细看附件

所以我就遇到了新的麻烦,下载了一个UltraEdit软件,然后把保存前的bmp图片 和 保存后的bmp图片 使用UltraEdit打开。分析bmp图片的格式。我从网上找到了一份非常好的说明,详细中文版分析请看附件。提供两个网址,关于bmp格式的分析的:http://blog.csdn.net/q673327335/article/details/8432384, 

http://blog.csdn.net/wen0006/article/details/6195311

 

 

图像文件头

  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。更正错误之后,重新运行一下,发现保存后的图片颜色恢复正常,与原图片颜色相同,问题解决。

 

 

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

 

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

 

 

 

 

  • 大小: 1.9 MB
  • 大小: 1.6 MB
  • 大小: 138.9 KB
2
0
分享到:
评论
1 楼 zfc645486908 2013-05-05  
您好,感谢你写这篇技术文章,对我帮助很大,刚好用到,但是我需要存储的是灰度的bmp图像,需要怎么修改,恳请指点, 谢谢!急啊~

相关推荐

    Android中把bitmap存成BMP格式图片的方法

    在Android开发中,有时我们需要将Bitmap对象转换成不同的图片格式,比如BMP。BMP(Bitmap File Format)是一种常见的位图文件格式,但它并不像JPEG或PNG那样被Android SDK直接支持。本文将详细介绍如何在Android中将...

    Android中将Bitmap转换成单色的Bmp图片

    Android不支持将Bitmap转换成单色的Bmp图片,所以参考Bmp格式说明,自己写了一个转换类。亲测有效!!!

    Android 实现把bitmap图片的某一部分的颜色改成其他颜色

    首先,我们需要了解什么是 bitmap 图片,bitmap 图片是一种图像存储格式,它将图像分割成一个个像素,然后将每个像素的颜色值存储在内存中,以便于图像的处理和显示。 在 Android 中,我们可以使用 Bitmap 类来处理...

    图片转化单色,位深度为1的BMP文件

    4. **保存为BMP格式**:最后,将处理后的二值图像以BMP格式保存,设置位深度为1。在BMP文件结构中,数据部分是以行优先的方式存储,每行像素是右对齐的,不足的部分用0填充。 这个过程中可能遇到的问题包括图像边缘...

    android Bitmap相关知识介绍~~~

    Android 中的 Bitmap 是一种特殊的类,它不能被直接创建,而只能通过 BitmapFactory 来获取。BitmapFactory 提供了多种方法来从不同的图像来源中获取 Bitmap,下面是其中的一些: 1. 从资源文件中获取 Bitmap 可以...

    android Bitmap用法总结

    Bitmap是Android平台中用于处理图像的核心类,它用于表示位图图像数据。下面是对Bitmap用法的详细总结: 1. **Drawable转换为Bitmap**: 当我们需要将一个Drawable对象(如从XML布局文件中加载的图像)转换为...

    Android Drawable、Bitmap、byte、灰度 转换

    在Android开发中,图片资源的处理是常见的需求之一,涉及到多种数据类型之间的转换,包括`Drawable`、`Bitmap`、`byte[]`等。本文将详细介绍这些类型之间的转换方法,以及如何实现灰度图像的转换。 ### 1. `...

    图片格式 NV21 转 RGB24 和 BMP图片源码(C语言)。

    6. **直接可用**:提供的源码应该是经过测试的,可以直接在C编译环境中运行,将输入的NV21图像数据转换成RGB24或BMP格式的输出文件。 7. **实际应用**:这种转换功能在视频处理、图像分析、手机应用开发等领域都有...

    android平台jpeg数据流转换成rgb直接用bitmap显示数据的so库

    android平台jpeg数据流转换成rgb直接显示的so库 使用方式: byte[] jpegRaw = V4L2Camera.decode(dataBuf, ret); rgb2Buffer(jpegRaw, WIDTH, HEIGHT, rgbBuffer); ByteBuffer jpegBuffer = ByteBuffer.wrap(rgb...

    Wlt2BmpDemo.rar_java wlt转jpg_wlt bmp_wlt图片转换_wlt文件_wlt转jpg

    android jni 将wlt图片转成bmp格式图片,支持32位armeabi架构手机

    Android bitmap

    位图(Bitmap)是Android开发中不可或缺的部分,它用于表示图像数据。Bitmap类是Android系统提供的用于处理图像的主要类,但需要注意的是,Bitmap对象本身并不直接创建,而是通过BitmapFactory类来解析并创建。...

    Bitmap图像转换为H264

    Bitmap(BMP)是一种无损的图像文件格式,它以原始的像素数据存储图像,占用的存储空间较大,不适合在网络传输和存储中使用。而H264(也称为AVC,Advanced Video Coding)是一种高效的视频编码标准,能够以较小的...

    Android开发者学习笔记——View、Canvas、bitmap

    需要注意的是,Bitmap 还提供了 compress() 接口来压缩图片,不过 AndroidSDK 只支持 PNG、JPG 格式的压缩。 显示位图 显示位图可以使用核心类 Canvas,通过 Canvas 类的 drawBitmap() 显示位图,或者借助于 ...

    Android应用开发详解(原始BMP文件编号)

    在Android应用开发中,原始BMP(Bitmap)文件是一个重要的图像格式,用于存储位图图像。BMP文件是未经过压缩的,因此它们通常比其他压缩格式如JPEG或PNG更大,但提供了无损的图像质量。这篇“Android应用开发详解...

    Android Drawable、Bitmap、byte、灰度 之间的转换

    在Android开发中,图片资源的处理是常见的需求之一,尤其涉及到不同格式间的转换,如Drawable、Bitmap、byte数组以及灰度图像的转换。这些转换在实际应用中具有重要意义,不仅能够优化内存使用,还能实现图像的高效...

    bmp格式转rle

    "android logo 图片格式转换,bmp格式转rle格式"这个任务就是将Android系统的标识或类似图片从BMP格式转换为RLE编码的格式,以减小文件大小,提高加载速度和节省存储空间。 BMP格式详解: BMP文件头包含有关图像的...

    bmp图片格式转换为JPG图片格式的javat程序

    8. **色彩空间转换**:BMP格式通常使用RGB色彩空间,而JPEG可能使用YCbCr或YCCK等色彩空间。在转换过程中,可能需要进行色彩空间的转换。 9. **质量设置**:在`ImageIO.write()`方法中,可以通过`ImageWriteParam`...

    android bitMap

    本文详细介绍了Android中`Bitmap` 的基本操作方法,包括从资源中加载、转换为字节数组、字节数组转换为`Bitmap`、缩放、将`Drawable` 转换为`Bitmap`以及获取圆角图片。这些操作对于处理图像数据非常重要,是每个...

    Yv12 nv21 yuv420 转换为Bitmap

    Camera onPreview中byte[] 转换为Bitmap 在录像时设置了YV12要保存图片时 YV12或者NV12时要转换时所用的工具的优化

Global site tag (gtag.js) - Google Analytics