How to draw an outline around text in AWT?
Asked Answered
A

5

16

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

Outline

Aeri answered 4/4, 2012 at 17:8 Comment(0)
E
10

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:

Encomiastic answered 4/4, 2012 at 18:21 Comment(4)
See also this answer where (beyond the spec.) I apply a border to the shape of the text.Mischance
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'. ;)Mischance
"for AWT Components use.." ..a time machine. Why even mention them?Mischance
@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 :-)Encomiastic
U
9

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);
    }
}
Undulant answered 5/2, 2016 at 10:42 Comment(2)
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.CAP_ROUND, BasicStroke.JOIN_ROUND)); Otherwise (without round cap and join) we can have unnecessary artifacts on sharp angles.Chausses
This answer doesn't work for eastern European characters. Does someone know how can I modify this program so it would work for eastern European characters as well?Calc
G
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.

Gangue answered 4/4, 2012 at 18:11 Comment(1)
Nice idea, definitely worth a try. Thanks.Aeri
C
1

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);
    }
}
Cinda answered 7/5, 2014 at 14:52 Comment(0)
H
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.

Harshman answered 4/4, 2012 at 17:15 Comment(1)
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.Aeri

© 2022 - 2024 — McMap. All rights reserved.