如何使用 Graphics2D 获取黑白图像,并使用它来定义应该在另一幅图像上渲染什么,不应该渲染什么?
例如,如果我有一张图片,比如一 block 田地,那 block 田地上有一头牛,而在另一张相同尺寸的图片上,我在黑色背景上画了一个白框,在牛的相同坐标处,当在 Java 中呈现的图像将全黑,除了我有白框的奶牛?
最佳答案
EDIT: Based on a long discussion in the chat, it became clear that there was a misunderstanding about the intention, and the original question suffered from the XY-Problem: The question of how to compose an image with a masking image was only about one solution attempt for the actual problem - namely painting some shadow/light effects on a tile map. The original versions of the post can be seen in the revision history.
实际目标显然是在图像上添加“光效”。这是如何实现这一目标的示例:
- 原图在背景中绘制
- 在图像上绘制了一个“阴影图像”。
“阴影图像”最初是一个近乎不透明、近乎黑色的图像。使用 RadialGradientPaint
将灯光绘制到此图像中。选择这种涂料的颜色是为了使阴影图像在应该有灯光的地方不那么不透明和不那么黑。这会导致这些区域看起来很亮,而其他部分仍然很暗。
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MultipleGradientPaint.CycleMethod;
import java.awt.Point;
import java.awt.RadialGradientPaint;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class LightEffectTest2
{
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new LightEffectTest2();
}
});
}
public LightEffectTest2()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new LightEffectPanel2());
f.setSize(600,600);
f.setVisible(true);
}
}
class LightEffectPanel2 extends JPanel implements MouseMotionListener
{
private Point point = new Point(0,0);
private BufferedImage image;
private BufferedImage shadow;
public LightEffectPanel2()
{
image = createExampleImage(600,600);
shadow = new BufferedImage(image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
addMouseMotionListener(this);
}
private static BufferedImage createExampleImage(int w, int h)
{
BufferedImage image = new BufferedImage(w, h,
BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
Random random = new Random(0);
for (int i=0; i<200; i++)
{
int x = random.nextInt(w);
int y = random.nextInt(h);
Color c = new Color(
random.nextInt(255),
random.nextInt(255),
random.nextInt(255));
g.setColor(c);
g.fillOval(x-20, y-20, 40, 40);
}
g.dispose();
return image;
}
@Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.drawImage(image, 0,0,null);
drawLights();
g.drawImage(shadow, 0,0, null);
}
private void drawLights()
{
Graphics2D g = shadow.createGraphics();
g.setComposite(AlphaComposite.Src);
g.setColor(new Color(0,0,16,240));
g.fillRect(0,0,getWidth(),getHeight());
drawLight(g, new Point(100,100));
drawLight(g, point);
g.dispose();
}
private void drawLight(Graphics2D g, Point pt)
{
float radius = 100;
g.setComposite(AlphaComposite.DstOut);
Point2D center = new Point2D.Float(pt.x, pt.y);
float[] dist = {0.0f, 1.0f};
Color[] colors = {new Color(255,255,255,255), new Color(0,0,0,0) };
RadialGradientPaint p =
new RadialGradientPaint(
center, radius, dist, colors, CycleMethod.NO_CYCLE);
g.setPaint(p);
g.fillOval(pt.x-(int)radius,pt.y-(int)radius,(int)radius*2,(int)radius*2);
}
@Override
public void mouseDragged(MouseEvent e) {
}
@Override
public void mouseMoved(MouseEvent e) {
point = e.getPoint();
repaint();
}
}
(late) EDIT For the request in the comments:
要添加另一个阴影(无论现有灯光如何),可以创建一个drawShadow
方法,在绘制灯光后重新应用阴影。它主要使用另一种 RadialGradientPaint
来部分“恢复”原始的、不透明的暗影图像。
(这里给阴影加了一个更锐利的边框,让效果更明显)
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MultipleGradientPaint.CycleMethod;
import java.awt.Point;
import java.awt.RadialGradientPaint;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class LightEffectTest3
{
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new LightEffectTest3();
}
});
}
public LightEffectTest3()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new LightEffectPanel3());
f.setSize(600,600);
f.setVisible(true);
}
}
class LightEffectPanel3 extends JPanel implements MouseMotionListener
{
private Point point = new Point(0,0);
private BufferedImage image;
private BufferedImage shadow;
public LightEffectPanel3()
{
image = createExampleImage(600,600);
shadow = new BufferedImage(image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
addMouseMotionListener(this);
}
private static BufferedImage createExampleImage(int w, int h)
{
BufferedImage image = new BufferedImage(w, h,
BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
Random random = new Random(0);
for (int i=0; i<200; i++)
{
int x = random.nextInt(w);
int y = random.nextInt(h);
Color c = new Color(
random.nextInt(255),
random.nextInt(255),
random.nextInt(255));
g.setColor(c);
g.fillOval(x-20, y-20, 40, 40);
}
g.dispose();
return image;
}
@Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.drawImage(image, 0,0,null);
drawLights();
g.drawImage(shadow, 0,0, null);
}
private void drawLights()
{
Graphics2D g = shadow.createGraphics();
g.setComposite(AlphaComposite.Src);
g.setColor(new Color(0,0,16,240));
g.fillRect(0,0,getWidth(),getHeight());
drawLight(g, new Point(200,200));
drawLight(g, point);
drawShadow(g, new Point(250,250));
g.dispose();
}
private void drawLight(Graphics2D g, Point pt)
{
float radius = 150;
g.setComposite(AlphaComposite.DstOut);
Point2D center = new Point2D.Float(pt.x, pt.y);
float[] dist = {0.0f, 1.0f};
Color[] colors = {new Color(255,255,255,255), new Color(0,0,0,0) };
RadialGradientPaint p =
new RadialGradientPaint(
center, radius, dist, colors, CycleMethod.NO_CYCLE);
g.setPaint(p);
g.fillOval(pt.x-(int)radius,pt.y-(int)radius,
(int)radius*2,(int)radius*2);
}
private void drawShadow(Graphics2D g, Point pt)
{
float radius = 75;
g.setComposite(AlphaComposite.DstOver);
Point2D center = new Point2D.Float(pt.x, pt.y);
float[] dist = {0.0f, 0.7f, 1.0f};
Color[] colors = {
new Color(0,0,0,200),
new Color(0,0,0,150),
new Color(255,255,255,0) };
RadialGradientPaint p =
new RadialGradientPaint(
center, radius, dist, colors, CycleMethod.NO_CYCLE);
g.setPaint(p);
g.fillOval(pt.x-(int)radius,pt.y-(int)radius,
(int)radius*2,(int)radius*2);
}
@Override
public void mouseDragged(MouseEvent e) {
}
@Override
public void mouseMoved(MouseEvent e) {
point = e.getPoint();
repaint();
}
}
关于Java2D Alpha 映射图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21704189/