编辑:基于聊天中的长时间讨论,很明显存在对意图的误解,最初的问题来自XY-Problem:如何用蒙版图像合成图像的问题是仅针对实际问题的一种解决方案尝试 - 即在平铺贴图上绘制一些阴影/灯光效果。帖子的原始版本可以在修订历史中看到。
实际目标显然是在图像上添加“灯光效果”。这是一个如何实现的示例:
- 原始图像在背景中绘制
- 在图像上绘制了“阴影图像”。
“阴影图像”最初是几乎不透明、几乎黑色的图像。灯光被绘制到此图像中,带有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();
}
}
(后期)编辑对于 cmets 中的请求:
要添加另一个阴影(不管现有的灯光),可以创建一个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();
}
}