Skip to main content

SGText quality

2 replies [Last post]
rossjudson
Offline
Joined: 2006-01-13

I am using JDK6u10. I have a tree of nodes, with SGText down the tree, using the "Candara" font under Windows. The font size is set to 18. No scaling or rotation is involved; just translation. The SGText is overlaid on top of a filled ellipse.

At the bottom of the window containing the JSGPanel I have a JPanel with a JLabel in it. I set the font of the label to Candara, size 18, and put the string "Query Types" in it (my SGText has the same string).

The two strings look very different, when displayed. The quality of the JLabel is very good, and the quality of the SGText is very poor. I've tried altering the anti-aliasing flags and it doesn't seem to help much. In particular, the 'y' characters look proper and proportionate on the JLabel, and very much out of place on the SGText.

I'm not sure what method the JLabel is using, but SGText really needs to look at using the same method.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
idk
Offline
Joined: 2005-01-12

Could you share a test case?

Are you using Mode.STROKE or Mode.STROKE_FILL for SGText by any chance?

rossjudson
Offline
Joined: 2006-01-13

I wrote the test case listed below. I took some screen shots then zoomed in, and I can see what's happening. The JLabel and my custom draw are rendered with LCD subpixel antialiasing. The SGText uses monochrome antialiasing, which makes for "chunkier" text.

The boundaries of the characters in the JLabel exhibit the color variations expected...while SGText doesn't. I suspect that there's something in the way that the bufferedimage is created, or in the way that the graphics2d is set up. Painting against a background color may be a factor here as well.

Zoom in on :

http://www.soletta.com/antitext.png

/*
* SGTextQuality.java
*
* Created on Oct 8, 2008, 12:23:05 AM
*/

package com.soletta.explore;

import com.sun.scenario.scenegraph.JSGPanel;
import com.sun.scenario.scenegraph.SGAbstractShape.Mode;
import com.sun.scenario.scenegraph.SGGroup;
import com.sun.scenario.scenegraph.SGRectangle;
import com.sun.scenario.scenegraph.SGText;
import com.sun.scenario.scenegraph.SGTransform;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.UIManager;

/**
*
* @author rjudson
*/
public class SGTextQuality extends javax.swing.JFrame {
private JSGPanel sgPanel;

/** Creates new form SGTextQuality */
public SGTextQuality() {
initComponents();

sgPanel = new JSGPanel() {

Font f18 = new Font("Candara", 0, 18);

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
RenderingHints rh = g2.getRenderingHints();
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);

Font old = g2.getFont();
Paint oldPaint = g2.getPaint();

g2.setPaint(qtLabel.getForeground());
g2.setFont(f18);
FontRenderContext frc = g2.getFontRenderContext();
GlyphVector gv = f18.createGlyphVector(frc, "Query Type");

g2.drawGlyphVector(gv, 350, 122);
// g2.drawString("Query Type", 350, 122);

g2.setPaint(oldPaint);
g2.setFont(old);
g2.setRenderingHints(rh);
}

};
viewPanel.add(sgPanel, BorderLayout.CENTER);
bottomPanel.setBackground(new Color(0xf3b151));
setSize(600, 250);

build();
}

void build() {
SGGroup group = new SGGroup();
SGRectangle color = new SGRectangle();
color.setArcHeight(12);
color.setArcWidth(12);
color.setFillPaint(new Color(0xf3b151));
color.setMode(Mode.FILL);
color.setX(175);
color.setY(6);
color.setWidth(300);
color.setHeight(200);
color.setAntialiasingHint(RenderingHints.VALUE_ANTIALIAS_ON);
group.add(color);
int y = 20;
for (int i = 6; i <= 18; i += 2) {
group.add(SGTransform.createTranslation(50, y, make(i)));
group.add(SGTransform.createTranslation(200, y, make(i)));
System.out.println(y);
y += i + 6;
}
sgPanel.setScene(group);
}

SGText make(int i) {
SGText t1 = new SGText();
t1.setFillPaint(qtLabel.getForeground());
if (on.isSelected())
t1.setAntialiased(true);
else if (off.isSelected())
t1.setAntialiased(false);
t1.setFont(new Font("Candara", 0, i));
t1.setText("Query Type");
return t1;
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
//
private void initComponents() {

buttonGroup1 = new javax.swing.ButtonGroup();
jPanel1 = new javax.swing.JPanel();
jLabel3 = new javax.swing.JLabel();
noSetting = new javax.swing.JRadioButton();
on = new javax.swing.JRadioButton();
off = new javax.swing.JRadioButton();
bottomPanel = new javax.swing.JPanel();
qtLabel = new javax.swing.JLabel();
viewPanel = new javax.swing.JPanel();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

jLabel3.setText("Antialias Text:");
jPanel1.add(jLabel3);

buttonGroup1.add(noSetting);
noSetting.setSelected(true);
noSetting.setText("No setting");
noSetting.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
noSettingActionPerformed(evt);
}
});
jPanel1.add(noSetting);

buttonGroup1.add(on);
on.setText("On");
on.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
onActionPerformed(evt);
}
});
jPanel1.add(on);

buttonGroup1.add(off);
off.setText("Off");
off.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
offActionPerformed(evt);
}
});
jPanel1.add(off);

getContentPane().add(jPanel1, java.awt.BorderLayout.PAGE_START);

qtLabel.setFont(new java.awt.Font("Candara", 0, 18)); // NOI18N
qtLabel.setText("Query Type");
bottomPanel.add(qtLabel);

getContentPane().add(bottomPanel, java.awt.BorderLayout.PAGE_END);

viewPanel.setMinimumSize(new java.awt.Dimension(400, 200));
viewPanel.setLayout(new java.awt.BorderLayout());
getContentPane().add(viewPanel, java.awt.BorderLayout.CENTER);

pack();
}//

private void noSettingActionPerformed(java.awt.event.ActionEvent evt) {
build();
}

private void onActionPerformed(java.awt.event.ActionEvent evt) {
build();
}

private void offActionPerformed(java.awt.event.ActionEvent evt) {
build();
}

/**
* @param args the command line arguments
*/
public static void main(String args[]) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Throwable ex) {
Logger.getLogger(SGTextQuality.class.getName()).log(Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new SGTextQuality().setVisible(true);
}
});
}

// Variables declaration - do not modify
private javax.swing.JPanel bottomPanel;
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JLabel jLabel3;
private javax.swing.JPanel jPanel1;
private javax.swing.JRadioButton noSetting;
private javax.swing.JRadioButton off;
private javax.swing.JRadioButton on;
private javax.swing.JLabel qtLabel;
private javax.swing.JPanel viewPanel;
// End of variables declaration

}

added image clip

Message was edited by: rossjudson