我创建了一个对话框,用户可以在其中浏览图像,然后查看在画布上绘制的图像的预览。图像缩放,以便在装入框中时保持其纵横比。我使用this answer中的调整大小的方法,包括将图像从SWT转换为AWT,执行调整大小,从AWT转换回SWT,最后在画布上绘制。由于此过程在时间和处理能力方面非常昂贵,我选择跳过调整大小步骤,如果图像的大小正确,因此不需要以任何方式进行转换。 / p>
处理具有Alpha透明度的图像时出现问题。在某些情况下,具有首先转换的透明度的图像将在具有黑色背景的画布上绘制。同一图像的副本已经调整为画布的确切大小,因此未转换,具有白色背景。
然而,情况并非总是如此。一些具有透明背景的图像将始终显示为白色,无论它们是否已被转换。
是什么原因导致具有透明背景的图像在SWT画布中使用一种颜色而不是另一种颜色进行绘制? AWT转换如何影响它,如果我这样做,如何使其变得一致希望?
以下是转换代码,全部来自其他来源:
public static BufferedImage convertToAWT (ImageData data) {
ColorModel colorModel = null;
PaletteData palette = data.palette;
if (palette.isDirect) {
colorModel = new DirectColorModel(data.depth, palette.redMask, palette.greenMask, palette.blueMask);
BufferedImage bufferedImage = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(data.width, data.height),
false, null);
WritableRaster raster = bufferedImage.getRaster();
int[] pixelArray = new int[3];
for (int y = 0; y < data.height; y++) {
for (int x = 0; x < data.width; x++) {
int pixel = data.getPixel(x, y);
RGB rgb = palette.getRGB(pixel);
pixelArray[0] = rgb.red;
pixelArray[1] = rgb.green;
pixelArray[2] = rgb.blue;
raster.setPixels(x, y, 1, 1, pixelArray);
}
}
return bufferedImage;
}
else {
RGB[] rgbs = palette.getRGBs();
byte[] red = new byte[rgbs.length];
byte[] green = new byte[rgbs.length];
byte[] blue = new byte[rgbs.length];
for (int i = 0; i < rgbs.length; i++) {
RGB rgb = rgbs[i];
red[i] = (byte) rgb.red;
green[i] = (byte) rgb.green;
blue[i] = (byte) rgb.blue;
}
if (data.transparentPixel != -1) {
colorModel = new IndexColorModel(data.depth, rgbs.length, red, green, blue, data.transparentPixel);
} else {
colorModel = new IndexColorModel(data.depth, rgbs.length, red, green, blue);
}
BufferedImage bufferedImage = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(data.width, data.height),
false, null);
WritableRaster raster = bufferedImage.getRaster();
int[] pixelArray = new int[1];
for (int y = 0; y < data.height; y++) {
for (int x = 0; x < data.width; x++) {
int pixel = data.getPixel(x, y);
pixelArray[0] = pixel;
raster.setPixel(x, y, pixelArray);
}
}
return bufferedImage;
}
}
public static ImageData convertToSWT (BufferedImage bufferedImage) {
if (bufferedImage.getColorModel() instanceof DirectColorModel) {
DirectColorModel colorModel = (DirectColorModel) bufferedImage.getColorModel();
PaletteData palette = new PaletteData(colorModel.getRedMask(), colorModel.getGreenMask(), colorModel.getBlueMask());
ImageData data = new ImageData(bufferedImage.getWidth(), bufferedImage.getHeight(), colorModel.getPixelSize(), palette);
WritableRaster raster = bufferedImage.getRaster();
int[] pixelArray = new int[3];
for (int y = 0; y < data.height; y++) {
for (int x = 0; x < data.width; x++) {
raster.getPixel(x, y, pixelArray);
int pixel = palette.getPixel(new RGB(pixelArray[0], pixelArray[1], pixelArray[2]));
data.setPixel(x, y, pixel);
}
}
return data;
}
else if (bufferedImage.getColorModel() instanceof IndexColorModel) {
IndexColorModel colorModel = (IndexColorModel) bufferedImage.getColorModel();
int size = colorModel.getMapSize();
byte[] reds = new byte[size];
byte[] greens = new byte[size];
byte[] blues = new byte[size];
colorModel.getReds(reds);
colorModel.getGreens(greens);
colorModel.getBlues(blues);
RGB[] rgbs = new RGB[size];
for (int i = 0; i < rgbs.length; i++) {
rgbs[i] = new RGB(reds[i] & 0xFF, greens[i] & 0xFF, blues[i] & 0xFF);
}
PaletteData palette = new PaletteData(rgbs);
ImageData data = new ImageData(bufferedImage.getWidth(), bufferedImage.getHeight(), colorModel.getPixelSize(), palette);
data.transparentPixel = colorModel.getTransparentPixel();
WritableRaster raster = bufferedImage.getRaster();
int[] pixelArray = new int[1];
for (int y = 0; y < data.height; y++) {
for (int x = 0; x < data.width; x++) {
raster.getPixel(x, y, pixelArray);
data.setPixel(x, y, pixelArray[0]);
}
}
return data;
}
return null;
}
答案 0 :(得分:2)
好的,因为我想我终于理解了你的要求,我决定发一个答案。让我确保我理解正确:
您希望在应用中以某种可以调整大小的Image
显示Widget
。图像应该与其父级一起调整大小并保持透明性。
您可以使用Label
并使用GC#drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight)
将图像绘制到适当的大小,而不是调整图像大小并在Widget
或其他Canvas
中显示图像。
要使用该功能,您需要Image
的大小,Canvas
的大小以及图像的正确缩放(宽高比)版本的大小。
以下是代码:
public static void main(String[] args)
{
Display display = Display.getDefault();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
/* Load the image and calculate size and ratio */
final Image image = new Image(display, "settings.png");
final Rectangle imageSize = image.getBounds();
final double imageRatio = 1.0 * imageSize.width / imageSize.height;
/* Define the canvas and set the background color */
final Canvas canvas = new Canvas(shell, SWT.BORDER);
canvas.setBackground(display.getSystemColor(SWT.COLOR_DARK_GRAY));
canvas.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
canvas.addListener(SWT.Paint, new Listener()
{
@Override
public void handleEvent(Event e)
{
Rectangle canvasSize = canvas.getBounds();
double canvasRatio = 1.0 * canvasSize.width / canvasSize.height;
int newHeight;
int newWidth;
/* Determine scaled height and width of the image */
if (canvasRatio > imageRatio)
{
newWidth = (int) (imageSize.width * (1.0 * canvasSize.height / imageSize.height));
newHeight = (int) (canvasSize.height);
}
else
{
newWidth = (int) (canvasSize.width);
newHeight = (int) (imageSize.height * (1.0 * canvasSize.width / imageSize.width));
}
/* Compute position such that the image is centered in the canvas */
int top = (int) ((canvasSize.height - newHeight) / 2.0);
int left = (int) ((canvasSize.width - newWidth) / 2.0);
/* Draw the image */
e.gc.drawImage(image, 0, 0, imageSize.width, imageSize.height, left, top, newWidth, newHeight);
}
});
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
/* DISPOSE THE IMAGE !!! */
image.dispose();
}
这就是启动后的样子:
并在调整大小后:
注意:我没时间在Windows上测试它,但我相信它有效。
它也适用于Windows!
修改强>:
添加以下行以启用抗锯齿:
e.gc.setAntialias(SWT.ON);
e.gc.setAdvanced(true);
答案 1 :(得分:2)
现在答案有点晚了,但由于我刚刚遇到类似的经历和问题,我认为我的发现可能有助于其他人。
最初的问题是使用提供的代码执行SWT-&gt; AWT和AWT-&gt; SWT转换。当使用直接调色板时,透明度(alpha)根本不适合,但是它适用于索引调色板,这就是为什么有些图像可以工作而有些图像无效。
修复代码以应对透明度相对简单,但有更好的解决方案无需通过AWT获取调整大小的图像。
如果您不关心转换后图像的抗锯齿(平滑度),那么一个简单的解决方案就是:
Image newImage = new Image(image.getDevice(),
image.getImageData().scaledTo(newWidth, newHeight));
如果您关心平滑度,那么解决方案几乎一样简单:
Image newImage = new Image(image.getDevice(), newWidth, newHeight);
GC gc = new GC(newImage);
gc.setAdvanced(true);
gc.setAntialias(SWT.ON);
gc.drawImage(image, 0, 0, origWidth, origHeight, 0, 0, newWidth, newHeight);
gc.dispose();