6

I am new to Java and trying to use Java2D Graphics to create a Image. But the output is coming as anti-aliased. I tried many ways to rectify it but doesn't work. The characters are getting distorted or jagged.

public BufferedImage createNameOnButton(String label) {
    int messageWidth = 0;
    Font font = new Font("Arial", Font.PLAIN, 11);

    BufferedImage bi = new BufferedImage(
        10, 10, BufferedImage.TYPE_INT_RGB);

    Graphics2D g2d = (Graphics2D) bi.getGraphics();
    g2d.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setRenderingHint(
        RenderingHints.KEY_TEXT_ANTIALIASING,
        RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    g2d.setRenderingHint(
        RenderingHints.KEY_FRACTIONALMETRICS,
        RenderingHints.VALUE_FRACTIONALMETRICS_ON);
    g2d.setFont(font);

    bi = g2d.getDeviceConfiguration()
        .createCompatibleImage(500, 30, Transparency.BITMASK);
    FontMetrics fm = bi.getGraphics().getFontMetrics(font);
    int messageHeight = fm.getHeight() - fm.getDescent();
    for (char ch : label.toCharArray()) {
        messageWidth += fm.charWidth(ch);
    }

    bi = bi.getSubimage(50, 0, messageWidth + 10, fm.getHeight());
    Graphics g = bi.getGraphics();
    g.setColor(Color.black);
    AttributedString as = new AttributedString(label);
    as.addAttribute(TextAttribute.FONT, font);
    g.drawString(as.getIterator(), 5, messageHeight);
    g2d.dispose();
    g.dispose();
    return bi;
}

Can anyone please help me to rectify the error?

Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
Prakash
  • 69
  • 1
  • 1
  • 5
  • What are you creating a 10x10 image first? Your code is really convoluted for what it is supposed to do. – Nicolas Repiquet Nov 26 '10 at 13:09
  • 4
    I'm not completly sure I understand. From yor question, I understand you don't want the characters to be antialiased. But reading the code, it's no wonder, since it says ANTIALIAS_ON everywhere. Could you explain? – Alexis Dufrenoy Nov 26 '10 at 13:16
  • Thanks for stating that - I tested the code with ANTIALIAS_OFF but there are some characters that still comes as anti-aliased (not all characters) like, the vertical '\' of N, 'a', 'v', 'e', y' , 'o' - basically the edges of characters are not smooth. Is there anything else I have do? – Prakash Nov 29 '10 at 05:41
  • Also as mentioned below - My requirement is to write a function that returns a BufferedImage that contains a text of pattern "Deliver Me to ". The phrase "Deliver Me to" should be in black color while "" which is collected within the flow should be in blue color. Can you please provide some inputs on the same? – Prakash Nov 29 '10 at 10:13

3 Answers3

12

Assuming you actually want smooth (non-aliased) text, TextLayout may make this easier. The FontRenderContext constructor can manage the anti-aliasing and fractional metrics settings.

Addendum: Using g2d.setColor(Color.blue) seems to produce the expected effect.

Addendum: On Mac OS X, the Pixie application in /Developer/Applications/Graphics Tools/ is convenient for examining the anti-alias pixels. On other platforms, Zoom may be used.

alt text

/** @see https://stackoverflow.com/questions/4285464 */
public class BITest extends JPanel {

    private BufferedImage image = createNameOnButton("Sample");

    public BITest() {
        this.setPreferredSize(new Dimension(
            image.getWidth(), image.getHeight()));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, null);
    }

    public BufferedImage createNameOnButton(String label) {
        Font font = new Font("Arial", Font.PLAIN, 64);
        FontRenderContext frc = new FontRenderContext(null, true, true);
        TextLayout layout = new TextLayout(label, font, frc);
        Rectangle r = layout.getPixelBounds(null, 0, 0);
        System.out.println(r);
        BufferedImage bi = new BufferedImage(
            r.width + 1, r.height + 1,
            BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = (Graphics2D) bi.getGraphics();
        g2d.setColor(Color.blue);
        layout.draw(g2d, 0, -r.y);
        g2d.dispose();
        return bi;
    }

    private void display() {
        JFrame f = new JFrame("BITest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setUndecorated(true);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new BITest().display();
            }
        });
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Thanks for the sample program. My requirement is to write a function that returns a BufferedImage that contains a text of pattern "Deliver Me to ". The phrase "Deliver Me to" should be in black color while "" which is collected within the flow should be in blue color. Can you please provide some inputs on the same? – Prakash Nov 29 '10 at 10:08
  • Also forgot to add that since it has to be placed on a button, image size has to be of specific width and height. I tried the sample program but the image rendered is completely black and was not able to see the text written. Please note that I am completely new in Java. – Prakash Nov 29 '10 at 10:34
  • Just to add - I got the image but actually I need to store and view the same as within a file. So how can I write the what is displayed via display() method to a file. – Prakash Nov 29 '10 at 11:17
  • @Prakash: I'd use `ImageIO.write()` to save the `BufferedImage`. You can call `setColor()` as needed for each line. – trashgod Nov 29 '10 at 19:06
  • Thanks, but the setColor() method is setting the full image as green not the text color. I need to print the text in Black color and background as white / grey. – Prakash Nov 30 '10 at 06:04
  • One thing please note that for output I cannot use JFrame or make use of display() method – Prakash Nov 30 '10 at 09:40
  • Since the image should be accessible via a URL JFrame or any application window cannot be used to render – Prakash Nov 30 '10 at 10:20
  • public BufferedImage createNameOnButton(String label, String decorateText){ Font font = new Font("Arial", Font.BOLD, 11); FontRenderContext frc = new FontRenderContext(null, true, true); TextLayout layout = new TextLayout(label, font, frc); Rectangle r = layout.getPixelBounds(null, 0, 0); bi = new BufferedImage(r.width + 5, r.height, Transparency.BITMASK); Graphics2D g2d = (Graphics2D) bi.getGraphics(); g2d.setColor(Color.black); layout.draw(g2d, 0, -r.y); g2d.drawImage(bi, 0, 0, null); g2d.dispose(); return bi;} The image produced is black. Setting Text color/background no luck. – Prakash Nov 30 '10 at 12:38
  • @Prakash:`Transparency.BITMASK` is a valid `BufferedImage` type, but only by coincidence. There's no need to copy the image onto itself with `g2d.drawImage(bi, 0, 0, null)`. – trashgod Nov 30 '10 at 14:44
  • I tried removing the option [copying the image to itself] but still the result is not achieved. – Prakash Nov 30 '10 at 17:05
  • @Prakash: I updated my example, and `setColor()` appears to change the text color. I don't see where your code is going wrong. Please edit your question, as code in comments is almost unreadable. – trashgod Nov 30 '10 at 20:45
  • I was unable to edit the code and started a new thread related to same issue - http://stackoverflow.com/questions/4316815/java2d-graphics-anti-aliased . Please have a look at the detailed description there and provide required resolution. As mentioned please read thru the descriptive and provide solutions. – Prakash Dec 01 '10 at 04:48
6

As Traroth mentioned it is more than likely due to

g2d.setRenderingHint(
    RenderingHints.KEY_ANTIALIASING,
    RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(
    RenderingHints.KEY_TEXT_ANTIALIASING,
    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

Instead this should be

g2d.setRenderingHint(
    RenderingHints.KEY_ANTIALIASING,
    RenderingHints.VALUE_ANTIALIAS_OFF);
g2d.setRenderingHint(
    RenderingHints.KEY_TEXT_ANTIALIASING,
    RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
Jim
  • 22,354
  • 6
  • 52
  • 80
  • 1
    Thanks for stating that - I tested the code with ANTIALIAS_OFF but there are some characters that still comes as anti-aliased (not all characters) like, the vertical '\' of N, 'a', 'v', 'e'' y' , 'o' - basically the edges of characters are not smooth. Is there anything else I have do? – Prakash Nov 29 '10 at 05:42
  • 11
    You seem not to understand what anti-aliasing means. Anti-aliased=smooth. – lbalazscs Aug 22 '12 at 14:39
2

I found that just this line does the trick:

  g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

After that, just use drawString().

Stefan Reich
  • 1,000
  • 9
  • 12