我有几个需要填充颜色渐变的Area
。我有一个将像素位置与其颜色关联的函数,如下所示:
(x,y) -> some RGBA color
我的问题是:Java API的哪一部分将允许我使用这样的函数来填充
Area
?我已经研究过Java 2D中的渐变,但是我认为它们太具体了,无法实现我想要的效果(它们不接受像我这样的函数)。
我试图理解
Paint
/ Raster
/ ColorModel
的内容,但是在我看来仍然很模糊,我仍然不明白我想要的内容是否可以用ColorModel
表示。我的印象是,此类的目的不是将像素位置与其颜色相关联,而是将颜色表示与另一种表示相关联,对吗?我想到的唯一可行的选择是使用
BufferedImage
,并在每个具有函数值的像素上使用setRGB()
。但是,由于它是一个矩形,当我超出Area
的范围时,我将不得不生成透明像素,这可能不是关于性能的最佳方法。反正这是正确的方法吗?在这里我缺少一些更合适的解决方案吗?
注意:我不是在寻找解决方案的详细实现,我只是想朝正确的方向走;-)
最佳答案
我很好奇,并实施了评论中提到的方法:
一种解决方案是简单地用所需的颜色完全填充BufferedImage,然后使用给定的区域作为Graphics#setClip绘制此图像? (不确定此处的性能,但很可能比手动测试要好...)
结果如下:
本示例使用一些“虚拟”类
class ColorFunction
{
int getColor(int x, int y)
{
...
}
}
该测试仅由随机填充的
BufferedImage
支持。此功能通过BufferedImage
方法转移到paintComponent
中。在“实际”应用程序案例中,可以并且应该在其他地方(例如在某些构造函数中)执行此操作,因此该操作只能执行一次,但这取决于应如何使用。但是,然后仅使用Area
作为Graphics2D
的剪切形状来绘制图像。看来可行,但我尚未进行任何详细的性能测试。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CustomFillingTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ColorFunction colorFunction = new ColorFunction();
Area area = createTestArea();
CustomFillingPanel customFillingPanel =
new CustomFillingPanel(colorFunction, area);
f.getContentPane().add(customFillingPanel, BorderLayout.CENTER);
f.setSize(400,200);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static Area createTestArea()
{
Font font = new Font("Monospaced", Font.BOLD, 120);
final FontRenderContext fontRenderContext =
new FontRenderContext(null, true, true);
GlyphVector glyphVector = font.createGlyphVector(
fontRenderContext, "Test");
Shape shape = glyphVector.getOutline(0,0);
AffineTransform at = AffineTransform.getTranslateInstance(40, 100);
Area area = new Area(at.createTransformedShape(shape));
return area;
}
}
class ColorFunction
{
private final BufferedImage bufferedImage;
ColorFunction()
{
this.bufferedImage = createDummyImage(1000, 1000);
}
private static BufferedImage createDummyImage(int w, int h)
{
Random random = new Random(1);
BufferedImage image =
new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics graphics = image.createGraphics();
graphics.setColor(Color.BLACK);
graphics.fillRect(0, 0, w, h);
for (int i=0; i<1000; i++)
{
int r = random.nextInt(255);
int g = random.nextInt(255);
int b = random.nextInt(255);
Color c = new Color(r,g,b);
int x = random.nextInt(w);
int y = random.nextInt(h);
int n = random.nextInt(w/10);
graphics.setColor(c);
graphics.fillRect(x,y,n,n);
}
graphics.dispose();
return image;
}
int getColor(int x, int y)
{
int w = bufferedImage.getWidth();
int h = bufferedImage.getHeight();
return bufferedImage.getRGB(x%w, y%h);
}
}
class CustomFillingPanel extends JPanel
{
private final ColorFunction colorFunction;
private final Area area;
CustomFillingPanel(ColorFunction colorFunction, Area area)
{
this.colorFunction = colorFunction;
this.area = area;
}
private static void paintIntoImage(
ColorFunction colorFunction, BufferedImage bufferedImage)
{
int w = bufferedImage.getWidth();
int h = bufferedImage.getHeight();
for (int y=0; y<h; y++)
{
for (int x=0; x<w; x++)
{
int rgb = colorFunction.getColor(x, y);
bufferedImage.setRGB(x, y, rgb);
}
}
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Rectangle b = area.getBounds();
BufferedImage bufferedImage =
new BufferedImage(b.width, b.height, BufferedImage.TYPE_INT_ARGB);
paintIntoImage(colorFunction, bufferedImage);
g.setClip(area);
g.drawImage(bufferedImage, b.x, b.y, null);
}
}