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

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

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://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)

相关推荐

  • Android中使用Bitmap类将矩形图片转为圆形的方法

    一般要做正圆形图片,只能是正方形的基础上才能实现,否则就变成椭圆了,下面说说如何使长方形的图片生成正圆形图片 废话不多说,没图没真相,先上图吧: 原图: 变成正圆后: 下面上代码: public static Bitmap makeRoundCorner(Bitmap bitmap) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); int left = 0, top = 0, right = width, bot

  • Android App开发中将View或Drawable转为Bitmap的方法

    View转换为Bitmap Android中经常会遇到把View转换为Bitmap的情形,比如,对整个屏幕视图进行截屏并生成图片:Coverflow中需要把一页一页的view转换为Bitmap.以便实现复杂的图形效果(阴影.倒影效果等):再比如一些动态的实时View为便于观察和记录数据.需要临时生成静态的Bitmap. 实现方法: 1)下面是笔者经常用的一个转换方法 public static Bitmap convertViewToBitmap(View view, int bitmapWid

  • Android Bitmap压缩方法的选择详解

    刚刚修改Bug碰到了一个问题,先描述一下问题. 1.测试说分享文章到微信失败,QQ成功. 定位到微信分享接口. 2.分享其它文章到微信成功. 接口有问题!差点就找接口了,还好没 3.断点微信分享,发现突然压缩失败. 代码写法问题,下面会分解 4.找到原因,微信对分享缩略图大小有32k的限制,代码是对文章的第一张图片进行压缩,图片太大,压缩代码也有问题. 开始解决问题 这里有两种解决方法: 1.接口提供文章对应的分享内容,在编辑人员编辑文章的时候就对这些数据进行了限制. { "title"

  • Android canvas drawBitmap方法详解及实例

     Android canvas drawBitmap方法详解及实例 之前自己在自定义view,用到canvas.drawBitmap(Bitmap, SrcRect, DesRect, Paint)的时候,对其中的第2和3个参数的含义含糊不清.看源码函数也没理解,然后看了一些其他的博客加上自己的理解,整理如下.首先,我们看一张图片,今天就要绘制这张图片. 然后将图片用红色的线条分成4个部分,如下: 我们自定义一个View,代码如下: public class PoterDuffLoadingVi

  • 解析Android中View转换为Bitmap及getDrawingCache=null的解决方法

    1.前言 Android中经常会遇到把View转换为Bitmap的情形,比如,对整个屏幕视图进行截屏并生成图片:Coverflow中需要把一页一页的view转换为Bitmap.以便实现复杂的图形效果(阴影.倒影效果等):再比如一些动态的实时View为便于观察和记录数据.需要临时生成静态的Bitmap. 2.实现方法 1)下面是笔者经常用的一个转换方法 public static Bitmap convertViewToBitmap(View view, int bitmapWidth, int

  • Android利用BitMap获得图片像素数据的方法

    本文实例讲述了Android利用BitMap获得图片像素数据的方法.分享给大家供大家参考,具体如下: 网上看到的参考是: int[] pixels = new int[bit.getWidth()*bit.getHeight()];//保存所有的像素的数组,图片宽×高 bit.getPixels(pixels,0,bit.getWidth(),0,0,bit.getWidth(),bit.getHeight()); for(int i = 0; i < pixels.length; i++){

  • Android自定义view实现圆形、圆角和椭圆图片(BitmapShader图形渲染)

    一.前言 Android实现圆角矩形,圆形或者椭圆等图形,一般主要是个自定义View加上使用Xfermode实现的.实现圆角图片的方法其实不少,常见的就是利用Xfermode,Shader.本文直接继承ImageView,使用BitmapShader方法来实现圆形.圆角和椭圆的绘制,等大家看我本文的方法后,其他的类似形状也就都能举一反三来来画出来了. 二.效果图: 三.BitmapShader简介 BitmapShader是Shader的子类,可以通过Paint.setShader(Shader

  • Android中将Bitmap对象以PNG格式保存在内部存储中的方法

    在Android中进行图像处理的任务时,有时我们希望将处理后的结果以图像文件的格式保存在内部存储空间中,本文以此为目的,介绍将Bitmap对象的数据以PNG格式保存下来的方法. 1.添加权限 由于是对SD card进行操作,必不可少的就是为你的程序添加读写权限,需要添加的内容如下: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

  • Android实现图片压缩(bitmap的六种压缩方式)

    Android中图片是以bitmap形式存在的,那么bitmap所占内存,直接影响到了应用所占内存大小,首先要知道bitmap所占内存大小计算方式: 图片长度 x 图片宽度 x 一个像素点占用的字节数 以下是图片的压缩格式: 其中,A代表透明度:R代表红色:G代表绿色:B代表蓝色. ALPHA_8 表示8位Alpha位图,即A=8,一个像素点占用1个字节,它没有颜色,只有透明度 ARGB_4444 表示16位ARGB位图,即A=4,R=4,G=4,B=4,一个像素点占4+4+4+4=16位,2个

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

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

  • Java实现将png格式图片转换成jpg格式图片的方法【测试可用】

    本文实例讲述了Java实现将png格式图片转换成jpg格式图片的方法.分享给大家供大家参考,具体如下: import java.awt.Color; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; public class ConvertImageFile { public static void main(Str

  • PHP处理bmp格式图片的方法分析

    本文分析了PHP处理bmp格式图片的方法.分享给大家供大家参考,具体如下: 白天QA提出项目上传图片有问题,具体为:上传成功,预览失败.我去了之后,又上传了几张其他的图片可以上传,然后仔细问了下他上传的是哪张图片,看了后使用getimagesize函数打印了下. Array ( [0] => 494 [1] => 260 [2] => 6 [3] => width="494" height="260" [bits] => 24 [mim

  • Android中的Bitmap的详细介绍

    Bitmap简介(摘抄于网络) 位图文件(Bitmap),扩展名可以是.bmp或者.dib.位图是Windows标准格式图形文件,它将图像定义为由点(像素)组成,每个点可以由多种色彩表示,包括2.4.8.16.24和32位色彩. 例如,一幅1024×768分辨率的32位真彩图片,其所占存储字节数为:1024×768×32/(8*1024)=3072KB 位图文件图像效果好,但是非压缩格式的,需要占用较大存储空间,不利于在网络上传送.jpg/png格式则恰好弥补了位图文件的缺点. 在Android

  • Android中的Bitmap序列化失败的解决方法

    之前写了个User类(实现了Serializable接口),类变量里有Bitmap类型的头像图片,Bitmap导致序列化不成功,报 "android.graphics.Bitmap"相关错误 解决方法之一:把Bitmap对象替换成byte数组来表示间接表示图片,在需要Bitmap的时候再讲byte数组转换成Bitmap对象.这是因为byte数组和Bitmap之间的可以转化,实现也比较方便. 附byte数组与Bitmap的相互转换方法: Bitmap转换成byte数组 private b

  • php将从数据库中获得的数据转换成json格式并输出的方法

    如下所示: header('content-type:application/json;charset=utf8'); $results = array(); while ($row = mysql_fetch_assoc($result_query)) { $results[] = $row; } if($results){ echo json_encode($results); }else{ echo mysql_error(); } 将查询到的数组存放到一个新的数组中,然后返回json格式

  • C语言实现BMP格式图片转化为灰度

    本文实例为大家分享了C语言将BMP格式图片转化为灰度的具体代码,供大家参考,具体内容如下 代码如下: #include<stdio.h> #include<malloc.h> #include<stdlib.h> #pragma pack(1) typedef struct tagBITMAPFILEHEADER { unsigned char bfType[2];//文件格式 unsigned long bfSize;//文件大小 unsigned short bfR

  • C语言读取和存储bmp格式图片

    开发过程中有时候需要解析bmp数据,下面先简单介绍bmp数据组成,后面附上C语言读取和存储bmp格式图片代码. 典型的位图文件格式通常包含下面几个数据块: 1.BMP文件头:保存位图文件的总体信息. 2.位图信息头:保存位图图像的详细信息.位图信息:保存位图图像的详细信息. 3.调色板:保存所用颜色的定义.调色板:保存所用颜色的定义. 4.位图数据:保存一个又一个像素的实际图像.位图数据:保存一个又一个像素的实际图像. 1. BMP文件头(14字节) BMP文件头数据结构含有BMP文件的类型.文

  • JS中的数组转变成JSON格式字符串的方法

    有一个JS数组,如: var arr = [["projectname1","projectnumber1"],["projectname2","projectnumber2"],["projectname3","projectnumber3"]]; 想将此数组转换成JSON字符串,如: var jsonarr = [{"projectname":projectnam

  • C#实现集合转换成json格式数据的方法

    本文实例讲述了C#实现集合转换成json格式数据的方法.分享给大家供大家参考,具体如下: /// <summary> /// dataTable转换成Json格式 /// </summary> /// <param name="dt"></param> /// <returns></returns> public static string ToJson(DataTable dt) { if (dt != null

随机推荐