在BufferedImage上使用半透明颜色不透明地绘制一条线是否可能?

huangapple go评论93阅读模式
英文:

Is it possible to draw a line with a semi-transparent color opaquely on top of other pixels in a BufferedImage?

问题

以下是您提供的内容的中文翻译:

我尝试准备一个带有半透明效果的 BufferedImage,以便无论在哪里绘制此图像,都可以部分透过底图。为此,我使用了 Graphics.drawLine(),其中画笔的宽度大于1,并且颜色具有 alpha 分量小于 255,即半透明。我经常绘制的线条会重叠或相交,以确保不会留下间隙。当发生这种交叉时,线条的颜色会叠加,即之前存在的颜色和我正在绘制的半透明颜色将产生新的颜色。这是合乎逻辑的。

然而,这不是我想要的。如果可能的话,我希望使用我的半透明颜色绘制,就好像它是完全不透明的,颜色的 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) {
		// 创建一个带有 alpha 通道的新 BufferedImage
		BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = img.createGraphics();
		// 设置半透明颜色和宽度大于一个像素的画笔
		g.setColor(new Color(255, 0, 0, 128 /* alpha; 半透明 */));
		g.setStroke(new BasicStroke(2));
		// 绘制一个交叉; 在线条交叉的地方,颜色将(逻辑上)变暗
		g.drawLine(0, 0, 100, 100);
		g.drawLine(0, 100, 100, 0);
		// 以某种方式使用图像,在本例中将其写入文件
		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。

英文:

I try to prepare a BufferedImage with semi-transparency so that whereever this image is painted on top of the background will partially shine through. For this purpose I use among other things Graphics.drawLine() with a stroke > 1 and colors that have an alpha component < 255, i.e. are semi-transparent. Lines I draw will often overlap or intersect to make sure there will be no gaps. When such intersections occur, the colors of the lines will stack, i.e. the color that was there before and the semi-transparent color I am painting with will result in a new color. Which is logical.

That is not what I want, however. If possible, I would like to paint with my semi-transparent color as if it was completely opaque and the alpha component of the color just a fourth color component. I would like to copy the color I am painting with - including the alpha component - exactly to the image, replacing everything that was there before.

Is there a way to do this?

The following code produces a simple semi-transparent red X, that will let the background partially shine through wherever it is painted on top of. It will have, however, a darker part where both lines intersect. I would like to be able to paint the X without this darker part. Is that possible (while still using 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, &quot;test.png&quot;);
	}
	
	private static void writeImage(BufferedImage img, String fileName) {
		try {
			ImageIO.write(img, &quot;png&quot;, new File(fileName));
		}
		catch (IOException e) {
			System.out.println(e);
		}
	}
}

I could, of course, solve this manually by implementing my own line drawing method and manipulate the pixels directly. (Not sure if that would create new problems with clipping which I also need.) However, that would increase the effort substantially which I would like to avoid.

A further constraint: I am restricted to Java 7.

答案1

得分: 1

以下是您提供的代码的翻译部分:

// 创建第二个图像。
// 使用不透明颜色在第二个图像上绘制。
// 使用半透明 alpha 复制第二个图像到原始图像上。

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

public class TranslucentX {
    
    public static void main(String[] args) {
        // 创建一个具有 alpha 通道的新 BufferedImage
        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));
        // 绘制一个交叉; 在交叉点处的颜色将(逻辑上)变暗
        g.drawLine(0, 0, 100, 100);
        g.drawLine(0, 100, 100, 0);
        g.dispose();

        // 创建一个具有 alpha 通道的新 BufferedImage
        BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
        g = img.createGraphics();
        // 使用透明度绘制不透明图像。
        g.setComposite(
            AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
        g.drawImage(x, 0, 0, null);
        g.dispose();

        // 在某种方式下使用图像,本例中将其写入文件
        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);
        }
    }
}

请注意,代码中的注释已被翻译成中文。

英文:
  • Create a second image.
  • Draw on that second image with opaque colors.
  • Copy that second image onto your original image using translucent 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, &quot;test.png&quot;);
}
private static void writeImage(BufferedImage img, String fileName) {
try {
ImageIO.write(img, &quot;png&quot;, new File(fileName));
}
catch (IOException e) {
System.out.println(e);
}
}
}

huangapple
  • 本文由 发表于 2020年7月30日 19:12:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/63171933.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定