Java2D/Swing:将具有文本抗锯齿的组件呈现到BuffereImage
我想将一个JavaSwing组件,例如一个JButton,也放在JFrame上,呈现到一个BuffereImage。这通常是可行的,但有一个主要缺点:文本抗锯齿,尤其是“LCD”抗锯齿模式,在渲染到BuffereImage时不起作用
我将一些示例代码放在一起演示问题,但首先是我的系统信息:
- 操作系统:Windows 7 64位
- JVM:1.6.0_26-b03(32位)
下面的示例代码将创建一个简单的JFrame,在其上放置一个JButton,然后将JButton呈现到一个文件“test.png”:
public class TextAntiAliasingTest
{
public TextAntiAliasingTest() throws IOException
{
// Create Test-Button which will be rendered to an image
JButton button = new JButton( "The Test-Button" );
button.setSize( 200, 70 );
button.setLocation( 200, 150 );
// Create JFrame
final JFrame frame = new JFrame();
frame.setSize( 800, 600 );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setLayout( null );
frame.setLocationRelativeTo( null );
frame.add( button );
// Show JFrame
SwingUtilities.invokeLater( new Runnable() {
@Override public void run() {
frame.setVisible( true );
}
});
// Render JButton to an BufferedImage
BufferedImage image = new BufferedImage( 800, 600, BufferedImage.TYPE_INT_ARGB );
Graphics2D g2d = (Graphics2D)image.getGraphics();
button.paint( g2d );
// Write BufferedImage to a PNG file
ImageIO.write( image, "PNG", new File( "test.png" ) );
}
public static void main( String[] args ) throws Exception
{
UIManager.setLookAndFeel( "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" );
System.setProperty( "awt.useSystemAAFontSettings", "lcd" );
new TextAntiAliasingTest();
}
}
下图显示了屏幕上JFrame中的JButton与图像文件中相同渲染JButton之间的差异:
实际上,图像中有一些文本消除混叠,但没有显示在JFrame屏幕上的LCD优化消除混叠(默认LookAndFeel也会出现此问题,而不仅仅是“WindowsLookAndFeel”)
我已经尝试在“g2d”(BuffereImage的Graphics2D上下文)上明确设置文本抗锯齿的渲染提示,如下所示:
g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB );
但这根本没有效果
我迫切需要将JButton渲染为一个图像文件,就像它在屏幕上渲染一样(这只是一个示例,实际上我需要渲染一些更复杂的组件,这些组件都存在抗锯齿问题),我希望有一个真正的解决方案,而不需要任何讨厌的解决方法,如截图或其他
我真的很感激任何帮助-非常感谢
# 1 楼答案
您希望(a)半透明的BuffereImage与JButton外观一样好,或者(b)希望JButton和BuffereImage外观相同
如果(b),你能有一个半透明的按钮吗?它看起来会和你的半透明BuffereImage一样吗
如果(a)那么很难做到这一点,您可以将JButton绘制为非半透明的BufferedImage(如果Java有灰度BufferedImage,那么使用这个)。这将最终成为最终BuffereImage的alpha通道的负片(黑色像素变为完全不透明,白色完全透明。)要获得BuffereImage中像素的颜色,您需要将任何不透明的像素设置为黑色-像素的透明度应使其显示为您想要的灰色
# 2 楼答案
反正可能已经太晚了。问题可能与您正在使用的半透明
BufferedImage
图像有关。以下各项似乎可以正常工作:环顾四周,我发现了类似的complains
# 3 楼答案
这是一个JVM错误
我遇到了和你一样的问题。我的结论是,问题确实在于绘制半透明位图。我相当肯定我们正在打:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6749069
变通办法
现在,我画一个不透明的位图,然后将它拼接到目标位图中。如果文本后面的背景色是纯文本,则应该可以:
如果背景不是纯彩色,则必须将文本呈现为黑白相间的位图,
A
。然后用文本颜色C
填充另一个位图。然后将它以:D += A*C
或D = D*(1-A)+A*C
或其他合适的混合函数的形式发送到目标图像