有才华的人,别忘记给滋润你的那块土壤施肥

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  28 随笔 :: 5 文章 :: 147 评论 :: 0 Trackbacks
作者:John  Zukowski
2003年1月

如果你对图像处理感兴趣,而且需要使用GIF、JPEG和PNG以外的其它图像格式,或者希望改善JPEG图像处理的性能但不知道到哪里寻找适当的方法,或者需要通过几何运算(包括非线性变换)来处理图像,不必再为此苦恼了,答案就在这里——来自Sun公司的Java高级图像处理API和JAI图像I/O  API  1.0  RC。

JAI  API是Java  Media  API的一部分,与之相伴的还包括Java  2D  API、Java  3D  API、Java  Speech  API和其他一些API。Java高级图像处理API是作为Java规范请求(JSP)34的一部分而开发的,是对J2SE  version  1.3+版的扩展,主要用于处理图像。最初发布的版本是1.0,JDC(Java  Developer  Connection)提供了一个预览版1.1.2  beta。(最新进展情况请查阅README.html文件。)与AWT和Java  2D相比,JAI  API提供了更丰富的图像处理,包括对许多通用图像操作的内在支持。

不过本文的目的不是讨论JAI  API,而是伴随这些API但分离到它自己的可安装库中的一组图像读写器(codec)类,即Java高级图像处理图像I/O工具1.0  RC。该RC提供了可以插接到J2SE  1.4的图像I/O框架上的一些功能。作为JSR-15一部分而开发的图像I/O  API提供了一个支持不同图像格式的可插拔框架。标准J2SE  1.4版本身支持GIF、JPEG和PNG图像格式,而JAI图像I/O  RC则提供了更多主流图像格式的编码解码器。只要加上针对操作平台的适当版本,以前开发的应用程序就可以处理这些新的图像格式。

要理解JAI图像I/O工具的使用,需要首先了解图像I/O库。在安装和介绍图像I/O工具包之前,我们先看一看图像I/O库。
图像I/O库

图像I/O库是J2SE  1.4的标准API,放在javax.imageio包内。虽然这个包提供了两个接口和9个类,整个API实际上就是ImageIO类。通过这个类可以弄清读写所支持的图像格式并对这些图像进行读写,实际上这也就是整个API的全部内容。

由于图像I/O库是一个可插拔的框架,所支持的图像格式集不是固定不变的。尽管随J2SE  1.4发布了一些标准格式,但任何人都可以增加新的支持格式。要查看有哪些格式可用,可以使用下面的代码:
import  javax.imageio.*;
import  java.util.Arrays;

public  class  GetFormats  {
       
public  static  void  main(String  args[])  {
               String  readFormats[]  
=  ImageIO.getReaderMIMETypes();
               String  writeFormats[]  
=  ImageIO.getWriterMIMETypes();
               System.out.println(
"Readers:  "  +  
                               Arrays.asList(readFormats));
               System.out.println(
"Writers:  "  +  
                               Arrays.asList(writeFormats));
       }

}

运行该程序,你会发现这个库支持读取GIF、JPEG和PNG图像,也支持写JPEG和PNG图像,但是不支持写GIF文件。

除了与像image/jpeg这样的MIME类型协同工作外,ImageIO类还允许通过getReaderFormatNames和  getWriterFormatNames方法使用JPEG这样的非正式名称。此外,通过getImageReadersBySuffix和  getImageWritersBySuffix还可以了解是否存在针对特定文件扩展名的reader/writer存在。

利用ImageIO类,你所要做的事情不过是读javax.imageio.stream.ImageInputStream、  java.io.InputStream、java.io.File或者java.net.URL,结果会得到一个  java.awt.image.BufferedImage。一旦拥有了BufferedImage,你就可以指定需要的格式名把图像写回去。(不仅仅是  BufferImage,任何实现RenderedImage接口的类都可以写。)新的格式既可以与读取的格式相同,也可以是不同的格式以便进行格式转换。如果指定的格式没有可用的writer,那么write方法就返回false,否则如果找到了相应的writer就返回true。
String  inputFilename  =  ;
BufferedImage  image  
=  ImageIO.read(inputFilename);

String  formatName  
=  "jpg"// desired format
String  outputFilename  =  ;
File  outputFile  
=  new  File(outputFilename);
boolean  writerExists  =  ImageIO.write(image,formatName,  outputFile);

为了说明图像I/O库的用法,下面的例子使用JFileChooser提示输入图像文件名。选中文件后再选择目标输出格式,然后按下“Save(保存)”按钮。保存完成后,将重新读取图像并在一个新窗口内显示。

import  java.awt.*;
import  java.awt.event.*;
import  java.awt.image.*;
import  javax.swing.*;
import  java.io.*;
import  java.net.*;
import  javax.imageio.*;

public  class  Converting  extends  JFrame  {
       JLabel  promptLabel;
       JTextField  prompt;
       JButton  promptButton;
       JFileChooser  fileChooser;
       JComboBox  comboBox;
?
       JButton  saveButton;
?
       
public  Converting()  {
               
super("Image  Conversion");
               setDefaultCloseOperation(EXIT_ON_CLOSE);
               Container  contentPane  
=  getContentPane();
               JPanel  inputPanel  
=  new  JPanel();
               promptLabel  
=  new  JLabel("Filename:");
               inputPanel.add(promptLabel);
               prompt  
=  new  JTextField(20);
               inputPanel.add(prompt);
               promptButton  
=  new  JButton("Browse");
               inputPanel.add(promptButton);
               contentPane.add(inputPanel,  BorderLayout.NORTH);

               fileChooser  
=  new  JFileChooser();
               promptButton.addActionListener(
                       
new  ActionListener()  {
                               
public  void  actionPerformed(ActionEvent  e)  {
                                       
int  returnValue  =  
                                                   fileChooser.showOpenDialog(
null);
                                       
if  (returnValue  ==  
                                                 JFileChooser.APPROVE_OPTION)  
{
                                           File  selectedFile  
=  
                                                       fileChooser.getSelectedFile();
                                             
if  (selectedFile  !=  null)  {
                                                   prompt.setText(selectedFile.getAbsolutePath());
                                             }

                                       }

                               }

                       }

               );

               JPanel  outputPanel  
=  new  JPanel();
               String  writerFormats[]  
=  
                               ImageIO.getWriterFormatNames();
               ComboBoxModel  comboBoxModel  
=  new  
                               DefaultComboBoxModel(writerFormats);
               comboBox  
=  new  JComboBox(comboBoxModel);
               outputPanel.add(comboBox);
               saveButton  
=  new  JButton("Save");
               outputPanel.add(saveButton);
               saveButton.addActionListener(
                       
new  ActionListener()  {
                               
public  void  actionPerformed(ActionEvent  e)  {
                                       
try  {
                                       String  name  
=  prompt.getText();
                                       File  file  
=  new  File(name);
                                       
if  (file.exists())  {
                                               BufferedImage  image  
=  
                                                               ImageIO.read(file.toURL());
                                       
if  (image  ==  null)  {
                                               System.err.println(
"Invalid  input  
                                                               file  format");
                                       }
  else  {
                                             String  selection  
=  
                                                         (String)comboBox.getSelectedItem();
                                               String  outputFilename  
=  name  +  
                                                             
"."  +  selection;
                                               File  outputFile  
=  new  File(outputFilename);
                                               
boolean  found  =  ImageIO.write(image,  
                                                               selection,  outputFile);
                                               
if  (found)  {
                                                   JDialog  window  
=  new  JDialog();
                                                   Container  windowContent  
=  
                                                                     window.getContentPane();
                                                   BufferedImage  newImage  
=  
                                                                     ImageIO.read(outputFile);
                                                   JLabel  label  
=  new  JLabel(new  
                                                                     ImageIcon(newImage));
                                                 JScrollPane  pane  
=  new  
                                                                     JScrollPane(label);
                                               windowContent.add(pane,  
                                                                 BorderLayout.CENTER);
                                               window.setSize(
300,  300);
                                               window.show();
                                       }
  else  {
                                           System.err.println(
"Error  saving");
                                       }

                                 }

                           }
  else  {
                                 System.err.println(
"Bad  filename");
                           }

                     }
  catch  (MalformedURLException  mur)  {
                           System.err.println(
"Bad  filename");
                   }
  catch  (IOException  ioe)  {
                         System.err.println(
"Error  reading  file");
                 }

           }

       }

   );

   contentPane.add(outputPanel,  BorderLayout.SOUTH);

   }

   
public  static  void  main(String  args[])  {
           JFrame  frame  
=  new  Converting();
           frame.pack();
           frame.show();
   }

}


注意,该程序没有硬编码任何文件类型,而是询问图像I/O框架支持哪些文件类型。安装Java高级图像处理图像I/O工具RC后,还可以重新运行该程序,你将会看到更多的存储格式。读取其它格式的图像基本上无需改变代码也能工作,用户只要选择不同的文件类型就可以了。

注意:图像I/O库中的内容比这里说明的要多得多。比方说可以通过写图像的参数设置压缩率,或者用读写进度监视器来监听事件。关于图像I/O用法的更多信息,请参阅Java  Image  I/O  API  Guide。
Java高级图像处理图像I/O工具包1.0概览

这就引出了本文要讨论的主题,Java高级图像处理图像I/O工具包1.0(RC)。JAI图像I/O工具主要用于为J2SE1.4的图像I/O库提供更多的图像readers/writers(编码解码器codecs)。只要运行时平台安装了该工具,你的程序就能够支持这些新的编码解码器。

JAI图像I/O工具提供的新编码解码器包括:

       *  支持对位图(BMP)编码解码(MIME类型image/bmp);
       *  通过本机代码加速的JPEG的读写支持(MIME类型image/jpeg),同时也支持无损JPEG(ISO  10918-1)和JPEG-LS(ISO  14495-1),对支持的所有JPEG变体都能处理12位色深;
       *  支持对JPEG  2000的编码与解码(MIME类型image/jpeg2000);
       *  用本机代码提高对PNG的编码解码速度(MIME类型image/png);
       *  可移植位图(PNM)编码解码器支持可移植位图(PBM)、可移植灰度位图(PGM)、可移植像素位图(PPM)(MIME类型分别为image/x-  portable-anymap、image/x-portable-bitmap、image/x-portable-graymap、image/x  -portable-pixmap);
       *  原始格式(无MIME类型);
       *  支持TIFF编码解码(MIME类型image/tiff);
       *  支持无线位图(WBMP)编码解码(MIME类型image/vnd.wap.wbmp)。

该工具库还使得流插件可以与NIO库一起使用,详情参阅com.sun.media.imageio.stream包中的  FileChannelImageInputStream、FileChannelImageOutputStream和  RawImageInputStream。前两个分别以java.nio.channels.FileChannel作为输入和输出,最后一个供原始格式解码器javax.imageio.ImageReader读取原始数据。同时该工具还支持JAI操作"ImageRead"  和"ImageWrite"  ,这两个操作都包含在包内,分别对应于现有的JAI操作集{"Stream",  "FileLoad",  "URL"}和{"Encode",  "FileStore"}。
安装Java高级图像处理图像I/O工具包1.0

要使用Java高级图像处理图像I/O工具包,首先必须根据使用的操作系统平台从Early  Access  page  for  the  RC下在适当的版本。支持的操作系统有Solaris  SPARC、Solaris  x86、Linux和Windows,大小也随着版本而异,  Solaris  SPARC版有5MB之多,而其他版本则只有1MB左右。下载页面的README-jai_imageio.html文件提供了有关的下载信息和安装说明,同时还给出了所支持的编码解码插件的版本信息,比如BMP的编码解码器可以读取版本号从3到5的图像,但是只能写版本号3的图像。

安装后除了本机库之外还有三个JAR文件。如果安全设置禁止使用,这些本机库就不会发生作用,而回复到仅仅使用内建的纯Java版JPG和PNG格式的状态。

如果是安装到Unix机器上,则需要把上述的三个JAR文件安装到jre/lib/ext目录下。对于Solaris-SPARC用户,需要把6个.so文件复制到jre/lib/sparc目录中。Solaris-x86和Linux用户应把libclib_jiio.so文件复制到  jre/lib/i386中。

如果要安装到Microsoft  Windows的机器上,同样需要把三个JAR文件复制到jre\lib\ext目录中,另外把clib_jiio.dll文件放到jre\bin下。

注意:上述目录都是相对于JRE的根目录而言的。

只要把这些文件放到了规定的位置,JAI图像I/O工具包就安装完成了。

Java高级图像处理图像I/O工具包1.0的用法

安装Java高级图像处理图像I/O工具包并不改变图像I/O库的用法。正确编写的代码无需变更也能正常运行。可能唯一需要改变的就是新的图像格式使用何种扩展名,你可以使用getWriterFormatNames之类的函数所返回的名称,也可以对各种格式进行硬编码。

为了说明已有的代码仍能工作,首先重新运行一遍前面的GetFormats程序,就可以看到对新的MIME类型的支持:

Readers:  [image/png,  image/x-portable-graymap,  
   mage/jpeg,  image/jpeg2000,  image/x-png,  
   mage/tiff,  image/vnd.wap.wbmp,  image/x-portable-pixmap,  
   mage/x-portable-bitmap,  image/bmp,  image/gif,  
   mage/x-portable-anymap,  ]
Writers:  [image/png,  image/x-portable-graymap,  image/jpeg,  
   mage/jpeg2000,  image/x-png,  image/tiff,  
   mage/vnd.wap.wbmp,  image/x-portable-pixmap,  
   mage/x-portable-bitmap,  image/bmp,  
   mage/x-portable-anymap,  ]

然后运行Converting程序,现在可以把图像转换成更多的格式。

尽管对于默认的编码解码器而言,那些缺省的读写设置通常已经足够了,但是也许你希望改变新增编码解码器的设置。改变这些设置无需调用ImageIO的  read和write方法,而只要针对指定的MIME类型从ImageIO获得相应的ImageReader或ImageWriter对象,然后改变这些对象的设置就可以了。一旦改变了默认的ImageReadParam或者ImageWriteParam,就可以返回去调用ImageIO的read和  Write方法。否则的话,就只能在ImageReader和ImageWriter中进行读写操作。比如,JPEG的ImageWriter会要求你通知编码器生成优化的图像Huffman表。其它的编码解码器也会提供它们自己的相应设置。
结论

对Java  平台可用的扩展而言,Java高级图像处理图像I/O工具包1.0  RC是一个受欢迎的增强。一旦通过RC阶段,新增的图像格式支持将是对标准运行时环境的一个令人鼓舞的改进。库的内容分别放在几个  com.sun.media.imageio包内,有一些还是本机代码库。但是所有库的使用都通过J2SE  1.4引入的标准图像I/O框架。只需要把库添加到JRE中就可以使用它们了。
资源

       *  Java  Media  APIs
       *  Java  Advanced  Imaging  API
       *  Java  Advanced  Imaging  Image  I/O  API  RC  1.0
       *  Java  Advanced  Imaging  Image  I/O  Tools  API  Documentation
       *  JSR  15:  Image  I/O  Framework  Specification
       *  JSR  34:  Java  Advanced  Imaging  API  1.1
       *  Java  Advanced  Imaging  Interest  Group
       *  Java  Image  I/O  API  Guide
posted on 2010-01-08 14:09 kissjava 阅读(506) 评论(0)  编辑  收藏 所属分类: java基础

只有注册用户登录后才能发表评论。


网站导航: