读取24位 BMP 图像并生成 JPG 缩略图

读取24位 BMP 图像并生成 JPG 缩略图

前言
    
       在任何一个综合性网站,我们往往需要上传一些图片资料。但随着高分辨率DC的普及,上传的图片容量会很大,比如300万象素DC出来的文件基本不下600K。为了管理方便,大家可能不愿意每次都用ACDsee修改它,而直接上传到服务器。但是这种做法在客户端看来就没有那么轻松了,对于拨号上网的用户简直是一场恶梦,虽然你可以在图片区域设置wide和high!
   
       上一篇文章中(http://www.blogjava.net/rosen/archive/2007/06/12/9940.html)我主要介绍了JPG(JEPG)、GIF、PNG图像的读取及压缩方法,遗憾的是不支持BMP图像。本文一鼓作气、再接再厉,一举解决了这个问题!
   
程序代码

package BMP;

import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;

import java.io.FileInputStream;
import java.io.FileOutputStream;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class BMPReader{

    public String Reader(){ 
        Image image;                                    //构造一个目标图
        String result="";                               //返回结果
 try{
     FileInputStream fs=new FileInputStream("/test.BMP");
     int bflen=14;                           
     byte bf[]=new byte[bflen];            
     fs.read(bf,0,bflen);                       //读取14字节BMP文件头
     int bilen=40;                 
     byte bi[]=new byte[bilen];
     fs.read(bi,0,bilen);                       //读取40字节BMP信息头

     // 获取一些重要数据
     int nwidth=(((int)bi[7]&0xff)<<24)         //源图宽度
     | (((int)bi[6]&0xff)<<16)
     | (((int)bi[5]&0xff)<<8)
     | (int)bi[4]&0xff;
     System.out.println("宽:"+nwidth);
            int nheight=(((int)bi[11]&0xff)<<24)       //源图高度
     | (((int)bi[10]&0xff)<<16)
     | (((int)bi[9]&0xff)<<8)
     | (int)bi[8]&0xff;
     System.out.println("高:"+nheight);
            //位数
     int nbitcount=(((int)bi[15]&0xff)<<8) | (int)bi[14]&0xff;
     System.out.println("位数:"+nbitcount);
            //源图大小
     int nsizeimage=(((int)bi[23]&0xff)<<24)
     | (((int)bi[22]&0xff)<<16)
     | (((int)bi[21]&0xff)<<8)
     | (int)bi[20]&0xff;
     System.out.println("源图大小:"+nsizeimage);

            //对24位BMP进行解析
     if(nbitcount==24){
         int npad=(nsizeimage/nheight)-nwidth*3;
         int ndata[]=new int[nheight*nwidth];
         byte brgb[]=new byte[(nwidth+npad)*3*nheight];
         fs.read (brgb,0,(nwidth+npad)*3*nheight);
         int nindex=0;
         for(int j=0;j<nheight;j++){
      for(int i=0;i<nwidth;i++){
                 ndata [nwidth*(nheight-j-1)+i]=
          (255&0xff)<<24
          | (((int)brgb[nindex+2]&0xff)<<16)
          | (((int)brgb[nindex+1]&0xff)<<8)
          | (int)brgb[nindex]&0xff;
                 nindex+=3;
            }
     nindex+=npad;
                }
  Toolkit kit=Toolkit.getDefaultToolkit();
  image=kit.createImage(new MemoryImageSource(nwidth,nheight,
      ndata,0,nwidth));
                result="从BMP得到图像image";
                System.out.println("从BMP得到图像image");
     }else{
         result="不是24位BMP,失败!";
                System.out.println("不是24位BMP,失败!");
         image=(Image)null;
     }
            fs.close();        //关闭输入流
           
            //开始进行图像压缩(对image对象进行操作)
     int wideth=image.getWidth(null);                                   //得到源图宽
     int height=image.getHeight(null);                                  //得到源图长
     BufferedImage tag=new BufferedImage(wideth/2,height/2,BufferedImage.TYPE_INT_RGB);
     tag.getGraphics().drawImage(image,0,0,wideth/2,height/2,null);     //绘制缩小后的图
     FileOutputStream out=new FileOutputStream("/newfile.jpg");         //输出到文件流
     JPEGImageEncoder encoder=JPEGCodec.createJPEGEncoder(out);     
     encoder.encode(tag);                                               //进行JPEG编码
     out.close();       //关闭输出流                     
 }catch (Exception e){
     System.out.println(e);
        }
        return result;
    }
}

    相信代码部分应该没有什么问题吧?通过以下方法,你可以得到更多的信息:


       //得到压缩值
        int ncompression = (((int)bi[19])<<24)
        | (((int)bi[18])<<16)
        | (((int)bi[17])<<8)
        | (int)bi[16];
        System.out.println("压缩:"+ncompression);


       //象素情况
        int nxpm = (((int)bi[27]&0xff)<<24)
        | (((int)bi[26]&0xff)<<16)
        | (((int)bi[25]&0xff)<<8)
        | (int)bi[24]&0xff;
        System.out.println("X-象素/米:"+nxpm);
        int nypm = (((int)bi[31]&0xff)<<24)
        | (((int)bi[30]&0xff)<<16)
        | (((int)bi[29]&0xff)<<8)
        | (int)bi[28]&0xff;
        System.out.println("Y-象素/米:"+nypm);


       //颜色使用情况
        int nclrused = (((int)bi[35]&0xff)<<24)
        | (((int)bi[34]&0xff)<<16)
        | (((int)bi[33]&0xff)<<8)
        | (int)bi[32]&0xff;
        System.out.println("颜色使用数:"+nclrused);
        int nclrimp = (((int)bi[39]&0xff)<<24)
        | (((int)bi[38]&0xff)<<16)
        | (((int)bi[37]&0xff)<<8)
        | (int)bi[36]&0xff;
        System.out.println("颜色显要:"+nclrimp);
        int nplanes = (((int)bi[13]&0xff)<<8) | (int)bi[12]&0xff;
        System.out.println("位面:"+nplanes);


       //信息头中的图像大小
        int nbisize = (((int)bi[3]&0xff)<<24) 
        | (((int)bi[2]&0xff)<<16)
        | (((int)bi[1]&0xff)<<8)
        | (int)bi[0]&0xff;
        System.out.println("BMP信息头大小:"+nbisize);


       //文件大小及种类
        int nsize=(((int)bf[5]&0xff)<<24)      
               | (((int)bf[4]&0xff)<<16)
        | (((int)bf[3]&0xff)<<8)
        | (int)bf[2]&0xff;
        System.out.println("文件种类:"+(char)bf[0]+(char)bf[1]);
        System.out.println("文件大小:"+nsize);
       
后记

       可以通过变量nbitcount来判断是否是8位位图并作出相应处理。限于目前24位位图应用较为广泛,所以没有写出相应代码,如有需要可查阅Jeff West与John D.Mitchell之著作《How to read 8- and 24-bit Microsoft Windows bitmaps in Java applications》。

       在此,我谨慎的表示:因为位图(BMP)没有经过压缩,所以对于源图的容量几乎没有限制,不会出现内存不足的情况。
   
       在写这篇文章时我只进行了9M左右BMP的读取,其实大家有兴趣的话可以利用50M左右的TIF图转换为BMP(几乎还是50M)来做试验。并欢迎上来指正。



请注意!引用、转贴本文应注明原作者:Rosen Jiang 以及出处:http://www.blogjava.net/rosen

你可能感兴趣的:(读取24位 BMP 图像并生成 JPG 缩略图)