java - SWT<->AWT 图像转换之间的透明度

标签 java image swt awt transparency

我创建了一个对话框,用户可以在其中浏览图像,然后查看在 Canvas 上绘制的图像的预览。图像被缩放,以便在适合盒子时保持其纵横比。我使用了在 this answer 中找到的调整大小的方法,这涉及将图像从 SWT 转换为 AWT,执行调整大小,从 AWT 转换回 SWT,最后将其绘制在 Canvas 上。由于此过程在时间和处理能力方面的成本非常高,我选择如果图像大小正确则跳过调整大小的步骤,因此不需要以任何方式进行转换。

处理具有 alpha 透明度的图像时会出现此问题。在某些情况下,首先转换的具有透明度的图像会以黑色背景绘制在 Canvas 上。同一图像的副本已调整为 Canvas 的精确大小,因此未转换,具有白色背景。

Fluttershy's background is so flaky and inconsistent.

然而,情况并非总是如此。一些具有透明背景的图像将始终显示为白色,无论它们是否已转换。

They've seen angrier days.

是什么导致具有透明背景的图像在 SWT Canvas 中用一种颜色绘制在另一种颜色之上?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;
}

最佳答案

好的,因为我认为我终于理解了您的要求,所以我决定发布一个答案。让我确保我理解正确:

您想在应用中以某种可以调整大小的 Widget 显示 Image。图像应随其父图像调整大小并保持透明度。

您可以使用 Canvas 并将图像绘制到使用 GC#drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight) 的适当尺寸.

要使用该功能,您需要 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();
}

这是启动后的样子:

enter image description here

调整大小后:

enter image description here


注意:我没有时间在 Windows 上测试它,但我相当有信心它能正常工作。

它也适用于 Windows!


编辑:

添加这些行以启用抗锯齿:

e.gc.setAntialias(SWT.ON);
e.gc.setAdvanced(true);

关于java - SWT<->AWT 图像转换之间的透明度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19258200/

相关文章:

java - 在 android 中使用 php session 更新在线数据库

java - Android API 无法获取 X509Certificate

android - 是否可以在 Android TextView 中显示来自 html 的内联图像?

c# - 绑定(bind)列表和 UI 控件,编辑时不更新

java - 用于 SWT/AWT 的图形可视化库

java - 如何通过拖动角来调整复合 Material 的大小

java - 通过 RequestDispatcher 检测 JSP 页面中的异常

java - 保存自定义 ListView 的实例状态?

python - 在 python 中旋转大图像 (85000x85000x3)

java - 关闭应用程序时 SWT 更新 UI