问题 如何继承系统的反别名设置,以便将文本绘制为像swing一样的屏幕外图像?


当我在Java 6下运行swing GUI应用程序时,它们会自动使用我为所有字体配置的子像素抗锯齿设置。与标准AA选项相比,结果有了很大改进。

但是当我绘制到图像时,我无法初始化图形上下文以使用系统的AA配置。尝试使用Java的不同AA提示是一个失败的原因,因为没有子像素方法将适用于所有用户。

有没有办法继承给定图形上下文的系统AA设置,而不必选择一个并明确设置提示?目前我必须使用GASP AA来避免标准AA用小字体给出的可怕结果。我试过没有为文本AA设置任何内容,也没有设置任何AA提示。


更新2010-01-05 

我想我已经把它钉死了;当直接绘制到AWT图形上下文时,子像素AA提示似乎只被尊重;当我画到双缓冲图像时,它只是标准AA;但是当我绕过双缓冲图像时,完成了子像素AA。

否则,The_Fire的答案将适用于具有Swing可用的JVM(但不适用于J2ME JVM);请注意,The_Fire的答案不能使用AWT组件(使用新的Label()而不是新的JLabel()失败),可能是因为在将组件实现到显示器之前无法提取FontRenderContext。


我目前为目标图像获取图形上下文的代码如下所示:

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;
    }

创建图像的代码使用底层的AWT组件,它构成了我所有绘画的背景 - 组件是一个Panel,因为我需要能够执行setFocusCycleRoot,因此它可以很好地与其他AWT组件一起使用。创建图像代码如下:

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));
    }

5445
2017-12-15 22:39


起源

与屏幕上或屏幕外没有关系(所以这是注释,而不是答案),但是你知道字符串中的某些外来字符如何导致swing切换回TextLayout字体呈现(这不是消除锯齿的), 对? - whybird


答案:


我发现这里有几个因素。

首先,需要从底层AWT组件创建图像,并且必须在没有透明度的情况下创建它:

cfg.createCompatibleImage(wid,hgt);

代替

cfg.createCompatibleImage(wid,hgt,Transparency.TRANSLUCENT);

其次,由于一些莫名其妙的原因,主AA设置KEY_ANTIALIASING必须关闭以使用LCD子像素AA。

最后,最重要的是,可以使用以下方法轻松检索桌面字体呈现提示:

java.awt.Toolkit.getDesktopProperty("awt.font.desktophints")

更新2010-01-05 

在Java 6.26中进行重新测试,似乎需要将常规AA设置为渲染文本AA的问题终于得到解决(方式转向Oracle ...在Sun之后只是一个 几年 十年太晚了)。


7
2018-01-09 07:15





使用Swing,我能够得到正确的文本抗锯齿提示,如下所示:

JLabel label = new JLabel();
FontMetrics fm  = label.getFontMetrics( label.getFont() );
Object aaHintValue = fm.getFontRenderContext().getAntiAliasingHint();

在我的系统上,这返回 RenderingHits.VALUE_TEXT_ANTIALIAS_LCD_HRGB


5
2017-12-22 19:27



这是一个有趣的想法。我不能使用Swing - 在J2ME / CDC / PP上不支持 - 但我可以在AWT窗口中获得相同的功能。 - Lawrence Dol
我需要在工作中测试它...但由于getFontMetrics()是一个Component方法,我完全希望这在我的上下文中工作。假设确实如此,你可以期待在1月接受这个。 - Lawrence Dol
给这个+1,因为它确实能够获得正确的AA提示;但它不适用于AWT(可能是因为没有实现原生组件),甚至应用指定的LCD提示也没有子像素AA,这是我需要解决的问题。 - Lawrence Dol
显然已经过了几年,所以你运行的Java可能与我正在运行的Java不同,但在我的系统上(Java 7,Mac OS 10.9),该代码返回VALUE_TEXT_ANTIALIAS_ON - 这正是Java正在使用的即使操作系统本身使用的是子像素渲染。 - Trejkaz
@Trejkaz:我怀疑,你错过了需要它使用纯AWT而不是使用Swing的部分。上面的代码确实(并且确实)有效,但不是没有Swing。 - Lawrence Dol


java.awt.Toolkit.getDesktopProperty(“awt.font.desktophints”)似乎在linux上为null,至少没有任何特殊的vm命令行选项,大概是因为它无法弄清楚平台默认是什么。添加例如“ -Dawt.useSystemAAFontSettings = lcd“似乎可以解决它,如果在Graphics2D实例上设置提示,则启用子像素渲染。


2
2018-03-28 14:18



Toolkit.getDefaultToolkit()getDesktopProperty( “awt.font.desktophints”); - Hanynowsky


等等,您是否在Windows JVM上运行此代码?我认为ClearType是一种微软技术,Swing通过一些本机代码继承(即,在Linux或其他非Microsoft平台上不可用)。

我曾经写过一个servlet,它生成了在Debian上运行的反别名字体的JPG,这就是我使用的代码

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);

我不记得是否有任何代码依赖于Swing(我导入了javax.swing并且servlet大约有300行,所以我可能认为我需要它用于其他东西),对Google的快速检查看起来像这样正好在AWT空间。希望有所帮助。


1
2017-12-23 19:39



是的,我可以很容易地打开AA,但它使用的标准AA看起来像任何字体大小小于约20磅的垃圾;使用GASP AA可以更好地工作,但是对于较小的字体大小,往往只关闭AA。使用子像素AA是最好的,但您必须匹配硬件像素排列(垂直或水平以及RGB或BGR)。我想继承O / S正在使用的任何AA设置,因为这将是正确的,或者至少等于用户在他们的桌面上看到的一般情况。真正的问题是标准AA看起来像子像素AA旁边的垃圾。 - Lawrence Dol
顺便说一句,虽然ClearType是微软的商标,但涉及的技术是 子像素 抗锯齿,可在所有主要平台上使用。 - Lawrence Dol