【问题标题】:Is it possible to draw a line with a semi-transparent color opaquely on top of other pixels in a BufferedImage?是否可以在 BufferedImage 中的其他像素之上不透明地绘制一条半透明颜色的线?
【发布时间】:2020-07-30 11:12:11
【问题描述】:

我尝试准备一个半透明的 BufferedImage,这样无论在背景顶部绘制此图像的任何位置,都会部分发光。为此,我使用 Graphics.drawLine() 的笔画 > 1 和 alpha 分量

然而,这不是我想要的。如果可能的话,我想用我的半透明颜色进行绘制,就好像它完全不透明一样,并且颜色的 alpha 分量只是第四个颜色分量。我想将我正在绘制的颜色(包括 alpha 组件)复制到图像中,替换之前的所有内容。

有没有办法做到这一点?

以下代码会生成一个简单的半透明红色 X,它可以让背景部分地透过它所绘制的任何位置。然而,它将在两条线相交的地方有一个较暗的部分。我希望能够在没有这个较暗部分的情况下绘制 X。这可能吗(同时仍在使用 Graphics.drawLine())?

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;

public class Test {
    
    public static void main(String[] args) {
        // create a new BufferedImage with alpha channel
        BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = img.createGraphics();
        // set a semi-transparent color and a stroke wider than one pixel
        g.setColor(new Color(255, 0, 0, 128 /* alpha; semi-transparent */));
        g.setStroke(new BasicStroke(2));
        // draw a cross; where the lines cross the color will (logically) be darker
        g.drawLine(0, 0, 100, 100);
        g.drawLine(0, 100, 100, 0);
        // use the image somehow, in this case write it to file
        writeImage(img, "test.png");
    }
    
    private static void writeImage(BufferedImage img, String fileName) {
        try {
            ImageIO.write(img, "png", new File(fileName));
        }
        catch (IOException e) {
            System.out.println(e);
        }
    }
}

当然,我可以通过实现我自己的线条绘制方法并直接操作像素来手动解决这个问题。 (不确定这是否会产生我需要的新的剪辑问题。)但是,这会大大增加我想避免的工作量。

进一步的限制:我仅限于 Java 7。

【问题讨论】:

  • 也许画三条线而不是两条。在相反的方向画一条长对角线和两条短对角线。这样线条就不会重叠。只是一个建议:-)
  • 对于这个特定的例子,这会起作用,是的,但不是一般的。我想在我不知道之前画过什么以及在哪里画过其他东西的地方画线。

标签: java graphics2d


【解决方案1】:
  • 创建第二张图片。
  • 用不透明的颜色在第二张图像上绘制。
  • 使用半透明 Alpha 将第二张图片复制到原始图片上。

 

import java.io.*;
import javax.imageio.*;

public class TranslucentX {
    
    public static void main(String[] args) {
        BufferedImage x = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = x.createGraphics();
        g.setColor(new Color(255, 0, 0));
        g.setStroke(new BasicStroke(2));
        // draw a cross; where the lines cross the color will (logically) be darker
        g.drawLine(0, 0, 100, 100);
        g.drawLine(0, 100, 100, 0);
        g.dispose();

        // create a new BufferedImage with alpha channel
        BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
        g = img.createGraphics();
        // Draw opaque image using translucency.
        g.setComposite(
            AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
        g.drawImage(x, 0, 0, null);
        g.dispose();

        // use the image somehow, in this case write it to file
        writeImage(img, "test.png");
    }
    
    private static void writeImage(BufferedImage img, String fileName) {
        try {
            ImageIO.write(img, "png", new File(fileName));
        }
        catch (IOException e) {
            System.out.println(e);
        }
    }
}

【讨论】:

  • 使用第二张图片的想法很有趣。我也不知道 AlphaComposite 的存在,谢谢你让我注意到这一点。不幸的是,该课程的文档对我来说有点难以访问。我是否正确理解/猜测您在这里对该类的使用是一种以相同方式影响每个像素的全局操作?这显然解决了我的例子。但我希望能够用 不同的 alpha 值绘制线条。
  • 不过,使用第二张图片的好处可能略有不同。我也许可以在两个不同的图像上绘制相同的线条,在一个不透明的图像上,完全根据您的建议,例如,在第二个图像上,alpha 值可以绘制为红色。在第二步中,可以再次组合两幅图像,并将第二幅图像的红色转换回第一幅图像的 alpha 值。我必须思考和测试一下,看看这是否可以这样工作。如果确实如此,那么感谢您的输入。比实现我自己的画线方法更好。
  • 我不太确定您需要什么,但我怀疑您可以从第二张图像重复复制,为您的线条可能具有的每个不透明度复制一次。意思是,如果你有一些 50% alpha 的线条和一些 30% alpha 的线条,用不透明的颜色绘制 50% 的线条,然后像我的例子一样复制它们;然后清除副图像,用不透明的颜色绘制其他线条,并将副图像复制到主图像上,并使用0.3f 初始化的 AlphaComposite。重复尽可能多的不同不透明度。
  • 我也发现所有 AlphaComposite 规则都令人生畏。我建议在 JDK 的 demo/jfc/J2Ddemo 目录下运行 Java2D Demo。 (在 JDK 9 或 10 中不可用;Java 8 版本为 available separately。)一旦运行,选择“Composite”选项卡,然后通过单击放大 AlphaComposite 规则迷你窗口(它位于右上角区域选项卡内),或选择“demos.Composite.ACrules”内部选项卡。它的动画大约每五秒循环一次。
  • 我现在意识到我不应该把问题缩小这么多,因为它会阻止像你这样乐于助人的人完全理解我需要朝哪个方向发展。更广泛的问题是我想画一条粗的之字形线。这个之字形包含从一侧到另一侧的颜色渐变(因此,不是从起点到终点,而是从左到右)。我试图通过在彼此旁边画线来解决这个问题。用 stroke > 1 来填补空白。只要不涉及 alpha 通道,此算法就可以完美运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-25
  • 1970-01-01
  • 1970-01-01
  • 2021-03-22
  • 2012-10-21
相关资源
最近更新 更多