How to draw an outline around text in AWT?

Go To StackoverFlow.com

9

How can I draw an outline around any text in AWT, something similar to this picture?

Outline

2012-04-04 17:08
by Konrad Garus


6

two examples

output from this paint would be the BufferedImage, for AWT Components use method paint(), for Swing JComponents is there paintComponet()

Also, from code linked in a comment:

2012-04-04 18:21
by mKorbel
See also this answer where (beyond the spec.) I apply a border to the shape of the text - Andrew Thompson 2012-04-05 05:21
Please forgive my edit. If you don't think it is appropriate for your answer, roll it back. But a picture paints a thousand words, ..or in this case 'Cat'. ; - Andrew Thompson 2012-04-05 05:23
"for AWT Components use.." ..a time machine. Why even mention them - Andrew Thompson 2012-04-05 05:30
@Andrew Thompson aaacch, thank you - mKorbel 2012-04-05 05:33
@Andrew Thompson part of peoples use SWT-AWT bridge, part of them for OpenGL, sure and nobody knows for why is used AWT for the most important part :- - mKorbel 2012-04-05 05:37
Oh yes, good points. Thanks for the reminder. : - Andrew Thompson 2012-04-05 05:42


3

Try the following:

public void paintTextWithOutline(Graphics g) {
    String text = "some text";

    Color outlineColor = Color.white;
    Color fillColor = Color.black;
    BasicStroke outlineStroke = new BasicStroke(2.0f);

    if (g instanceof Graphics2D) {
        Graphics2D g2 = (Graphics2D) g;

        // remember original settings
        Color originalColor = g2.getColor();
        Stroke originalStroke = g2.getStroke();
        RenderingHints originalHints = g2.getRenderingHints();


        // create a glyph vector from your text
        GlyphVector glyphVector = getFont().createGlyphVector(g2.getFontRenderContext(), text);
        // get the shape object
        Shape textShape = glyphVector.getOutline();

        // activate anti aliasing for text rendering (if you want it to look nice)
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setRenderingHint(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY);

        g2.setColor(outlineColor);
        g2.setStroke(outlineStroke);
        g2.draw(textShape); // draw outline

        g2.setColor(fillColor);
        g2.fill(textShape); // fill the shape

        // reset to original settings after painting
        g2.setColor(originalColor);
        g2.setStroke(originalStroke);
        g2.setRenderingHints(originalHints);
    }
}
2016-02-05 10:42
by Eddo
This is the finest answer here. I'd add that it is necessary to initialize the following BasicStroke: graphics.setStroke(new BasicStroke(contour-width, BasicStroke.CAPROUND, BasicStroke.JOINROUND));

Otherwise (without round cap and join) we can have unnecessary artifacts on sharp angles - sergpank 2019-01-27 22:25



2

Not sure how you're drawing the text now, but one way you could do it is use a BufferedImage as an overlay to whatever it is that you're drawing on.

  1. Create BufferedImage using the dimensions of the string and font you are wanting to draw with (look at FontMetrics class for this).
  2. Fill the BufferedImage with transparency.
  3. Draw your string onto the BufferedImage with whatever color you want.
  4. Iterate over every pixel in the BufferedImage and see how far away it is from a pixel of your text's color. If it's within a certain distance, draw that pixel black, and maybe more transparent if it's further away from the color of your text. Of course, if the pixel is already the same color as your text color, then ignore it.
  5. Draw BufferedImage onto whatever it is that you're painting onto.

EDIT

There may be libraries out there that already do this, but if I had to code it from scratch, this is how I'd try to do it.

2012-04-04 18:11
by CodeBlind
Nice idea, definitely worth a try. Thanks - Konrad Garus 2012-04-05 09:04


0

some stupidest workarounds: -type same words twice but one of them is black and the other is white, put white on top of the black one, you may get something similar. -find a font looks like above the example, and use it.

2012-04-04 17:15
by guness
Very unlikely to work in general and I need it to look nice. I don't think that's what MS or Google does in their maps - Konrad Garus 2012-04-04 17:19


0

Here is a hacky example. It is not as sophisticated as others, but it is simpler to understand, and it behaves like a JLabel.

public class OutlineLabel extends JLabel {

    private Color outlineColor = Color.WHITE;
    private boolean isPaintingOutline = false;
    private boolean forceTransparent = false;

    public OutlineLabel() {
        super();
    }

    public OutlineLabel(String text) {
        super(text);
    }

    public OutlineLabel(String text, int horizontalAlignment) {
        super(text, horizontalAlignment);
    }

    public Color getOutlineColor() {
        return outlineColor;
    }

    public void setOutlineColor(Color outlineColor) {
        this.outlineColor = outlineColor;
        this.invalidate();
    }

    @Override
    public Color getForeground() {
        if ( isPaintingOutline ) {
            return outlineColor;
        } else {
            return super.getForeground();
        }
    }

    @Override
    public boolean isOpaque() {
        if ( forceTransparent ) {
            return false;
        } else {
            return super.isOpaque();
        }
    }

    @Override
    public void paint(Graphics g) {

        String text = getText();
        if ( text == null || text.length() == 0 ) {
            super.paint(g);
            return;
        }

        // 1 2 3
        // 8 9 4
        // 7 6 5

        if ( isOpaque() )
            super.paint(g);

        forceTransparent = true;
        isPaintingOutline = true;
        g.translate(-1, -1); super.paint(g); // 1 
        g.translate( 1,  0); super.paint(g); // 2 
        g.translate( 1,  0); super.paint(g); // 3 
        g.translate( 0,  1); super.paint(g); // 4
        g.translate( 0,  1); super.paint(g); // 5
        g.translate(-1,  0); super.paint(g); // 6
        g.translate(-1,  0); super.paint(g); // 7
        g.translate( 0, -1); super.paint(g); // 8
        g.translate( 1,  0); // 9
        isPaintingOutline = false;

        super.paint(g);
        forceTransparent = false;

    }

    public static void main(String[] args) {
        JFrame w = new JFrame();
        w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        OutlineLabel label = new OutlineLabel("Test", OutlineLabel.CENTER);
        label.setOpaque(true);
        w.setContentPane(new JPanel(new BorderLayout()));
        w.add(label, BorderLayout.CENTER);
        w.pack();
        w.setVisible(true);
    }
}
2014-05-07 14:52
by Booyah Johnson
Ads