0

Language: Java.

Hi, I need to prevent drawing over the same location of a Graphics2D more than once. For example, if the user draws using a BasicStroke with a round cap and a width of 10 over a certain area, that same area cannot be drawn on a second time.

The reason I want to do this is so that the user can draw (free-hand) translucent colours over an image without drawing over the same stroke (thus increasing the density of the colour and reducing its translucency).

I've tried storing the shapes of all the strokes made by the user (as Area objects that subtract the shape) and then clipping the Graphics2D by the intersection of all those Area objects.

This almost works, but the 'shape' obtained by the clip is not quite the same as the 'shape' drawn by the stroke - it is out by a couple of pixels.

Does anyone have any other ideas that might work?

4

1 回答 1

2

这个概念相对简单,你需要有多个可以渲染的图层......

有多种不同的方法可以解决这个问题。您可以维护一个Points 列表,并在每个绘制周期中,将这些点渲染到后备缓冲区,然后您将使用AlphaComposite.

您可以(如本例那样)直接绘制到后备缓冲区和repaint内容,再次使用 aAlphaComposite来呈现更高层。

你可以有任意数量的层...

在此处输入图像描述

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;

public class PaintOver {

    public static void main(String[] args) {
        new PaintOver();
    }

    public PaintOver() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new MapPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

            }
        });
    }

    public class MapPane extends JPanel {

        private BufferedImage background;
        private BufferedImage foreground;

        public MapPane() {
            try {
                background = ImageIO.read(getClass().getResource("/TreasureMap.png"));
                foreground = new BufferedImage(background.getWidth(), background.getHeight(), BufferedImage.TYPE_INT_ARGB);
            } catch (Exception e) {
                e.printStackTrace();
            }

            MouseAdapter mouseHandler = new MouseAdapter() {
                private Point startPoint;

                @Override
                public void mousePressed(MouseEvent e) {
                    startPoint = e.getPoint();
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    startPoint = null;
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    Point endPoint = e.getPoint();
                    Graphics2D g2d = foreground.createGraphics();

                    Point offset = getOffset();

                    Point from = new Point(startPoint);
                    from.translate(-offset.x, -offset.y);
                    Point to = new Point(endPoint);
                    to.translate(-offset.x, -offset.y);
                    g2d.setColor(Color.RED);
                    g2d.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
                    g2d.draw(new Line2D.Float(from, to));
                    g2d.dispose();
                    startPoint = endPoint;
                    repaint();
                }
            };

            addMouseListener(mouseHandler);
            addMouseMotionListener(mouseHandler);

        }

        @Override
        public Dimension getPreferredSize() {
            return background == null ? super.getPreferredSize() : new Dimension(background.getWidth(), background.getHeight());
        }

        protected Point getOffset() {
            Point p = new Point();
            if (background != null) {
                p.x = (getWidth() - background.getWidth()) / 2;
                p.y = (getHeight() - background.getHeight()) / 2;
            }
            return p;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (background != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                Point offset = getOffset();

                g2d.drawImage(background, offset.x, offset.y, this);
                g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
                g2d.drawImage(foreground, offset.x, offset.y, this);
                g2d.dispose();
            }
        }
    }
}
于 2013-02-20T03:45:31.843 回答