前言
????
???????在任何一個綜合性網站,我們往往需要上傳一些圖片資料。但隨著高分辨率DC的普及,上傳的圖片容量會很大,比如300萬象素DC出來的文件基本不下600K。為了管理方便,大家可能不愿意每次都用ACDsee修改它,而直接上傳到服務器。但是這種做法在客戶端看來就沒有那么輕松了,對于撥號上網的用戶簡直是一場惡夢,雖然你可以在圖片區域設置wide和high!
???
?????? 上一篇文章中(http://www.aygfsteel.com/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.aygfsteel.com/rosen