Может ли Java отображать полупрозрачный текст с использованием субпиксельного сглаживания?

Я обнаружил, что при рендеринге непрозрачного текста в Java (последняя версия 6u23) прекрасно используется субпиксельное сглаживание, а рендеринг полупрозрачного текста — нет.

Субпиксельное сглаживание:

alt textальтернативный текст

Тот же текст, у которого изменен только цвет с 0xFFFFFFFF на 0xBFFFFFFFF:

alt textальтернативный текст

Как вы можете видеть, полупрозрачный текст явно является стандартным AA, и вместо чистого полупрозрачного рендеринга он имеет тот ужасный вид «паука» 90-х.

Это связано с техническим ограничением для субпиксельного сглаживания в целом, или с ошибкой в ​​Java, или просто потому, что Java даже не пытается полупрозрачный текст, или я что-то пропустил?


Инициализация графики

dbGraphics=(Graphics2D)dbImage.getGraphics();
if(dctRoot.properties.getBoolean("Antialias",true)) {
    try {
        Map hnts=(Map)(dctRoot.awtComponent.getToolkit().getDesktopProperty("awt.font.desktophints"));

        // SET AA ON OVERALL (NOTE: GENERAL AA MUST BE OFF FOR SUBPIXEL AA TO BE HONORED - TEXT WIDGETS MUST DO THIS THEMSELVES)
        dbGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

        if(hnts!=null) {
            // SET FONT RENDERING HINTS FROM DESKTOP
            dbGraphics.addRenderingHints(hnts);
            }
        else {
            try {
                // SET TEXT AA TO FONT-SPECIFIED GASP AA (JAVA 6+)
                dbGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.class.getField("VALUE_TEXT_ANTIALIAS_GASP").get(null));
                }
            catch(Throwable thr3) {
                // SET TEXT AA TO DEFAULT
                dbGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                }
            }
        }
    catch(Throwable thr) {
        dctRoot.log.println("Antialiasing not supported on this JVM ("+thr+").");
        dctRoot.setProperty("Antialias","False");           // turn off AA for subsequent painting
        }
    }
else {
    try {
        dbGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
        dbGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
        }
    catch(Throwable thr) {;}                                // ignore exception
    }

Визуализация текста

Object oaa=disableGeneralAA(gc);
...
gc.drawString(tl,xx,(ty+(xa*met.getHeight())));
restoreGeneralAA(gc,oaa);

...


static private volatile boolean         hasRenderingHints=true;

// *****************************************************************************
// STATIC INIT & MAIN
// *****************************************************************************

// *****************************************************************************
// STATIC METHODS
// *****************************************************************************

/**
 * Disable the general anti-aliasing rendering hint, returning whether the old value was RenderingHints.VALUE_ANTIALIAS_ON.
 * <p>
 * This method is needed for text rendering due to a bug in AWT; as of Java 6_20 when general AA is on text is not rendered using subpixel
 * AA, so general AA has to be turned off before rendering text and turned back on when done.  This method abstracts that work and deals
 * with the possibility that the JVM does not support rendering hints, such as is the case with JME JVMs.
 */
static public Object disableGeneralAA(Graphics2D gc) {
    Object                              old=null;

    if(hasRenderingHints) {
        try {
            old=gc.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
            gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
            }
        catch(NoClassDefFoundError thr) { hasRenderingHints=false; }
        catch(NoSuchFieldError     thr) { hasRenderingHints=false; }
        catch(NoSuchMethodError    thr) { hasRenderingHints=false; }
        }
    return old;
    }

/**
 * Disable the general anti-aliasing rendering hint, returning whether the old value was RenderingHints.VALUE_ANTIALIAS_ON.
 * <p>
 * This method is needed for text rendering due to a bug in AWT; as of Java 6_20 when general AA is on text is not rendered using subpixel
 * AA, so general AA has to be turned off before rendering text and turned back on when done.  This method abstracts that work and deals
 * with the possibility that the JVM does not support rendering hints, such as is the case with JME JVMs.
 */
static public void restoreGeneralAA(Graphics2D gc, Object val) {
    Object                              old=null;

    if(hasRenderingHints && val!=null) {
        try { gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING,val); }
        catch(NoClassDefFoundError thr) { hasRenderingHints=false; }
        catch(NoSuchFieldError     thr) { hasRenderingHints=false; }
        catch(NoSuchMethodError    thr) { hasRenderingHints=false; }
        }
    }

person Lawrence Dol    schedule 22.12.2010    source источник
comment
Вы пробовали визуализировать сглаженный текст в BufferedImage, а затем использовать AlphaComposite, чтобы полупрозрачно нарисовать изображение на экране? (Это будет медленнее, к сожалению.)   -  person finnw    schedule 22.12.2010
comment
@finnw: Все рисование выполняется в закадровом BufferedImage, и это изображение копируется в базовый контекст экранной графики для каждого paint(Graphics agc) с помощью простого gc.drawImage. Я ожидаю, что изображение в закадровом буфере будет окончательным изображением; Я делаю много полупрозрачного рисования, и единственная проблема заключается в том, что рендеринг текста кажется стандартным AA, когда цвет текста полупрозрачный.   -  person Lawrence Dol    schedule 22.12.2010
comment
Похоже, что это было проблемой некоторое время forums.java.net/node/676951   -  person z5h    schedule 11.01.2011


Ответы (3)


Кажется, что рендеринг текста на прозрачном фоне (полностью) не поддерживается, как видно из этих отчетов об ошибках:

person Bas Leijdekkers    schedule 13.01.2011
comment
Я делаю прозрачный текст на непрозрачном фоне. - person Lawrence Dol; 13.01.2011

Я думаю, это потому, что вы используете GASP, который берет баллы из стиля шрифта. Вы пытались использовать VALUE_TEXT_ANTIALIAS_DEFAULT и VALUE_ALPHA_INTERPOLATION_DEFAULT? стоит попробовать.

http://download.oracle.com/javase/6/docs/api/java/awt/RenderingHints.html

person Ross    schedule 28.12.2010
comment
Нет, я использую субпиксельное сглаживание; GASP — это всего лишь запасной вариант на тот случай, если подсказки рендеринга на рабочем столе не возвращаются. Это демонстрируют скриншоты - единственное различие между ними заключается в цвете, используемом для рендеринга. - person Lawrence Dol; 28.12.2010

Какую версию Java вы используете? Вы не говорите. Но, по-видимому, это было исправлено либо в обновлении Java 6 12 (J6u12), либо в JDK7 b43.

См. здесь: http://bugs.sun.com/view_bug.do?bug_id=6749060< /а>

Если вы снова тестируете Java = или выше, чем J6u12, и все еще видите ошибку, есть RFE, где вы можете прокомментировать в базе данных ошибок Sun.

Чтобы исправить ситуацию на платформе Java, нужно:

  1. Проголосуйте за отчет об ошибке на Sun's BugParade, чтобы повысить его приоритет, и подождите, пока программисты Sun/Oracle не доберутся до него или
  2. Теперь, когда исходный код Java открыт, исправьте это самостоятельно. (присоединяйтесь к списку рассылки на ho.io/jkp5 :-)

Отчет об ошибках, за который вы хотите проголосовать или прокомментировать, находится здесь (на случай, если вы тестируете j6u12, и он все еще присутствует) по адресу: ho.io/jkp2.

Если вы хотите реализовать известный обходной путь, чтобы текст выглядел красиво даже в старых JRE, здесь приведен обходной путь.

URL: ho.io/jkpy

«Похоже, решение, которое я использую для эмуляции полупрозрачности путем смешивания необходимого цвета переднего плана с цветом фона компонента, все еще является способом убедиться, что используется собственный растеризатор».

Удачи!

person Fernando el Geek    schedule 15.01.2011
comment
Это определенно не исправлено в 6.23; Я использую последние версии JVM и JDK. Я отмечаю, что это говорит о том, что место назначения не является непрозрачным, и я использую полупрозрачный источник, но я подозреваю, что проблема заключается в том, когда вообще происходит какое-либо альфа-смешивание. - person Lawrence Dol; 16.01.2011
comment
И о том, чтобы сделать полупрозрачность самостоятельно, не может быть и речи, поскольку фон, на котором выполняется рендеринг теста, варьируется — часто это изображение, логотип или градиент — нет одного цвета, который будет работать для всех пикселей. - person Lawrence Dol; 16.01.2011