當前位置:編程學習大全網 - 編程語言 - java高手來,位圖問題~~

java高手來,位圖問題~~

作者 Jean-Pierre Dubé

摘要

雖然 Java 提供了幾種打開圖像的機制,但保存圖像並不是他的強項。這篇技巧將講述怎麽將圖像保存在 24 位位圖文件中。另外,Jean-Pierre 還提供了將圖像文件寫入位圖文件所需的全部代碼。

這篇技巧是 Java 技巧 43 的補充,那篇技巧說明了在 Java 應用程式中加載位圖文件的過程。本月我再提供壹篇教程,說明怎麽將圖像保存在 24 位位圖文件中,其中還包含將圖像對象寫入位圖文件的代碼片斷。

如果妳在 Microsoft 視窗系統 環境中工作,那麽創建位圖文件的功能將為妳提供許多方便。例如,在我的上壹個項目中,我必須將 Java 和 Microsoft Access 對接。Java 程式允許用戶在屏幕上繪圖。這幅圖隨後被打印到 Microsoft Access 報表中。由於 Java 不支持 OLE,我的唯壹選擇就是創建該圖的壹個位圖文件,並通知 Microsoft Access 報表在何處能找到這個位圖文件。如果妳寫過向剪貼板發送圖像的應用程式,則這個技巧可能對妳有用 -- 尤其是當妳將這個信息傳遞給另壹個應用程式時。

位圖文件的格式

位圖文件格式支持 4 位 RLE(行程長度編碼)及 8 位和 24 位編碼。因為我們只處理 24 位格式,所以下面我們查看壹下該文件的結構。

位圖文件分為三個部分。我已將他們列在下面。

第 1 部分:位圖文件的標頭

標頭包含位圖文件的類型大小信息和版面信息。結構如下(摘自 C 語言結構定義):

typedef struct tagBITMAPFILEHEADER {

UINT bfType;

DWORD bfSize;

UINT bfReserved1;

UINT bfReserved2;

DWORD bfOffBits;

}BITMAPFILEHEADER;

下面是對這個清單中的代碼元素的說明:

bfType:指定文件類型,其值始終為 BM。

bfSize:指定整個文件的大小(以字節為單位)。

bfReserved1:保留 -- 必須為 0。

bfReserved2:保留 -- 必須為 0。

bfOffBits:指定從 BitmapFileHeader 到圖像首部的字節偏移量。

目前妳已明白位圖標頭的用途就是標識位圖文件。讀取位圖文件的每個程式都使用位圖標頭來進行文件驗證。

第 2 部分:位圖信息標頭

隨後的標頭稱為信息標頭,其中包含圖像本身的屬性。

下面說明怎麽指定 視窗系統 3.0(或更高版本)設備獨立位圖 (DIB) 的大小和顏色格式:

typedef struct tagBITMAPINFOHEADER {

DWORD biSize;

LONG biWidth;

LONG biHeight;

WORD biPlanes;

WORD biBitCount;

DWORD biCompression;

DWORD biSizeImage;

LONG biXPelsPerMeter;

LONG biYPelsPerMeter;

DWORD biClrUsed;

DWORD biClrImportant;

} BITMAPINFOHEADER;

以上代碼清單的每個元素說明如下:

biSize:指定 BITMAPINFOHEADER 結構所需的字節數。

biWidth:指定位圖的寬度(以象素為單位)。

biHeight:指定位圖的高度(以象素為單位)。

biPlanes:指定目標設備的位面數。這個成員變量的值必須為 1。

biBitCount:指定每個象素的位數。其值必須為 1、4、8 或 24。

biCompression:指定壓縮位圖的壓縮類型。在 24 位格式中,該變量被設置為 0。

biSizeImage:指定圖像的大小(以字節為單位)。如果位圖的格式是 BI_RGB,則將此成員變量設置為 0 是有效的。

biXPelsPerMeter:為位圖指定目標設備的水平分辨率(以“象素/米”為單位)。應用程式可用該值從最符合當前設備特征的資源群組中選擇壹個位圖。

biYPelsPerMeter:為位圖指定目標設備的垂直分辨率(以“象素/米”為單位)。

biClrUsed:指定位圖實際所用的顏色表中的顏色索引數。如果 biBitCount 設為 24,則 biClrUsed 指定用來優化 視窗系統 調色板性能的參考顏色表。

biClrImportant:指定對位圖的顯示有重要影響的顏色索引數。如果此值為 0,則所有顏色都非常重要。

目前已定義了創建圖像所需的全部信息。

第 3 部分:圖像

在 24 位格式中,圖像中的每個象素都由存儲為 BRG 的三字節 RGB 序列表示。每個掃描行都被補足到 4 位。為了使這個過程稍復雜壹點,圖像是自底而上存儲的,即第壹個掃描行是圖像中的最後壹個掃描行。下圖顯示了標頭 (BITMAPHEADER) 和 (BITMAPINFOHEADER) 及部分圖像。各個部分由垂線分隔:

0000000000 4D42 B536 0002 0000 0000 0036 0000 | 0028

0000000020 0000 0107 0000 00E0 0000 0001 0018 0000

0000000040 0000 B500 0002 0EC4 0000 0EC4 0000 0000

0000000060 0000 0000 0000 | FFFF FFFF FFFF FFFF FFFF

0000000100 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF

*

目前,我們開始檢視代碼

目前我們已知道了 24 位位圖文件的結構,下面就是妳期待已久的內容:用來將圖像對象寫入位圖文件的代碼。

import java.awt.*;

import java.io.*;

import java.awt.image.*;

public class BMPFile extends Component {

//--- 私有常量

private final static int BITMAPFILEHEADER_SIZE = 14;

private final static int BITMAPINFOHEADER_SIZE = 40;

//--- 私有變量聲明

//--- 位圖文件標頭

private byte bitmapFileHeader [] = new byte [14];

private byte bfType [] = {’B’, ’M’};

private int bfSize = 0;

private int bfReserved1 = 0;

private int bfReserved2 = 0;

private int bfOffBits = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE;

//--- 位圖信息標頭

private byte bitmapInfoHeader [] = new byte [40];

private int biSize = BITMAPINFOHEADER_SIZE;

private int biWidth = 0;

private int biHeight = 0;

private int biPlanes = 1;

private int biBitCount = 24;

private int biCompression = 0;

private int biSizeImage = 0x030000;

private int biXPelsPerMeter = 0x0;

private int biYPelsPerMeter = 0x0;

private int biClrUsed = 0;

private int biClrImportant = 0;

//--- 位圖原始數據

private int bitmap [];

//--- 文件部分

private FileOutputStream fo;

//--- 缺省構造函數

public BMPFile() {

}

public void saveBitmap (String parFilename, Image parImage, int

parWidth, int parHeight) {

try {

fo = new FileOutputStream (parFilename);

save (parImage, parWidth, parHeight);

fo.close ();

}

catch (Exception saveEx) {

saveEx.printStackTrace ();

}

}

/*

* saveMethod 是該進程的主方法。該方法

* 將調用 convertImage 方法以將內存圖像轉換為

* 字節數組;writeBitmapFileHeader 方法創建並寫入

* 位圖文件標頭;writeBitmapInfoHeader 創建

* 信息標頭;writeBitmap 寫入圖像。

*

*/

private void save (Image parImage, int parWidth, int parHeight) {

try {

convertImage (parImage, parWidth, parHeight);

writeBitmapFileHeader ();

writeBitmapInfoHeader ();

writeBitmap ();

}

catch (Exception saveEx) {

saveEx.printStackTrace ();

}

}

/*

* convertImage 將內存圖像轉換為位圖格式 (BRG)。

* 他還計算位圖信息標頭所用的某些信息。

*

*/

private boolean convertImage (Image parImage, int parWidth, int parHeight) {

int pad;

bitmap = new int [parWidth * parHeight];

PixelGrabber pg = new PixelGrabber (parImage, 0, 0, parWidth, parHeight,

bitmap, 0, parWidth);

try {

pg.grabPixels ();

}

catch (InterruptedException e) {

e.printStackTrace ();

return (false);

}

pad = (4 - ((parWidth * 3) % 4)) * parHeight;

biSizeImage = ((parWidth * parHeight) * 3) + pad;

bfSize = biSizeImage + BITMAPFILEHEADER_SIZE +

BITMAPINFOHEADER_SIZE;

biWidth = parWidth;

biHeight = parHeight;

return (true);

}

/*

* writeBitmap 將象素捕捉器返回的圖像轉換為

* 所需的格式。請記住:掃描行在位圖文件中是

* 反向存儲的!

*

* 每個掃描行必須補足為 4 個字節。

*/

private void writeBitmap () {

int size;

int value;

int j;

int i;

int rowCount;

int rowIndex;

int lastRowIndex;

int pad;

int padCount;

byte rgb [] = new byte [3];

size = (biWidth * biHeight) - 1;

pad = 4 - ((biWidth * 3) % 4);

if (pad == 4) // <==== 錯誤修正

pad = 0; // <==== 錯誤修正

rowCount = 1;

padCount = 0;

rowIndex = size - biWidth;

lastRowIndex = rowIndex;

try {

for (j = 0; j < size; j++) {

value = bitmap [rowIndex];

rgb [0] = (byte) (value & 0xFF);

rgb [1] = (byte) ((value >> 8) & 0xFF);

rgb [2] = (byte) ((value >> 16) & 0xFF);

fo.write (rgb);

if (rowCount == biWidth) {

padCount += pad;

for (i = 1; i <= pad; i++) {

fo.write (0x00);

}

rowCount = 1;

rowIndex = lastRowIndex - biWidth;

lastRowIndex = rowIndex;

}

else

rowCount++;

rowIndex++;

}

//--- 更新文件大小

bfSize += padCount - pad;

biSizeImage += padCount - pad;

}

catch (Exception wb) {

wb.printStackTrace ();

}

}

/*

* writeBitmapFileHeader 將位圖文件標頭寫入文件中。

*

*/

private void writeBitmapFileHeader () {

try {

fo.write (bfType);

fo.write (intToDWord (bfSize));

fo.write (intToWord (bfReserved1));

fo.write (intToWord (bfReserved2));

fo.write (intToDWord (bfOffBits));

}

catch (Exception wbfh) {

wbfh.printStackTrace ();

}

}

/*

*

* writeBitmapInfoHeader 將位圖信息標頭

* 寫入文件中。

*

*/

private void writeBitmapInfoHeader () {

try {

fo.write (intToDWord (biSize));

fo.write (intToDWord (biWidth));

fo.write (intToDWord (biHeight));

fo.write (intToWord (biPlanes));

fo.write (intToWord (biBitCount));

fo.write (intToDWord (biCompression));

fo.write (intToDWord (biSizeImage));

fo.write (intToDWord (biXPelsPerMeter));

fo.write (intToDWord (biYPelsPerMeter));

fo.write (intToDWord (biClrUsed));

fo.write (intToDWord (biClrImportant));

}

catch (Exception wbih) {

wbih.printStackTrace ();

}

}

/*

*

* intToWord 將整數轉換為單字,返回值

* 存儲在壹個雙字節數組中。

*

*/

private byte [] intToWord (int parValue) {

byte retValue [] = new byte [2];

retValue [0] = (byte) (parValue & 0x00FF);

retValue [1] = (byte) ((parValue >> 8) & 0x00FF);

return (retValue);

}

/*

*

* intToDWord 將整數轉換為雙字,返回值

* 存儲在壹個 4 字節數組中。

*

*/

private byte [] intToDWord (int parValue) {

byte retValue [] = new byte [4];

retValue [0] = (byte) (parValue & 0x00FF);

retValue [1] = (byte) ((parValue >> 8) & 0x000000FF);

retValue [2] = (byte) ((parValue >> 16) & 0x000000FF);

retValue [3] = (byte) ((parValue >> 24) & 0x000000FF);

return (retValue);

}

}

  • 上一篇:安卓軟件全屏顯示如何設置安卓軟件全屏?
  • 下一篇:現在是java發展前景好還是Python發展前景好?
  • copyright 2024編程學習大全網