协议之最简单的解析——bmp格式

[size=x-large][color=black] 一:协议之感想 [/color][/size]
学了协议以后我就感觉这个东西有种很美妙的感觉,让我更进一步认识到计算机和计算机之间的交流原来是通过协议进行的。一旦双方不遵守这个协议那么这个交流就变得没有意义了 就像是用两种不同的语言进行交流一样,那么这种结果就只能是你看着我,然后我看着你,谁也不懂谁的。忽然想到那句话“[color=indigo]世界上最遥远的距离不是生与死的距离,而是两个人之间明明说着话,却不知道对方的意思[/color]” 由此看来,协议是那么的重要。以前我总是认为很多大牛们,他们之所有成为大牛,是因为他们往往都不去遵循这个世界的规矩,总是表现得和平凡的人不一样,结果就成了大牛。学了协议以后 我慢慢的改变了这个看法,他们是在大规矩下的不拘泥小节。无规矩则不成方圆,我们必须在遵循这个大规矩前提下尽可能的发挥我们的想象力。协议是通信之枢纽。那么下面我将用解析bmp格式这个协议来谈谈我对他的理解吧。
[size=x-large][color=black]二:bmp格式的定义[/color][/size]
[size=large]BMP格式由四部分组成:[/size]
1:[color=black]文件头信息块[/color]

0000-0001 :文件标识,字母为ASCII码"BM".
0002-0005: 文件大小。
0006-0009: 保留,每字节以"00",填写。
000A-000D: 记录图像数据区的起始的位置。各字节的信息含义依次为: 文件头信息块大小 ,图像描述信息块的大小 , 图像颜色表的大小,保留为(01)
[color=black]2:图像描述信息块:[/color]
000E-0011: 图像描述信息块的大小,常为28H。
0012-0015:图像宽度。
0016-0019:图像的高度。
001A-001B:图像的plane总数(横为1)
001C-001D:记录像素的位数,很重要的数值,图像的颜色数由该值决定。
001E-0021:数据压缩方式(数值位0:不压缩;1:8位压缩;2:4位压缩)
0022-0025:图像区数据的大小。
0026-0029:水平每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。
002A-002D:垂直每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。
002E-0031:此图像所用的颜色数,如值为0,表示所有颜色一样重要

[color=black]3.颜色表[/color]
颜色表的大小根据所使用的颜色模式而定:2色图像为8字节;16色图像位64字节;256色图像为1024字节。其中,每4字节表示一种颜色,并以B (蓝色)、G(绿色)、R(红色)、alpha(32位位图的透明度值,一般不需要)。即首先4字节表示颜色号1的颜色,接下来表示颜色号2的颜色,依此类推。

[color=black]4.图像数据区:[/color]
这里是图片最重要的地方,要是想了解去百度。我也没太搞懂,先将其弄过来
颜色表接下来位为位图文件的图像数据区,在此部分记录着每点像素对应的颜色号,其记录方式也随颜色模式而定,既2色图像每点占1位(8位为1字节);16色图像每点占4位(半字节);256色图像每点占8位(1字节);真彩色图像每点占24位(3 字节)。所以,整个数据区的大小也会随之变化。究其规律而言,可的出如下计算公式:图像数据信息大小=(图像宽度*图像高度*记录像素的位数)/8。 
  然而,未压缩的图像信息区的大小。除了真彩色模式外,其余的均大于或等 于数据信息的大小。这是为什么呢?原因有两个: 
  1.BMP文件记录一行图像是以字节为单位的。因此,就不存在一个字节中的数据位信息表示的点在不同的两行中。也就是说,设显示模式位16色,在每个字节分配两个点信息时,如果图像的宽度位奇数,那么最后一个像素点的信息将独占一个字节,这个字节的后4位将没有意义。接下来的一个字节将开始记录下一行的信息。 
  2.为了显示的方便,除了真彩色外,其他的每中颜色模式的行字节数要用数据“00”补齐为4的整数倍。如果显示模式为16色,当图像宽为19时,存储时每行则要补充4-(19/2+1)%4=2个字节(加1是因为里面有一个像素点要独占了一字节)。如果显示模式为256色,当图像宽为 19时,每行也要补充4-19%4=1个字节。
这些定义不用去记。到用的时候去查就行了。现在就举例一个bmp文件格式的解析吧,上代码

三:举例说明bmp文件格式的解析(这里用比较简单的24为真彩 ,因为要考虑的比较少)
首先实现一个窗体类 :用来读取和保存bmp格式图片

/**
* 实现bmp文件的解析类,继承窗体。将其读入到自己的画板中
*
*/
public class AnalysisBmp extends JFrame{
/**
* 显示窗体的方法
*/
public void intitUi(){
this.setTitle("bmp图形解析器");
this.setSize(600,500);
this.setResizable(false);
//设置关闭的时候退出
this.setDefaultCloseOperation(3);
//给窗体设置面板布局方式
this.setLayout(new BorderLayout());

//实例化一个菜单栏对象,并把该对象添加到窗体上
JMenuBar menuBar=new JMenuBar();
this.setJMenuBar(menuBar);

//实例化菜单项对象
JMenu jmenu1=new JMenu("文件(F)");
JMenu jmenu2=new JMenu("编辑(E)");
menuBar.add(jmenu1);
menuBar.add(jmenu2);

JMenuItem menuitem=new JMenuItem("打开");
JMenuItem menuitem2=new JMenuItem("保存");
JMenuItem menuitem3=new JMenuItem("退出");

JMenuItem menuitem4=new JMenuItem("撤销");
JMenuItem menuitem5=new JMenuItem("复制");
JMenuItem menuitem6=new JMenuItem("粘贴");

//在“文件”菜单项中添加 “打开”,“保存”,“退出”,
jmenu1.add(menuitem);
jmenu1.add(menuitem2);
jmenu1.add(menuitem3);
//在“编辑”菜单项中添加“撤销”,“复制”,“粘贴”
jmenu2.add(menuitem4);
jmenu2.add(menuitem5);
jmenu2.add(menuitem6);

//显示窗体,放在最后面
this.setVisible(true);

//注意在实例化对象的时候就是产生一个新的对象,很容易产生空指针异常
// //实例化一个PanelMouseListener对象 并将窗体传递给改对象
PanelMouseListener pm=new PanelMouseListener(this);
//实例化一个MenuActionListener对象 其实就是面板 并将pm传递给listener;
MenuActionListener listener=new MenuActionListener(pm,this);

//将面板listener添加到窗体上面
this.add(listener, BorderLayout.CENTER);
//然后给画板添加鼠标监听器
listener.addMouseListener(pm);

//给菜单项上事件添加监听器
menuitem.addActionListener(listener);
menuitem2.addActionListener(listener);
menuitem3.addActionListener(listener);
menuitem4.addActionListener(listener);
menuitem5.addActionListener(listener);
menuitem6.addActionListener(listener);
}
//主函数,程序的入口
public static void main(String[] args) {
//实例化一个对象用来调用显示窗体的方法
AnalysisBmp asp=new AnalysisBmp();
//调用显示窗体的方法
asp.intitUi();
}

}


[color=green]运行该界面类,结果如图所示:[/color]
[img]
[img]http://dl2.iteye.com/upload/attachment/0087/0223/745fa1f3-f925-3084-b2de-7535a34fb57c.jpg[/img]
[/img]

然后实现bmp格式的读取和写操作,都放入到监听器类

/**
* 菜单项上实现监听器
* @author Administrator
*
*/
public class MenuActionListener extends JPanel implements ActionListener {
// private Graphics g; //声明画布变量,用来保存传过来的画布
private JFileChooser fileChooser;
private int width; //声明整型变量,保存图片的宽度(在位信息的14~17位)
private int heigh; //声明整型变量,保存图片的高度(在位信息的18~21位)
private int skip_width;
private int[][] ColorR; //保存像素中的红色变量
private int[][] ColorG; //保存像素中的绿色变量
private int[][] ColorB; //保存像素中的蓝色变量
private int bflen=14; //头文件的14个字节的整形变量
private int bilen=40; //40位的信息头变量
private int size=0; //bmp信息头大小 14~17 固定值为28H;
java.io.FileInputStream fis;
java.io.DataInputStream dis;
File file; //打开选择的文件
File file1; //保存选择的文件
javax.swing.JFrame jf;
PanelMouseListener pm; //保存PanelMouseListener对象的属性
/**
* 构造器对象 ,用来接收PanelMouseListener的对象和窗体对象
* @param pm PanelMouseListener的对象
*/
public MenuActionListener(PanelMouseListener pm,JFrame jf){
this.pm=pm;
this.jf=jf;
}
//监听器中的抽象方法
public void actionPerformed(ActionEvent e) {
if("打开".equals(e.getActionCommand())){ //点击打开菜单项时,弹出选择文件对话框
// System.out.println("执行啦");
fileChooser=new JFileChooser();
//调设置只能选择目录,默认是选择文件 (收索目录的时候用到,或则就不要用到)
// fileChooser.setFileSelectionMode();
//然后将显示出来。null是显示在窗体中中央
fileChooser.showOpenDialog(null);
//接收读取得到的文件
file = fileChooser.getSelectedFile();
if(file!=null){ //当选择有文件的时候 进行读取
readBmp(file);
System.out.println("读取得到的文件"+file);
}
}
if("退出".equals(e.getActionCommand())){ //退出
System.exit(0);
}
if("保存".equals(e.getActionCommand())){ //点击保存事件的时候就 把所画的图形保存出来
fileChooser=new JFileChooser(); //实例化一个文件选择器
//宣示保存文件
fileChooser.showSaveDialog(null);
file1=fileChooser.getSelectedFile();
//将取得的BufferedImage对象赋值给bm
writeBMP(pm.bi);
System.out.println(pm.bi);
}
}
/**
* 读取所选中的bmp文件方法
* @param fileName 所选择的文件
*/
public void readBmp(File fileName){
try {
//实例化输入流对象
fis=new java.io.FileInputStream(fileName);
dis=new java.io.DataInputStream(fis);

//1:读取Bmp头文件 长度14位
byte []bf=new byte[bflen];
int d=dis.read(bf,0,bflen);
System.out.println("头文件所占的字节:"+d);

//2:读取为信息图 40位
byte[] bi=new byte[bilen];
int t=dis.read(bi,0,bilen);
System.out.println("位信息所占的字节:"+t);
//在位图信息中 获取重要的信息,主要是图片的高度和宽度
size=changeInt(bi,3); //信息头在14~17位
width=changeInt(bi,7); //宽度在18~21位
heigh=changeInt(bi,11); //高度在22~25位
//打印图片相关信息
System.out.println("bmp信息头大小:"+size);
System.out.println("bmp源图的宽度:"+width);
System.out.println("bmp源图的高度:"+heigh);

//判断图片宽度字节数能否被4整除,不能整除要补0
if(width*3%4!=0){
skip_width=4-width*3%4;
//检验无效的长度,方便后面直接跳过该位数
System.out.println("要补的0长度为:"+skip_width);
}
//调用读取像素颜色的具体值方法
dispalyRGB();
} catch (Exception e) {
e.printStackTrace();
System.out.println("出错误啦。。。。。");
}
}
/**
* 读取颜色的方法 并调用paint()方法
* @throws IOException
*/
public void dispalyRGB() throws IOException{
//声明二维数组用来保存点的 坐标
ColorR= new int[heigh][width];
ColorG= new int[heigh][width];
ColorB= new int[heigh][width];
//读取每个点的具体颜色值
//用两个for循环 读取像素的颜色值 每一个点都是由 R,G,B组成
for(int h=heigh-1;h>=0;h--){
for(int w=0;w<width;w++){ //因为下标是从0开始的,所以不能取到宽度
// System.out.println("h="+h+",w="+w);
ColorB[h][w]=dis.read();
ColorG[h][w]=dis.read();
ColorR[h][w]=dis.read();
if(w==width-1){ //当宽度读到最后的时候,就跳过后面补零的位
dis.skipBytes(skip_width);
}
//打印颜色的值
// System.out.println("像素的绿色:"+ColorG[h][w]
// +",像素的红色:"+ColorR[h][w]
// +",像素的蓝色:"+ColorB[h][w]);
}
}
//重写绘画方法 ,保证重绘的时候是读取的画过的图片
this.repaint();
}
/**
* 将字节转化为整形的方法
* @param bi要进行变化的字节数组
* @param start 字节开始的位数
* @return 转化好的整形
*/
public int changeInt(byte []bi,int start){
return (((int)bi[start]&0xff)<<24)|
(((int)bi[start-1]&0xff)<<16)|
(((int)bi[start-2]&0xff)<<8)|
(int)bi[start-3]&0xff;
}
/**
* 重写面板的方法
* 用什么画就重绘什么
*/
public void paint(Graphics g){
//调用父类的窗体方法
super.paint(g);

//重绘鼠标所画的图片
this.pm.draw();
System.out.println("重绘!! "+"高度"+heigh+"宽度"+width);
//重绘所打开图片画的RGB图形
this.drawRGB(g);
System.out.println("重绘结束!!");
}
/**
* 将像素的颜色画出来
*/
public void drawRGB(Graphics g){
for(int h=heigh-1;h>=0;h--){
for(int w=0;w<width;w++){
//设置颜色为 原图读取的像素颜色值
g.setColor(new Color(ColorR[h][w],ColorG[h][w],ColorB[h][w]));
//将各个像素画出来
// g.fillOval(w, h, 1, 1); //用这种方法画的时候就不出现题目, 我还不懂!!!!!!
int w1=w+(jf.getWidth()-width)/2; //将水平方向平移,图片显示在窗体的最中间
g.drawLine(w1, h, w1, h);
// System.out.println("w==="+w+"h==="+h);
// System.out.println("像素的绿色:"+ColorG[h][w]
// +",像素的红色:"+ColorR[h][w]
// +",像素的蓝色:"+ColorB[h][w]);
if(w==width-1){ //当宽度读到最后的时候,就跳过后面补零的位
try {
dis.skipBytes(skip_width);
} catch (IOException e) {
e.printStackTrace();
System.out.println("我出错误啦啦啦...");
}
}
}

}
}
/**
* 将所画图片转化成bmp格式文件
* @param bi
*/
public void writeBMP(BufferedImage bi){
try {
if(file1!=null){
//实例化一个输出对象
java.io.FileOutputStream out=new java.io.FileOutputStream(file1);
java.io.DataOutputStream dout=new java.io.DataOutputStream(out);

int w=bi.getWidth(); //取得图片的宽度
int h=bi.getHeight(); //取得图片的高度
int size =w*h*3; //所以像素的字节
System.out.println("w="+w+",h="+h+",size="+size);
if(w%4!=0){
size+=(w%4)*h;
}
//实例化一个bmp头文件头对象
BmpFileHeader bfi=new BmpFileHeader(size,56);
//实例化一个bmp头文件内容对象
BmpInfoHeader bis=new BmpInfoHeader(w,h,24);

//定义一个长度为三的数组,保存颜色
byte[]rgbs=new byte[3];
byte[]blank=new byte[w%4];

//将数据写入
dout.write(bfi.getData());
dout.write(bis.getData());
//定义一个标记
int index=0;
//取得默认的颜色R,G,B的值 ,对用下面注销掉的颜色写入
ColorModel cm = ColorModel.getRGBdefault();
for(int y=h-1;y>=0;y--){ //循还里面的要注意啊。不要把变量写错啊。。。。出了好多次错误
for(int x=0;x<w;x++){
index+=3;
// System.out.println("x="+x+",y="+y);
//取得颜色
int rgb=bi.getRGB(x, y);
// System.out.println("rgb="+rgb);
//将颜色写入到文件中
// rgbs[2] = (byte)cm.getGreen(rgb);
// rgbs[1] = (byte)cm.getBlue(rgb);
// rgbs[0] = (byte)cm.getRed(rgb);
/**颜色写的时候要让BGR的顺序读取
在存的时候是按顺序rgbs[0]=r,rgbs[1]=g,rgbs[2]=b;
所以要按反方向写入
*/
rgbs[2]=(byte)rgb;
rgb=rgb>>>8;
rgbs[1]=(byte)rgb;
rgb=rgb>>>8;
rgbs[0]=(byte)rgb;
// System.out.println("颜色是:"+rgbs[0]+" "+rgbs[1]+" "+rgbs[2]);
dout.write(rgbs);
if((w%4!=0)&&(index%(w*3)==0)){
dout.write(blank); //写入多余的部分
}
}
}
//刷新输出流中的数据,完成之后并关闭输出流
dout.flush();
dout.close();

}

} catch (Exception e) {
e.printStackTrace();
}
}
}



定义bmp的头文件结构类(保存bmp格式的时候用到) 代码如下

/**
* bmp的头文件结构类 用于保存文件时候做
* Title :bmp头文件结构
*
* byte[2] bfTyte 文件结构类型 必须是0x424D 即字符串"BM";
* byte[4] bfSize 指定文件大小,包括这14个字节
* byte[2] bfReserved1; 保留字
* byte[2] bfReserved2; 保留字
* byte[4] bfOffBits ; 文件头到实际位图数据的偏移字节数
*/
public class BmpFileHeader {
//声明一个14长度字节的字节数组
private byte[] data=new byte[14];
private int size; //文件的大小 2~5字节
private int offset; //偏移量 11~14字节
/**
* 用构造方法介绍文件的大小和偏移量
* 并且写入
* @param size 大小
* @param offsert 偏移量
*/
public BmpFileHeader(int size,int offsert){
this.size=size; //文件的大小 2~5字节
this.offset=offsert; //偏移量 11~14字节;
data[0]='B';
data[1]='M';
// System.out.println("头文件data[0]="+Integer.toHexString((int)data[0])+
// ",头文件data[1]="+Integer.toHexString((int)data[1]));
//将文件大小赋值给一个value 并将文件大小转化为字节 因为要写入 所以要转化为字节
int value=size;
data[2]=(byte)value;
value=value>>>8;
data[3]=(byte)value;
value=value>>>8;
data[4]=(byte)value;
value=value>>>8;
data[5]=(byte)value;
value=value>>>8;
//检验文件大小 按位输出,
// System.out.println("头文件第三位是:"+Integer.toHexString((int)data[2])+
// ",头文件第四位是:"+Integer.toHexString((int)data[3])+
// ",头文件第五位是:"+Integer.toHexString((int)data[4])+
// ",头文件第六位是:"+Integer.toHexString((int)data[5]));
//将offsert 转化为字节型; 用中间变量 来做
value=offsert;
//先将强制转化为字节型; 运用强制转化和位的右移运算
data[10]=(byte)value;
value=value>>>8;
data[11]=(byte)value;
value=value>>>8;
data[12]=(byte)value;
value=value>>>8;
data[13]=(byte)value;
//打印验证
// System.out.println("头文件第十一位是:"+Integer.toHexString((int)data[10])+
// ",头文件第十二位是:"+Integer.toHexString((int)data[11])+
// ",头文件第十三位是:"+Integer.toHexString((int)data[12])+
// ",头文件第十四位是:"+Integer.toHexString((int)data[13]));
}
/**
* 取得文件结构的数组数据;
* @return 数组数据
*/
public byte[] getData() {
return data;
}
/**
* 取得头文件的大小
* @return
*/
public int getSize() {
return size;
}
/**
* 取得文件偏移量
* @return
*/
public int getOffset() {
return offset;
}
}


文件头结构内容代码 (主要是用于保存图片为bmp格式的时候)

/**
* bmp文件头内容的结构
* 文件内容的头结构固定是40个字节,
*
* byte[4] biSize:这个结构的长度 为40; (15位)
* byte[4] biWidth;指定图形的宽度,单位为像素;() (19~12)
* byte[4] biHeigh;指定图形的高度,单位为像素 ()(23~26)
* byte[2] biPlanes 必须是1,不用考虑 (27~28)
* byte[2] biBitCount;指定颜色时要用到的位数, () (29~30)
* 常用值为1(黑白) 4(16色) 8(256色),24(真彩彩色图)
* byte[4] biCompression ;指定是否压缩 (31~34)
* byte[4] biSizeImage 指定实际的位图数据占用的字节数 (35~38)
* byte[4] biXPelsPerMeter 指定目标水平的分辨率 单位是每米像素的个数 (39~42)
* byte[4] biXPelsPerMeter 指定目标垂直的分辨率 单位是每米像素的个数 (43~46)
* byte[4] biClrUsed 指定本图像实际用到的颜色数 如果为0,则用2biBitCount;(47~50)
* byte[4] biClrImportant; 指定本图像中的重要颜色数,如果该值为零,则都是重要的(41~54)
*
*
*/
public class BmpInfoHeader {
private int width; //图片的宽度变量
private int heigh; //图片的高度变量
private int biBitCount; //图片的颜色的位数变量
private int biLen=40;
private byte []data; //声明一个字节数组,保存文件内容
/**
* 构造函数 用来接收 所要保存图片的高度 宽度 和 指定颜色的位数属性
*/
public BmpInfoHeader(int width,int heigh,int biBitCount){
this.width=width;
this.heigh=heigh;
this.biBitCount=biBitCount;

//创建40字节的的字节数组
data=new byte[biLen];
data[0]=40; //文件内容大小为40;
// System.out.println("信息内容大小:"+(int)data[0]);
//2到4位默认值为0;

int value=width;
//将图片宽度转化为字节型
data[4]=(byte)value;
value=value>>>8;
data[5]=(byte)value;
value=value>>>8;
data[6]=(byte)value;
value=value>>>8;
data[7]=(byte)value;

// System.out.println("文件内容第5位是:"+Integer.toHexString((int)data[4])+
// ",文件内容第6位是:"+Integer.toHexString((int)data[5])+
// ",文件内容第7位是:"+Integer.toHexString((int)data[6])+
// ",文件内容第8位是:"+Integer.toHexString((int)data[7]));

//将图片的高度转化为字节型
value =heigh;
data[8]=(byte)value;
value=value>>>8;
data[9]=(byte)value;
value=value>>>8;
data[10]=(byte)value;
value=value>>>8;
data[11]=(byte)value;

// System.out.println("文件内容第9位:"+Integer.toHexString((int)data[8])+
// ",文件内容第10位是:"+Integer.toHexString((int)data[9])+
// ",文件内容第11位是:"+Integer.toHexString((int)data[10])+
// ",文件内容第12位是:"+Integer.toHexString((int)data[11]));

data[12]=1;
data[14]=(byte)biBitCount; //颜色位数

//所有像素所占的字节 赋值给value 在(35~38字节,包括文件头14)
value=width*heigh*3;
if(width%4!=0){ //不能被4整除
value+=(width%4)*heigh; //加上所补的零
}
data[20]=(byte)value;
value=value>>>8;
data[21]=(byte)value;
value=value>>>8;
data[22]=(byte)value;
value=value>>>8;
data[23]=(byte)value;
// System.out.println("文件内容第35位是:"+Integer.toHexString((int)data[20])+
// ",文件内容第36位是:"+Integer.toHexString((int)data[21])+
// ",文件内容第37位是:"+Integer.toHexString((int)data[22])+
// ",文件内容第38位是:"+Integer.toHexString((int)data[23]));
}
/**
* 取得图片的宽度
* @return
*/
public int getWidth() {
return width;
}
/**
* 取得图片的高度
* @return
*/
public int getHeigh() {
return heigh;
}
/**
* 取得颜色的位数
* @return
*/
public int getBiBiCount() {
return biBitCount;
}
/**
* 取得文件内容的数据
* @return
*/
public byte[] getData() {
return data;
}

}


最后实现一个鼠标监听器类,用鼠标点击事件去画图 然后将画好的图片保存;

public class PanelMouseListener implements MouseListener{
JFrame jf; //窗体的变量
int x1,y1,x2,y2; //定义保存鼠标按下和释放时候的坐标
BufferedImage bi;//保存缓冲对象的变量
JPanel jp;
/**
* 构造方法,用来接收传递过来的窗体
* @param jf
*/
public PanelMouseListener(JFrame jf){
this.jf=jf;
}
public void mousePressed(MouseEvent e) {

x1=e.getX();
y1=e.getY();
// System.out.println("x1="+x1+",y1="+y1);
}
public void mouseReleased(MouseEvent e) {
x2=e.getX();
y2=e.getY();
jp = (JPanel)e.getSource();
draw();
// System.out.println("x1="+x1+",y1="+y1);
}
public void mouseClicked(MouseEvent e) {

}

public void mouseEntered(MouseEvent e) {

}

public void mouseExited(MouseEvent e) {

}
Graphics gg;
/**
* 定义画线的方法 并且将画好的图保存下来
*/
public void draw(){
if(jp!=null){
int w=jp.getWidth();
int h=jp.getHeight();
Graphics g=jp.getGraphics();
// System.out.println("w="+w+",h="+h);

//将图片画到缓冲流中
if(bi == null){
bi=new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
gg=bi.getGraphics();
}
//取得BufferedImage的画布对象
// Graphics gg=bi.getGraphics();
gg.setColor(Color.BLUE);
gg.drawLine(x1, y1, x2, y2);
//将缓冲流中的图片画到画布上
gg.setColor(Color.WHITE);
g.drawImage(bi, 0, 0, null);
}
}
}


[color=orange]紧接着上面的运行 首先完成读取操作 选择要打开的文件如图[/color]
[img]
[img]http://dl2.iteye.com/upload/attachment/0087/0225/7be281af-4f88-39cd-a49d-15de1f255002.jpg[/img]
[/img]

[color=green]点击之后读取bmp图像就会显示到我自己上的画图板上了。看看是什么图片吧[/color]
[img]
[img]http://dl2.iteye.com/upload/attachment/0087/0227/7e19f1a5-fa00-3e94-85fd-9082bcc34a06.jpg[/img]
[/img]

[color=brown]在之后就是自己先到画图板上随便画一个 然后用图片编辑器打开,结果如下[/color]
[img]
[img]http://dl2.iteye.com/upload/attachment/0087/0229/d954ef88-7a37-3676-85a6-fcf9809a4347.jpg[/img]
[/img]

[img]
[img]http://dl2.iteye.com/upload/attachment/0087/0231/879ca221-c2ca-3028-af45-a91f145ad670.jpg[/img]
[/img]

[size=large][color=black]代码实现总结[/color][/size]:到这里bmp格式的读取和保存就实现了。但是在写代码的时候花的时间还是比较久,首先得到找资料查看bmp格式的协议 ,知道了协议以后就是然后才能进行读写操作,这里就花了不少的时间。在写代码的时候自己又遇见了很多很多的技术上的问题,其中我觉得最难理解的也最重要的就是将字节型和整形进行相互转化,我写到这里的时候卡了好久。测试的时候要不就是不出来,要不就不是自己想要的。后面经过和同学的讨论 又问了老师,才把这个问题彻底解决了。这种基础性的问题以后还是要多看点书吧。还有就是讨论真的很重要。有时候自己想了很久的问题在别人稍微指导一下就能轻松的懂了。所以在以后的学习过程中 ,又有机会讨论的时候尽量去讨论。自己写代码的时间随时都会有。在写的时候还有一个难点就是在补0那一块不太了解,我在没有补零的时候,图片虽然是出来了,但是却是斜的。问了同学,查资料都是说这是规定要记。好吧,那我就把记下,知道有这么回事,会用就行了。就这样慢慢的问题就都解决了。在做完这个作品以后我个人感想吧就是问题总是会解决的,所以不要害怕出现问题。以后的路还很长.任重而道远......
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值