- 浏览: 4405 次
最新评论
图片的打开与保存(基于画图板)
上次的博客中可以看出,我们已经基本实现了画图板的基本功能。那么最后的一步,就是打开和保存。
在此之前,我们首先要加一个菜单条(我们的画图板是模仿win自带的)。菜单条的代码如下:
JMenuBar menubar = new JMenuBar();
// 创建一个菜单的数组
String[] menu1 = { "文件", "编辑", "关于" };
String[][] menu2 = { { "新建", "打开", "保存" }, { "撤销", "还原" }, { "关于" } };
String[][] commands = { { "xinjian", "dakai", "baocun" },
{ "chexiao", "huanyuan" }, { "guanyu" } };
// 创建一个菜单监听器
Filelistener listener1 = new Filelistener(centre);
// 遍历
for (int i = 0; i < menu1.length; i++) {
// 创建菜单对象
JMenu menu = new JMenu(menu1[i]);
menubar.add(menu);
for (int j = 0; j < menu2[i].length; j++) {
// 创建菜单选项
JMenuItem item = new JMenuItem(menu2[i][j]);
// 加在菜单上
menu.add(item);
// 设置选项的动作命令
item.setActionCommand(commands[i][j]);
// 给每个选项加监听器,注意,这是是item
item.addActionListener(listener1);
}
}
this.setJMenuBar(menubar);
在此要注意两点:
1:加监听器时候,是给item加,也即每一个选项加。
2:菜单以数组的形式创建,例如,文件下面包括了新建,保存,和打开。
3:设置动作命令时候,要把数组commands[i][j]传进来。
下面就是菜单的监听器,代码如下:
import java.awt.Dimension; import java.awt.Point; import java.awt.Rectangle; import java.awt.Robot; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JFileChooser; import javax.swing.JPanel; import javax.swing.filechooser.FileNameExtensionFilter; public class Filelistener implements ActionListener { //要把画板centre传过来 private JPanel centre; //声明机器人对象 java.awt.Robot robot; //创建一个重绘的二维数组 int[][] keep; public Filelistener(JPanel centre) { this.centre=centre; //robot try { robot=new java.awt.Robot(); } catch (AWTException e) { e.printStackTrace(); } } public void actionPerformed(ActionEvent e) { String commen = e.getActionCommand(); if ("xinjian".equals(commen)) { System.out.print("xinjian"); } /** * 这里是保存 */ if ("baocun".equals(commen)) { // 弹出文件选择框 javax.swing.JFileChooser c = new javax.swing.JFileChooser(); // 过滤 javax.swing.filechooser.FileNameExtensionFilter f = new javax.swing.filechooser.FileNameExtensionFilter( "BMP images", "BMP"); c.setFileFilter(f); c.showSaveDialog(null); //得到选择文件的路径 String path1=c.getSelectedFile().getAbsolutePath(); //保存图像 baocun b=new baocun(path1); b.keep(path1); System.out.print("baocun"); /************************************保存************************************************/ //得到centre左上角的坐标,相对于屏幕 Point left=centre.getLocationOnScreen(); //得到宽度 高度 Dimension dimension=centre.getPreferredSize(); //创建截取的区域对象 Rectangle rectangle=new Rectangle(left,dimension); //截图 java.awt.image.BufferedImage image=robot.createScreenCapture(rectangle); //创建二维数组 keep=new int[image.getHeight()][image.getWidth()]; //遍历 for(int i=0;i<keep.length;i++){ for(int j=0;j<keep[i].length;j++){ //获取坐标点的颜色 keep[i][j]=image.getRGB(j, i); } } } /** * 这里是读取 */ if ("dakai".equals(commen)) { // 弹出文件选择框 JFileChooser chooser = new JFileChooser(); // 过滤 FileNameExtensionFilter filter = new FileNameExtensionFilter( "BMP Images", "BMP"); chooser.setFileFilter(filter); System.out.print("过滤"); chooser.showOpenDialog(null); // 得到选择文件的路径 String path = chooser.getSelectedFile().getAbsolutePath(); // 解析,显示图像 jiexi jie = new jiexi( path, centre); jie.show(path); } } }
下面我们要做的,就是写一个解析(就是打开)的类和保存的类。
下面先来说明解析类。
首先,要做保存和打开,我们要知道bmp图片的格式信息。
此段转自百度:
位图文件可看成由4个部分组成:位图文件头(bitmap-file header)、位图信息头(bitmap-information header)、彩色表(color table)和定义位图的字节阵列,它具有如下所示的形式。
http://baike.baidu.com/view/189487.htm
网址如下,我就不在这里黏贴一次了。
打开有两步:
1:显示出bmp文件。
2:将其转成int。
1:显示出,代码如下:
import java.awt.Color; import java.awt.Dimension; import javax.swing.JPanel; public class jiexi { // 画布 private JPanel centre; // 窗口的画笔 private java.awt.Graphics g; // 文件打开的路径 private String path = null; // 图像大小 //private int size; // 读取的两个保留字 //private int c1, c2; // 数据偏移量 //private int dataoffset; // 图片的宽高 private int width, heigh; // 存放像素点的颜色 private int R[][], G[][], B[][]; // 宽取模?? int skipwidth = 0; public jiexi(String path, JPanel centre) { this.path = path; this.centre = centre; } // public void paint(java.awt.Graphics g) {pubi // for (int i = 0; i < heigh; i++) { // for (int j = 0; j < width; j++) { // g.setColor(new java.awt.Color(R[i][j], G[i][j], B[i][j])); // g.fillOval(j, i, 1, 1); // } // // } // } /** * 显示出BMP文件 */ public void show(String path) { try { // 文件输入流 java.io.FileInputStream input = new java.io.FileInputStream(path); // 将文件流包装成可写基本数据类型的输出流 java.io.DataInputStream input1 = new java.io.DataInputStream(input); // 读取14字节bmp文件头 // int bflen = 14; // 定义数组来存放 // byte bf[] = new byte[bflen]; // input1.read(bf, 0, bflen); // 读取40字节的信息头 // int bilen = 40; // byte bi[] = new byte[bilen]; // input1.read(bi, 0, bilen); // 获取重要数据 // 原图宽 // width = ChangeInt(bi, 7); // 原图高 // heigh = ChangeInt(bi, 11); //bmp图片的信息头 int len = 54; byte b[] = new byte[len]; input1.read(b, 0, len); width = ChangeInt(b, 21); heigh = ChangeInt(b, 25); // 存入重绘的数组 Drawlistener.keep = new int[heigh][width]; centre.setPreferredSize(new Dimension(width, heigh)); // 按照行读取 if (width * 3 % 4 != 0) { input1.skip(width * 3 % 4); } // // (从下往上,从左往右) for (int i = heigh - 1; i >= 0; i--) { for (int j = 0; j < width; j++) { // 读取三原色 int blue = input1.read(); int green = input1.read(); int red = input1.read(); // 将三原色转换为颜色 Color color = new Color(red, green, blue); // 将相对应的颜色转为整形存入数组中(下标极为重要) Drawlistener.keep[i][j] = color.getRGB(); } } centre.repaint();// 调用重绘的方法 // ??? // int nbitcount = (((int) bi[15] & 0xff) << 8) | (int) bi[14] & // 0xff; // / System.out.println("位数:" + nbitcount); // int nsizeimage = ChangeInt(bi, 23); // System.out.println("源图大小:" + nsizeimage); // 关闭文件流 input.close(); input1.close(); } catch (Exception e) { e.printStackTrace(); } } // public void showRGB24(DataInputStream input1) { // this.setTitle(path); // 弹出一个图片的窗口的大小 // this.setSize(width, heigh); // this.setResizable(false); // this.setVisible(true); // g = this.getGraphics(); // 如果图像的宽度不为0 // //if (!(width * 3 % 4 == 0)) { // skipwidth = 4 - width * 3 % 4; // } // R = new int[heigh][width]; // G = new int[heigh][width]; // B = new int[heigh][width]; // 按行读取,如果i,j为正则倒着来 i=heigh,j=width // for (int i = heigh - 1; i >= 0; i--) { // for (int j = 0; j < width; j++) { // 读入三原色 // try { // int red = input1.read(); // int green = input1.read(); // int blue = input1.read(); // R[i][j] = red; // G[i][j] = green; // B[i][j] = blue; // 这里小心 // if(j==width-1){ // System.out.print(input1.skipBytes(skipwidth)); // } // / } catch (IOException e) { // e.printStackTrace(); // / } // }repaint(); // } // }
我将第一次做的代码也贴上来,方便对比。(就是屏蔽掉的部分)
1:我第一次写的时候,将bmp的文件头拆开来写,实际上,并没有必要。因为现在是读取,没有必要将文件头和信息头分 开两个数组来存放。我们直接将其存在同一个数组里面就可。
2:关于颜色的储存方式。首先,没必要去弹窗口神马的。第二,我第一次写的时候,将三原色分别储存在一个二维的数组 里面,这样显得十分麻烦(并且有时候也会出bug)。实际上,我们直接用的文件流来读取(在前一篇blog里面有关于 文件流的详细分析和代码示例),所以直接用文件流来读取三原色就可以了。然后,将颜色存入同一个数组就可以。这 就和文件头和信息头一样,既无必要分开,也不容易出错。
最后一步,就是转成int,因为bmp格式的图片是以byte保存的,我们要读取出来,就要专程成int,代码如下:
/** * 转成int * * @param bi * @param i * @return */ public int ChangeInt(byte[] bi, int i) { return (((int) bi[i] & 0xff) << 24) | (((int) bi[i - 1] & 0xff) << 16) | (((int) bi[i - 2] & 0xff) << 8) | (int) bi[i - 3] & 0xff; } }
至此,我们的打开就完成了。
下面,是将图片保存成bmp格式。首先,代码如下:
import java.awt.Color; import java.io.DataOutputStream; import java.io.EOFException; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; public class baocun { private String path1; private int width, heigh; public baocun(String path1) { this.path1 = path1; } public void keep(String path1) { // 输出 try { java.io.FileOutputStream output = new java.io.FileOutputStream( path1); java.io.BufferedOutputStream op1 = new java.io.BufferedOutputStream( output); /** * 文件头 14个字节 */ op1.write((byte) 66);// b op1.write((byte) 77);// m // 图片文件的大小,这里要自己算出来 int size = (4 - (width * 3) % 4) * heigh + heigh * width * 3 + 54; // 2--5字节,转成int op1.write(turnByte((int) size)); // 有4个字节的保留字 op1.write(0); op1.write(0); op1.write(0); op1.write(0); /** * 信息头 54字节 */ // 10--13字节,起始位置 op1.write(turnByte((int) 54)); // 存入信息头数据40 // 14--17,4个字节 op1.write(turnByte((int) 40)); op1.write(turnByte(width)); // 18-21 4个字节 图片宽度 op1.write(turnByte(heigh));// 22-25 4个字节 图片高度 // 26-27 2个字节 必须1 op1.write((byte) 1); op1.write((byte) 0); // 28-29 2个字节 必须24 op1.write((byte) 24); op1.write((byte) 0); op1.write(turnByte((int) 0)); // 30-34 4个字节 必须0 // 未完成 op1.write(turnByte((int) (size - 54))); // 34-37 4个字节 位图的大小,以字节为单位 op1.write(turnByte((int) 0)); // 38-41 4个字节 位图水平分辨率, op1.write(turnByte((int) 0)); // 42-45 4个字节 位图垂直分辨率, op1.write(turnByte((int) 0)); // 46-49 4个字节 位图实际使用的颜色表中的颜色数(全选) op1.write(turnByte((int) 0)); // 50-53 4个字节 位图显示过程中重要的颜色数(都重要) // 因为是24bmp图像,不需要颜色表 // 位图数据 int wid = 0; // 判断是否后面有补0 的情况 if ((width * 3) % 4 != 0) { wid = 4 - (width * 3) % 4; } // (从下往上,从左往右) for (int i = heigh - 1; i >= 0; i--) { for (int j = 0; j < width; j++) { int[][] aa = new int[heigh][width]; Color c = new Color(aa[i][j]); op1.write((byte) c.getBlue()); op1.write((byte) c.getGreen()); op1.write((byte) c.getRed()); } for (int j = 0; j < wid; j++) { op1.write((byte) 0); } } // 关闭流 op1.flush(); op1.close(); } catch (Exception e) { e.printStackTrace(); } } // 将其转成byte保存 private byte[] turnByte(int a) { byte[] b = new byte[4]; for (int i = 0; i < 4; i++) { b[i] = (byte) ((a >>> (8 * i)) & 0xFF); // 将int从低8位到高8位加入到byte数组中 } return b; } }
我觉得保存的重点,1是要写出他的文件头和信息头,2是要记得转成byte来保存!
相关推荐
总结一下,Delphi中的文件打开功能主要通过`TOpenDialog`组件实现,而显示和处理图片则可借助`TImage`组件。这些基础知识对于构建任何涉及用户与文件交互的应用程序都至关重要。通过熟练掌握这些技能,开发者能够...
总结来说,“打开图片的软件”涵盖了计算机上用于查看、管理和简单编辑图片的应用程序。它们是日常数字生活不可或缺的一部分,帮助我们更好地组织和享受我们的视觉资料。用户在选择此类软件时,可以根据自己的需求,...
打开.BMP图片的方法与.jpg类似,只是不需要指定文件类型: ```cpp CImage bitmap; if (!bitmap.Load("path_to_your_bitmap.bmp")) { AfxMessageBox(_T("无法打开图片")); return; } ``` 3. **显示图片** ...
在描述中提到的“打开网格图片时的动画效果”可能就是这种功能的体现,它可能包含图片放大、透明度变化或是其他形式的视觉转换。 “网格的消失动画效果”可能是指用户在浏览图片时,原本的图片网格背景会有一个优雅...
在探讨如何在WPF(Windows Presentation Foundation)应用中打开并显示图片到`Image`控件的过程中,我们将深入解析代码逻辑、关键类库的使用以及一些最佳实践,这将对WPF初学者尤其有益。 ### WPF与图片处理 WPF...
总结来说,"java屏幕截图后打开图片"的功能实现涵盖了Java GUI编程、图像处理以及操作系统交互等多个技术点。通过`Robot`类获取屏幕截图,使用`BufferedImage`处理图像,结合`ImageIO`保存图片,并利用`Runtime.exec...
MFC单文档打开图片 MFC单文档应用程序显示图像是指使用MFC单文档架构创建的一个应用程序,可以显示图像。下面将详细介绍如何使用MFC单文档打开图片的步骤。 Step 1: 创建MFC单文档应用程序 使用VS2010向导创建一...
Windows 10 系统让图片打开方式为照片查看器的步骤和知识点总结 在 Windows 10 系统中,图片的打开方式默认不是照片查看器,这让很多用户感到不方便。那么,如何让图片打开方式为照片查看器呢?下面将详细介绍相关...
总结来说,这段代码展示了如何使用JavaScript结合jQuery来实现通过网页按钮点击下载图片的功能,并且考虑到了图片加载的问题。对于想学习JavaScript在网页交互方面应用的开发者来说,这是一个不错的参考示例。不过,...
在计算机编程领域,尤其是...总结来说,实现VC++打开BMP、JPG或GIF图片涉及对图像格式的理解、选择合适的API或库以及正确地使用它们。通过学习和实践,开发者可以熟练掌握这项技能,为更复杂的图像处理任务打下基础。
总结来说,要实现“ie直接打开pdf、图片”,开发者需要考虑浏览器兼容性、安全性和性能优化。这通常涉及使用ActiveX控件、HTML5标签、JavaScript库以及后端技术如JSP来处理文件请求。不过,为了确保最佳的安全性和...
总结,用VC++打开并处理JPEG图片主要涉及引入GDI+库、加载图片、创建设备上下文、绘制图像以及可能的图像处理。虽然VC++标准库不直接支持,但借助GDI+,我们可以轻松实现这些功能。在实际项目中,还可以结合MFC或...
在Windows Forms (WinForms) 开发中,经常需要处理图像,其中一个常见的需求就是允许用户通过简单的拖拽操作来打开和显示图片。这种方式相较于传统的“打开文件”对话框更加直观和便捷。本文将详细介绍如何在...
总结来说,Android开发者可以通过ImageView直接显示项目内的图片,使用文件路径配合加载库处理下载的图片,通过注册Intent Filter则能让用户选择你的App打开外部图片。理解并熟练运用这些技术对于开发功能完善的...
总结一下,VC++中打开JPG图片主要涉及以下几个知识点: 1. GDI+库的使用:包括头文件的包含,库的链接,以及GDI+的初始化和关闭。 2. `Gdiplus::Image`类:用于加载和存储JPG图片。 3. `Gdiplus::Graphics`类:用于...
### 二、PictureBox与TextBox控件简介 - **PictureBox**:这是一个显示图像的控件,可以用来显示静态图像或者动态加载的图像。 - **TextBox**:这是用来显示文本或接受用户输入的控件。在这里,我们将用它来显示...
在Android开发中,与相机和图片相关的功能是...总结来说,Android应用中实现打开相机和图片功能涉及启动相机应用、处理返回结果、从图库选择图片以及权限管理。理解这些知识点能帮助开发者构建更完善的图像相关功能。
1. 加载图片:首先,你需要使用易语言提供的函数,如`打开图片文件`,加载图片到内存并获取图片句柄。 2. 获取图片数据:有了图片句柄后,可以使用`取得图片数据`这样的函数,传入图片句柄,来获取图片的原始二进制...
总结来说,实现“wpf打开图片显示到界面,另存为图片,并显示文件路径”的功能,你需要使用`Image`控件显示图片,`OpenFileDialog`和`SaveFileDialog`处理用户的选择,以及适当的方法来读取、保存图像数据。...
总结起来,实现"MFC基于单文档打开bmp图片"的关键在于理解MFC的SDI架构,掌握BMP图片的加载、绘制和缩放技术。通过以上步骤,我们可以创建一个功能完备的应用程序,允许用户查看和缩放BMP图片。这不仅加深了对MFC的...