The goal here is to smooth a colored drawing, to avoid the tile effect.
Although they look similar, the path for the two images above is pretty different.
The regular path to draw on a javax.swing.JPanel is to override the method
public void paintComponent(Graphics gr)
We have defined an array of colors, for the example
private final static int[][] COLOR_VALUES =
{
{255, 255, 255 },
{208, 244, 250 },
{161, 233, 246 },
{115, 222, 241 },
{68, 211, 237 },
{21, 200, 232 },
{21, 207, 223 },
{20, 214, 214 },
...
{59, 2, 64 },
{30, 1, 32 },
{0, 0, 0 }
};
The tile panel
The method used to the tile (left) approach would look like this:
private static JPanel colorPane = new JPanel()
{
public void paintComponent(Graphics gr)
{
((Graphics2D)gr).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
((Graphics2D)gr).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = this.getWidth();
int h = this.getHeight();
paintColors(gr, w, h);
gr.setColor(Color.black);
gr.setFont(gr.getFont().deriveFont(40f));
String str = "Some text on top";
int strWidth = gr.getFontMetrics(gr.getFont()).stringWidth(str);
gr.drawString(str, (w / 2) - (strWidth / 2), (h / 2) + (40 / 2));
}
private void paintColors(Graphics gr, int w, int h)
{
// Draw 7x7
int wStep = (int)((float)w / 7f);
int hStep = (int)((float)h / 7f);
for (int hor=0; hor<7; hor++)
{
for (int vert=0; vert<7; vert++)
{
Color c = new Color(COLOR_VALUES[(hor * 7) + vert][0],
COLOR_VALUES[(hor * 7) + vert][1],
COLOR_VALUES[(hor * 7) + vert][2]);
gr.setColor(c);
gr.fillRect(hor * wStep, vert * hStep, wStep, hStep);
}
}
}
};
The smoothed panel
The other approach is a bit less straightforward.
The way to proceed is to
- Generate an Image
- Apply a blur filter on it
- Display the image
The blur filter could look like this:
public static BufferedImage blur(BufferedImage bimg, int matrixDim)
{
float blurMatrix[] = new float[matrixDim * matrixDim];
for (int i=0; i< blurMatrix.length; i++)
blurMatrix[i] = 1f / (float)(matrixDim * matrixDim);
Kernel kernel = new Kernel(matrixDim, matrixDim, blurMatrix);
BufferedImageOp blurFilter = new ConvolveOp(kernel,
ConvolveOp.EDGE_NO_OP,
null);
bimg = blurFilter.filter(bimg, null);
return bimg;
}
And it can be used as follow in the paintComponent method:
public void paintComponent(Graphics gr)
{
((Graphics2D)gr).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
((Graphics2D)gr).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = this.getWidth();
int h = this.getHeight();
// Create the image
BufferedImage bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
// Create a graphics contents on the buffered image
Graphics2D g2d = bufferedImage.createGraphics();
this.paintColors((Graphics)g2d, w, h);
// Graphics context no longer needed so dispose it
g2d.dispose();
// Blur it
bufferedImage = blur(bufferedImage, w / 7);
// Display it
gr.drawImage(bufferedImage, 0, 0, null);
gr.setColor(Color.black);
gr.setFont(gr.getFont().deriveFont(40f));
String str = "Some text on top";
int strWidth = gr.getFontMetrics(gr.getFont()).stringWidth(str);
gr.drawString(str, (w / 2) - (strWidth / 2), (h / 2) + (40 / 2));
}
And that's it!
It's fully compatible with transparency,
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
But beware, depending on the size of the Kernel matrix, the blur operation can be pretty demanding.