当前位置: 首页 > 知识库问答 >
问题:

SWTAWT图像转换之间的透明度

史良哲
2023-03-14

我创建了一个对话框,用户可以在其中浏览图像,然后看到画布上绘制的图像的预览。图像被缩放,以便在框中安装时保持其宽高比。我使用了在这个答案中找到的调整大小的方法,包括将图像从SWT转换为AWT,执行调整大小,从AWT转换回SWT,最后在画布上绘制。由于这个过程在时间和处理能力方面非常昂贵,如果图像大小完全正确,我选择跳过调整大小的步骤,因此不需要以任何方式进行转换。

在处理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;
}

共有2个答案

段干宜
2023-03-14

现在回答有点晚,但由于我刚刚有过类似的经历和问题,我认为我的发现可能会帮助其他人。

最初的问题在于提供的执行SWT的代码-

修复代码以处理透明度相对简单,但有更好的解决方案,不需要通过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();
钦侯林
2023-03-14

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

你想在你的应用程序中,在某种可以调整大小的小部件中显示图像。图像应与其父对象一起调整大小,并保持透明度。

您可以使用Canvas并使用GC#drawImage(图像图像,int-srcX,int-srcY,int-srcWidth,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();
}

这是开始后的样子:

调整大小后:

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

它也适用于Windows!

编辑:

添加以下行以启用抗锯齿:

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

 类似资料:
  • 问题内容: 如何将图像的白色背景转换为透明背景?谁能给我打电话怎么做? 问题答案: Google的第一个结果是: 使颜色透明 http://www.rgagnon.com/javadetails/java-0265.html 它使图像的蓝色部分透明,但是我敢肯定您可以对其进行调整以使用白色 (提示:传递给函数,而不是)

  • #klem1,#klem2 { opacity:0.4; filter:alpha(opacity=40); /* For IE8 and earlier */ } #klem1:hover,#klem2:hover { opacity:1.0; filter:alpha(opacity=100); /* For IE8 and earlier */ } div.background { widt

  • 问题内容: 我有一个Android应用程序,可将图像加载为位图并将其显示在ImageView中。问题在于图像似乎具有透明背景;这会导致图像上的某些黑色文本在黑色背景下消​​失。 如果将ImageView背景设置为白色,则可以完成这种工作,但是在图像上会出现丑陋的大边框,将其拉伸以适合父对象(实际图像在中间缩放)。 所以-我想将位图中的透明像素转换为纯色-但我不知道该怎么做! 任何帮助将不胜感激!

  • 问题内容: 所以我有两个图像,我想显示在彼此的顶部。这个 上面的图像应该是透明的,这样底部的图像是透明的 可见。 Here is my code so far: With the face in the bottom and the eyes on top. 问题答案: Try this 我没有你的两个源图像,所以我不能确定它将与工作 他们。如有任何问题,请提供两者的原件。

  • 我尝试将背景透明的tiff格式的图像转换为jpeg,以将其大小调整为200x200或1200x1200,但在转换时,背景变为黑色,我希望在转换后保持背景透明或白色 我的代码如下: 这在java JAI中是如何实现的?

  • 我正在处理位图图像的透明部分用洋红色着色(在一些语言中,可以将颜色设置为透明)。我试图在原始位图图像中透明洋红色的像素。 我从SD卡加载位图: 将其复制到另一个位图以使其可变: 然后逐像素扫描,找到洋红色的像素,并尝试改变它们的透明度。 但是那些我希望变成透明的像素被转换成黑色。通过更改alpha,我发现最终颜色从中提到的颜色(不提及alpha)变为黑色。例如,变为白色,为灰色,而变黑。 我不知道