· 創建 SWT 圖像
SWT Image 類似於 AWT BufferedImage,因為它的像素數據可以有直接讀或者寫操作訪問。這意味著可以通過直接讀取或者修改圖像的數據,來設置或者取得圖像中任何像素或者任何一組像素的顏色值。不過, SWT API 與相應的 AWT API 有很大不同,並且更容易使用。
SWT 的 Image 類提供了幾個構造函數,可以完成以下任務:
通過將一個文件名或者一個 InputStream 作為參數傳遞給構造函數裝載一個現有的圖像。圖像的格式必須是所支持的格式之一:BMP、GIF、JPG、PNG、Windows ICO 等。
構造一個指定大小的空圖像。可以通過修改其像素值或者向它拷貝一個 SWT 圖形上下文的內容 (GC) 來繪制該圖像。構造一個用像素值的現有緩沖區進行初始化的圖像。您將使用第三個構造函數創建一個 SWT 圖像,它是所繪制的 AWT 圖像的副本。
· 關於 ImageData 類
有關圖像的像素數據的信息包含在它的 ImageData 中。ImageData 是一個包含有關圖像大小、調色板、顏色值和透明度信息的類。應當特別關注以下 ImageData 字段:
width 和 height 指定圖像的大小。
depth 指定圖像的顏色深度。可能的值為 1、2、4、8、16、24 或者 32,指定編碼每一個像素的值所使用的位數。
palette 包含一個 PaletteData 對象,它存儲有關圖像的顏色模型的信息。與 AWT 一樣,SWT 的顏色模型可以是索引或者直接的。如果顏色模型是索引的,那麼 PaletteData 包含顏色索引。如果它是直接的,那麼它包含轉換(shift)信息,表明應當如何從像素的整數值中提取出顏色的 RGB 成分。
data 包含包含有像素值的字節緩沖區。與 AWT 緩沖區不同,SWT 緩沖區不是包含每一個像素的一種顏色值的整數數組。相反,它包含字節值。字節編碼的方法取決於所使用的顏色深度。對於一個 8 位的圖像,數組中的一個字節正好表示圖像中一個像素的值。對於 16 位圖像,每一個像素值編碼為緩沖區中的兩個字節。這兩個字節以最低有效字節順序存儲。對於 24 或者 32 位圖像,每一個像素值以最高有效位字節順序編碼為緩沖區中的三個或者四個字節。
bytesPerline 表明緩沖區中有多少字節用於編寫圖像中一行像素的所有像素值。transparentPixel 定義用於圖像中透明度的像素值。我們將使用帶有一個透明度顏色信道的 24 位圖像。圖像中的每一個像素都編碼為數組中的三個字節,順序為紅、綠和藍成分。
· 轉換圖像
知道了圖像數據就可以容易地將 AWT 圖像轉換為 SWT 圖像。只要將(由 AWT 圖像利用 getRGB(...) 返回的)整數緩沖區轉換為 SWT 圖像所使用的字節緩沖。圖 3 顯示了在 SWT 圖像的緩沖區中這些值是如何存儲的。
圖3. 將像素值寫入 SWT 圖像(圖片較大,請放大查看)和圖 2 中一樣,上圖中下面的部分顯示了圖像緩沖區的內部表示。括號中的數字顯示在緩沖區中表示其顏色值的那個像素的坐標。盡管每一個像素都用三個字節編碼,但是對於 24 位圖像,緩沖區中一行像素的大小並不總是 3*width。緩沖區中兩行像素之間可能有一些索引未使用。要知道圖像中每一行像素真正使用了多少字節(這樣就可知道緩沖區中下一行從哪個索引位置開始),必須使用 ImageData 字段的 bytesPerLine 值。
· SWT 到 Java 2D 渲染器
清單 1 顯示實現了屏外圖像技術的一般性渲染器(renderer)的源代碼。這個渲染器可以在 SWT 組件或者 Draw2D 圖像上繪制時透明地使用 Java 2D 例程。
清單 1. SWT/Draw2D Java 2D renderer
package swtgraphics2d;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import org.Eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.widgets.Display;
/**
* Helper class allowing the use of Java 2D on SWT or Draw2D graphical
* context.
* @author Yannick Saillet
*/
public class Graphics2DRenderer {
private static final PaletteData PALETTE_DATA =
new PaletteData(0xFF0000, 0xFF00, 0xFF);
private BufferedImage awtImage;
private Image swtImage;
private ImageData swtImageData;
private int[] awtPixels;
/** RGB value to use as transparent color */
private static final int TRANSPARENT_COLOR = 0x123456;
/**
* Prepare to render on a SWT graphics context.
*/
public void prepareRendering(GC gc) {
org.eclipse.swt.graphics.Rectangle clip = gc.getClipping();
prepareRendering(clip.x, clip.y, clip.width, clip.height);
}
/**
* Prepare to render on a Draw2D graphics context.
*/
public void prepareRendering(org.eclipse.draw2d.Graphics graphics) {
org.eclipse.draw2d.geometry.Rectangle clip =
graphics.getClip(new org.eclipse.draw2d.geometry.Rectangle());
prepareRendering(clip.x, clip.y, clip.width, clip.height);
}
/**
* Prepare the AWT offscreen image for the rendering of the rectangular
* region given as parameter.
*/
private void prepareRendering(int clipX, int clipY, int clipW, int clipH) {
// check that the offscreen images are initialized and large enough
checkOffScreenImages(clipW, clipH);
// fill the region in the AWT image with the transparent color
java.awt.Graphics awtGraphics = awtImage.getGraphics();
awtGraphics.setColor(new java.awt.Color(TRANSPARENT_COLOR));
awtGraphics.fillRect(clipX, clipY, clipW, clipH);
}
/**
* Returns the Graphics2D context to use.
*/
public Graphics2D getGraphics2D() {
if (awtImage == null) return null;
return (Graphics2D) awtImage.getGraphics();
}
/**
* Complete the rendering by flushing the 2D renderer on a SWT graphical
* context.
*/
public void render(GC gc) {
if (awtImage == null) return;
org.eclipse.swt.graphics.Rectangle clip = gc.getClipping();
transfERPixels(clip.x, clip.y, clip.width, clip.height);
gc.drawImage(swtImage, clip.x, clip.y, clip.width, clip.height,
clip.x, clip.y, clip.width, clip.height);
}
/**
* Complete the rendering by flushing the 2D renderer on a Draw2D
* graphical context.
*/
public void render(org.eclipse.draw2d.Graphics graphics) {
if (awtImage == null) return;
org.eclipse.draw2d.geometry.Rectangle clip =
graphics.getClip(new org.eclipse.draw2d.geometry.Rectangle());
transferPixels(clip.x, clip.y, clip.width, clip.height);
graphics.drawImage(swtImage, clip.x, clip.y, clip.width, clip.height,
clip.x, clip.y, clip.width, clip.height);
}
/**
* Transfer a rectangular region from the AWT image to the SWT image.
*/
private void transferPixels(int clipX, int clipY, int clipW, int clipH) {
int step = swtImageData.depth / 8;
byte[] data = swtImageData.data;
awtImage.getRGB(clipX, clipY, clipW, clipH, awtPixels, 0, clipW);
for (int i = 0; i < clipH; i++) {
int idx = (clipY + i) * swtImageData.bytesPerLine + clipX * step;
for (int j = 0; j < clipW; j++) {
int rgb = awtPixels[j + i * clipW];
for (int k = swtImageData.depth - 8; k >= 0; k -= 8) {
data[idx++] = (byte) ((rgb >> k) & 0xFF);
}
}
}
if (swtImage != null) swtImage.dispose();
swtImage = new Image(Display.getDefault(), swtImageData);
}
/**
* Dispose the resources attached to this 2D renderer.
*/
public void dispose() {
if (awtImage != null) awtImage.flush();
if (swtImage != null) swtImage.dispose();
awtImage = null;
swtImageData = null;
awtPixels = null;
}
/**
* Ensure that the offscreen images are initialized and are at least
* as large as the size given as parameter.
*/
private void checkOffScreenImages(int width, int height) {
int currentImageWidth = 0;
int currentImageHeight = 0;
if (swtImage != null) {
currentImageWidth = swtImage.getImageData().width;
currentImageHeight = swtImage.getImageData().height;
}
// if the offscreen images are too small, recreate them
if (width > currentImageWidth || height > currentImageHeight) {
dispose();
width = Math.max(width, currentImageWidth);
height = Math.max(height, currentImageHeight);
awtImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
swtImageData = new ImageData(width, height, 24, PALETTE_DATA);
swtImageData.transparentPixel = TRANSPARENT_COLOR;
awtPixels = new int[width * height];
}
}
}
這個渲染器包含在一個實用程序類中。這個類包含並管理屏外圖像技術所需要的 AWT 和 SWT 屏外圖像的引用。還要注意:
字段 swtImageData 和 awtPixels 分別是在像素轉移時包含 SWT 圖像的像素值的緩沖區和用於包含 AWT 圖像的像素值的緩沖區。
常量 TRANSPARENT_COLOR 包含一個作為 SWT 圖像中透明顏色的 RGB 值。因為必須定義作為透明度信道的顏色以繪制背景,所以必須為此保留一個顏色值。在代碼中我使用了隨機值 0x123456。所有使用這個顏色值的像素都按透明處理。如果這個值所表示的顏色有可能在繪制操作中用到,可以用另一個值表示透明度。