Question

I would like to apply a stroke (outline) to an image in Java. After reading this and this it looks like Java2D API applies strokes to shapes only? Surely I can do a bitmap fill and then apply a stroke to that shape but I want to know if I can apply it directly on the given bitmap.

UPDATE: I managed to apply a stroke bit it outlines the whole image.My images have PNG transparency.How do I apply the stroke around the visible pixels of the image only ?

 public static void main(String[] args) {
    try {
        // TODO code application logic here
        URL u = GraphicsDemo.class.getResource("Capture222.png");
        BufferedImage img = ImageIO.read(new File(u.getPath()));
        System.out.print("loaded");
        Graphics2D g = img.createGraphics();
        Rectangle2D tr = new Rectangle2D.Double(0, 0,
                img.getWidth(), img.getHeight());
        // Create the TexturePaint.
        TexturePaint tp = new TexturePaint(img, tr);
        g.setStroke(new BasicStroke(20));
        g.setPaint(Color.ORANGE);
        //   g.fill(tr);
        g.draw(tr);


        ImageIO.write(img, "PNG", new File("myeditedimage.png"));
        g.dispose();
    } catch (IOException ex) {
        Logger.getLogger(GraphicsDemo.class.getName()).log(Level.SEVERE, null, ex);
    }
 } 

UPDATE 1: I am not sure what I am trying to do is possible using Java Graphics API.Once again.I need to outline the image based on the visible pixels contour and not around it's bounding box. That is what I am trying to achieve: enter image description here

Was it helpful?

Solution

Yes, the Java2D API applies strokes to shapes only. You can do two things:

Either create a Shape out of the transparency information of your bitmap image, so that you can stroke only the non-transparent part. This is difficult in any language, because it means converting the bitmap-information into a vector-based information.

Check this: Image/Graphic into a Shape

And this: Smoothing a jagged path

But basically I would try to avoid the converting problem, and solve it in a bitmap-only way - for example, colorize those pixels (with the "stroke color") for which a transparent pixel can be found at a given pixel-distance ("stroke width").

OTHER TIPS

  • First, tell the Graphics2D how you want the outline to be drawn by calling setStroke(). This method accepts any object that implements the java.awt.Stroke interface. The 2D API comes with a class, java.awt.BasicStroke, that implements common stroking options.
  • Use setPaint() to tell the Graphics2D how the outline itself should be drawn. Outlines, like the interior of shapes, can be drawn using a color, a gradient, a texture, or anything else that implements the Paint interface.
  • Draw the outline of the shape using Graphics2D's draw() method. The Graphics2D uses the Stroke from step 1 to determine what the outline looks like. The Paint from step 2 is used to actually render the outline.

Graphics2D uses a Stroke to figure out what the outline of a particular shape looks like. When you ask Graphics2D to draw() a shape, it asks its Stroke what the outline of the shape should look like. Interestingly, Stroke returns the stroked outline as another shape:

public abstract Shape createStrokedShape(Shape p)

This method returns a Shape that represents the stroked outline of the supplied shape. This is the only method in Stroke. Usually, you won't call it yourself, a Graphics2D will call it on your behalf when you draw() a shape.

Calling draw() on a Graphics2D is equivalent to the following code:

public void longwindedDraw(Graphics2D g2, Shape s) 
{
    Stroke stroke = g2.getStroke();
    Shape strokedOutline = stroke.createStrokedShape(s);
    g2.fill(strokedOutline);
}

Try this :

final static BasicStroke dash_stroke =new BasicStroke(1.0f,
                        BasicStroke.CAP_BUTT,
                        BasicStroke.JOIN_MITER,
                        10.0f, dash1, 0.0f);

Then set the Stroke :

g2.getStroke()

To acquire a Graphics2D object that paints on a bitmap, you should use a BufferedImage.

BufferedImage img = ImageIO.read(new File("myimage.png"));
Graphics2D g = img.createGraphics();

// Paint on it like you want here...


g.dispose();
ImageIO.write(img, "PNG", new File("myeditedimage.png"));

Like this? If not, please attach an image that shows the required result.

StrokedImage

import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;

public class StrokedImage {

    public BufferedImage getStrokedImage(
            BufferedImage bi, Shape shape, int strokeWidth) {
        int w = bi.getWidth();
        int h = bi.getHeight();
        BufferedImage bib = new BufferedImage(w,h,bi.getType());
        Graphics2D g = bib.createGraphics();

        BasicStroke bs = new BasicStroke(strokeWidth);
        g.setStroke(bs);
        Rectangle rect = new Rectangle(0,0,w,h); 
        TexturePaint tp = new TexturePaint(bi, rect); 
        g.setPaint(tp);
        g.draw(shape);

        g.dispose();
        return bib;
    }

    public static void main(String[] args) throws Exception {
        URL url = new URL("http://pscode.org/media/stromlo1.jpg");
        final BufferedImage bi = ImageIO.read(url);
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                StrokedImage si = new StrokedImage();

                int strokeWidth = 12;
                int pad = 50;
                Shape shape = new Rectangle(
                        pad,pad,
                        bi.getWidth()-(2*pad),bi.getHeight()-(2*pad)); 
                Image i = si.getStrokedImage(bi, shape, strokeWidth);

                JPanel p = new JPanel(new GridLayout(1,0,5,5));
                p.add(new JLabel(new ImageIcon(i)));
                p.add(new JLabel(new ImageIcon(bi)));
                JOptionPane.showMessageDialog(null, p);
            }
        });
    }
}

Post question edit - update

Have a look at this answer. It applies a clip of the Shape before drawing the image. Then it clears the clip and draws the Shape itself, as a border.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top