How can I inherit the system's anti-alias setting for painting text to off-screen images like swing does?
When I run my swing GUI applications under Java 6, they automatically use my configured sub-pixel anti-alias settings for all fonts. The result is much improved over standard AA options.
But when I paint to an image I can find no way to initialize the graphics context to use the system's AA configuration. Trying to play around with Java's different AA hints is a lost cause because no sub-pixel method will work for all users.
Is there any way to inherit system AA settings for a given graphics context instead of having to pick one and explicitly set the hint? At the moment I have to use GASP AA to avoid the horrible results that standard AA gives with small fonts. I have tried 开发者_如何学JAVAnot setting anything for text AA, and not setting any AA hints at all.
Update 2010-01-05
I think I have pinned this down; the subpixel AA hints appear to only be respected when painting directly to the AWT graphics context; when I paint to a double-buffer image it just does standard AA; but when I bypass the double-buffer image the subpixel AA is done.
Otherwise The_Fire's answer would work in JVMs which have Swing available (but not J2ME JVMs); Note that The_Fire's answer does not work using an AWT component (using new Label() instead of new JLabel() fails), presumably because the FontRenderContext cannot be extracted until the component is realized to the display.
My current code to get the graphics context for my target image currently looks like this:
try {
if((dbImage=dctRoot.createImage(wid,hgt,1))!=null) { // if createImage returns null or throws an exception the component is not yet displayable
dbGraphics=(Graphics2D)dbImage.getGraphics();
if(dctRoot.properties.getBoolean("Antialias",true)) {
try {
// set AA on overall
dbGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING ,RenderingHints.VALUE_ANTIALIAS_ON);
// set text AA to platform/impl default
dbGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
// try to override platform/impl AA with font-specified AA (Java 6+)
try { dbGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.class.getField("VALUE_TEXT_ANTIALIAS_GASP").get(null)); } catch(Throwable thr) {;} // yes, ignore exception
}
catch(Throwable thr) {
dctRoot.log.println("Antialiasing not supported on this JVM ("+thr+").");
dctRoot.setProperty("Antialias","False"); // turn off AA for subsequent painting
}
}
}
}
catch(Throwable thr) {
dbImage=null;
dbGraphics=null;
}
The code to create the image uses an underlying AWT component, which forms the backdrop on which I do all my painting - the component is a Panel, because I need to be able to do a setFocusCycleRoot so it plays well with other AWT components. The create image code follows:
public DctImage createImage(int wid, int hgt, float accpty) {
GraphicsConfiguration cfg=awtComponent.getGraphicsConfiguration();
Image img=null;
if(transparentImages) {
//y { img=new BufferedImage(wid,hgt,BufferedImage.TYPE_INT_ARGB); } // NB: J2ME CDC/PP 1.1 does not have the BufferedImage constructors (one day I may discover a way to create a BufferedImage via another API!!)
try { img=cfg.createCompatibleImage(wid,hgt,Transparency.TRANSLUCENT); }// NB: J2ME CDC/PP 1.1 does not have this API, but prefer to use GraphicsConfiguration over new BufferImage(...)
catch(NoClassDefFoundError thr) { transparentImages=false; createImage(wid,hgt,accpty); } // try again with transparency disabled
catch(NoSuchMethodError thr) { transparentImages=false; createImage(wid,hgt,accpty); } // try again with transparency disabled
catch(NoSuchFieldError thr) { transparentImages=false; createImage(wid,hgt,accpty); } // try again with transparency disabled
}
else {
img=cfg.createCompatibleImage(wid,hgt);
}
if(accpty>0 && SET_ACCELERATION_PRIORITY!=null) {
try { SET_ACCELERATION_PRIORITY.invoke(img,new Object[]{new Float(accpty)}); } catch(Throwable thr) {;}
}
return (img==null ? null : new DctImage(img));
}
I found there were a few factors going on here.
First, the image needs to be created from the underlying AWT component, and it must be created without transparency:
cfg.createCompatibleImage(wid,hgt);
instead of
cfg.createCompatibleImage(wid,hgt,Transparency.TRANSLUCENT);
Second, for some inexplicable reason, the primary AA setting, KEY_ANTIALIASING, must be off to use LCD subpixel AA.
Lastly, and most importantly, the desktop font rendering hints are easily retrieved using:
java.awt.Toolkit.getDesktopProperty("awt.font.desktophints")
Update 2010-01-05
Retesting in Java 6.26, it seems like the problem with needing to set general AA off to render text AA has finally been resolved (way to go Oracle... after Sun was just a few years decade too late).
Using Swing, I'm able to get the right text anti-aliasing hint like this:
JLabel label = new JLabel();
FontMetrics fm = label.getFontMetrics( label.getFont() );
Object aaHintValue = fm.getFontRenderContext().getAntiAliasingHint();
On my system this returns RenderingHits.VALUE_TEXT_ANTIALIAS_LCD_HRGB
.
java.awt.Toolkit.getDesktopProperty("awt.font.desktophints") appears to be null on linux, at least without any special vm command line options, presumably because it's unable to figure out what the platform defaults are.. adding e.g "-Dawt.useSystemAAFontSettings=lcd" seems to cure it and enables subpixel rendering if you set the hints on your Graphics2D instance.
Wait, are you running this code on a Windows JVM? I thought ClearType was a Microsoft technology that Swing inherits through some native code (ie, not available on Linux or other non Microsoft platforms).
I once wrote a servlet that generated JPGs with anti aliased fonts that ran on Debian, and this was the code I used
Font font = new Font("Komix", Font.PLAIN, 8);
Graphics2D g2;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
FontRenderContext frc = g2.getFontRenderContext();
g2.setFont(font);
g2.setPaint(Color.black);
g2.drawString(sMessage, xOffset, yOffset);
Offhand I can't recall if any of this code relies on Swing (I imported javax.swing and the servlet is about 300 lines long, so I may have thought I needed it for something else), a quick check on Google looks like this is squarely in the AWT space. Hope that helps.
精彩评论