【问题标题】:How to draw on top of scaled Image in java?如何在java中的缩放图像之上绘制?
【发布时间】:2019-07-31 00:44:00
【问题描述】:

我有一个BufferedImage,已添加到JPanel。 我可以使用AffineTransform 放大/缩小图像。 我可以在图像上书写,但不能在我想要的位置上书写。 我绘制的线条显示在图像上的错误位置。

我猜它与规模有关,但我无法弄清楚我的代码的哪一部分是错误的。

这是我的意思的屏幕截图。

这是我的代码:


    public class MouseScaleTest {

        int xbegin = 0;
        int ybegin = 0;
        int xend = 0;
        int yend = 0;

        boolean isNewLine = true;

        int initx;
        int inity;

        int count = 0;
        Line2D linebuffer;
        Rectangle2D box;
        final ArrayList<Line2D> lineContainer = new ArrayList();
        final ArrayList<Rectangle2D> boxContainer = new ArrayList();

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

        public MouseScaleTest() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());

    //                JScrollPane
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }

        public class TestPane extends JPanel {

            private BufferedImage img;

            private float scale = 1f;
            private float scaleDelta = 0.05f;
            JLabel lbl;
            JLabel scalePoint;
            JLabel begin;
            JLabel end;
            JLabel aft;

            public TestPane() {

                try {
                    img = ImageIO.read(new File("C:\\Users\\John Ebarita\\Documents\\report.jpg"));
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                lbl = new JLabel();
                lbl.setBounds(0, 0, 50, 10);
                scalePoint = new JLabel();
                scalePoint.setBounds(50, 0, 50, 10);
                begin = new JLabel();
                begin.setBounds(150, 0, 50, 10);
                end = new JLabel();
                end.setBounds(200, 0, 50, 10);
                aft = new JLabel();
                aft.setBounds(250, 0, 50, 10);

                add(lbl);
                add(scalePoint);
                add(begin);
                add(end);
                add(aft);

                addMouseWheelListener(new MouseWheelListener() {

                    @Override
                    public void mouseWheelMoved(MouseWheelEvent e) {
                        int rotation = e.getWheelRotation();
                        if (rotation < 0) {
                            scale -= scaleDelta;
                        } else {
                            scale += scaleDelta;
                        }
                        if (scale < 0) {
                            scale = 0;
                        }
    //                    else if (scale > 1.5) {
    //                        scale = 1;
    //                    }
                        scalePoint.setText("Scale: " + String.valueOf(scale));

                        repaint();

    //                    System.out.println(getSize());
                    }
                });

                addMouseMotionListener(new MouseMotionListener() {
                    @Override
                    public void mouseDragged(MouseEvent e) {
                        if (isNewLine == false) {
                            xend = e.getX();
                            yend = e.getY();

                            end.setText("End Values : " + xend + " " + yend);
                            repaint();
                        }
                    }

                    @Override
                    public void mouseMoved(MouseEvent e) {
                        lbl.setText("Mouse Point: " + e.getX() + " " + e.getY());
                        if (isNewLine == false) {
                            xend = e.getX();
                            yend = e.getY();
                            repaint();
                        }
                    }
                });

                addMouseListener(new MouseAdapter() {

                    @Override
                    public void mouseReleased(MouseEvent e) {
                        System.out.println(e.getX() + " " + e.getY() + "mouse");
                        if (isNewLine == true) {
                            xbegin = xend = e.getX();
                            ybegin = yend = e.getY();

                            isNewLine = false;
                            box = new Rectangle2D.Float(xend - 5, yend - 5, 12, 12);

                            boxContainer.add(box);
                        } else {

                            linebuffer = new Line2D.Float((float) xbegin, (float) ybegin, (float) xend, (float) yend);

                            System.out.println("xbegin: " + xbegin + " " + ybegin + " " + xend + " " + yend);
                            lineContainer.add(linebuffer);

                            repaint();

                            xbegin = e.getX();
                            ybegin = e.getY();

                            if (box.contains(xend, yend)) {
                                xend = (int) box.getCenterX();
                                yend = (int) box.getCenterY();
                                isNewLine = true;
                                return;
                            }

                            box = new Rectangle2D.Float(xend - 6, yend - 6, 12, 12);

                            boxContainer.add(box);
                            return;
                        }
                    }

                    @Override
                    public void mousePressed(MouseEvent e) {
                        begin.setText("Begin Values : " + xbegin + " " + ybegin);
                    }
                });
                setBorder(new BevelBorder(1));
            }

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

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                if (img != null) {
    //
                    Graphics2D g2 = (Graphics2D) g.create();
    //
                    int x = (int) ((getWidth() - (img.getWidth() * scale)) / 2);
                    int y = (int) (getHeight() - (img.getHeight() * scale)) / 2;

                    aft.setText("AFT : " + x + " " + y);

                    AffineTransform at = new AffineTransform();
                    at.translate(x, y);
    //                System.out.println(scale);
                    at.scale(scale, scale);

                    g2.setTransform(at);
                    g2.drawImage(img, 0, 0, this);

                    g2.draw(new Line2D.Float(xbegin, ybegin, xend, yend));
                    for (int i = 0; i < lineContainer.size(); i++) {

                        g2.draw(lineContainer.get(i));
                    }
                    g2.setStroke(new BasicStroke(3));
                    for (int i = 0; i < boxContainer.size(); i++) {
                        g2.setColor(Color.BLUE);
                        g2.draw(boxContainer.get(i));
                    }

                    g2.dispose();
    //                System.out.println("int x and y " + x + " " + y);
    //                System.out.println("getWidth and getHeight " + getWidth() + " " + getHeight());
                }
            }
        }
    }

这是我想用我的代码实现的。 我可以在图像顶部动态绘制,并且仍然可以在保持绘制线条的同时放大/缩小。

【问题讨论】:

  • 有趣,如果你尝试在原点绘制会发生什么?它是否最终达到了您的预期。
  • 我尝试在面板本身的原点绘图,它显示在图像的原点。
  • 1) 为了尽快获得更好的帮助,edit 添加minimal reproducible exampleShort, Self Contained, Correct Example。上面看到的例子,整个屏幕都是进口的,绝对不是 MRE / SSCCE。 2) 例如,获取图像的一种方法是热链接到在this Q&A 中看到的图像。例如。 This answer 指向嵌入在 this question 中的图像的热链接。
  • 谁能帮我解决这个问题。我只是复制粘贴了我的代码,因此有人可以将它们复制并粘贴到他们的 ide 中并直接运行它们。很抱歉没有将其设为“MRE/SSCEE”。实际上我确实在 wiki 上阅读过它,但我没有费心更改细节。我正忙着寻找解决方案。我刚刚批准了 ThanhPhan 所做的修改
  • 这并不容易——你必须从一个简单的测试开始——一张图片——就是这样!没有其他垃圾。跳入高水也无济于事。

标签: java image swing scale mouselistener


【解决方案1】:

恕我直言,错误是您在单击时存储的是绝对值,而不是存储相对位置。 (将比例和平移考虑在内 - 这就是您在绘制图像时所做的)

1) 保持从油漆的转变 2)通过反向变换计算相对坐标

将这两个添加到MouseScaleTest 构造函数下方的代码中:

AffineTransform atg;

Point2D calcCoordinates(MouseEvent e)
{
    Point p = new Point(e.getX(), e.getY());
    try
    {
        return atg.inverseTransform(p, null);
    }
    catch (NoninvertibleTransformException ex)
    {
        ex.printStackTrace();
        return p;
    }
}

paintComponent 中分配 atg:

g2.setTransform(at);
atg = (AffineTransform) at.clone(); // new!

现在到处(mouseDragged、mouseMoved、mouseReleased)你都有类似的代码

xend = e.getX();
yend = e.getY();

改为这样做:

Point2D p = calcCoordinates(e);
xend = (int) p.getX();
yend = (int) p.getY();

如果您喜欢“复制和粘贴开发”(不好!),请查看以下部分:

addMouseWheelListener(new MouseWheelListener()
{

    @Override
    public void mouseWheelMoved(MouseWheelEvent e)
    {
        int rotation = e.getWheelRotation();
        if (rotation < 0)
        {
            scale -= scaleDelta;
        }
        else
        {
            scale += scaleDelta;
        }
        if (scale < 0)
        {
            scale = 0;
        }
        //                    else if (scale > 1.5) {
        //                        scale = 1;
        //                    }
        scalePoint.setText("Scale: " + String.valueOf(scale));

        repaint();

        //                    System.out.println(getSize());
    }
});

addMouseMotionListener(new MouseMotionListener()
{
    @Override
    public void mouseDragged(MouseEvent e)
    {
        if (isNewLine == false)
        {
            xend = e.getX();
            yend = e.getY();

            //NEW
            Point2D p = calcCoordinates(e);
            xend = (int) p.getX();
            yend = (int) p.getY();

            end.setText("End Values : " + xend + " " + yend);
            repaint();
        }
    }

    @Override
    public void mouseMoved(MouseEvent e)
    {
        lbl.setText("Mouse Point: " + e.getX() + " " + e.getY());
        if (isNewLine == false)
        {
            xend = e.getX();
            yend = e.getY();

            //NEW
            Point2D p = calcCoordinates(e);
            xend = (int) p.getX();
            yend = (int) p.getY();

            repaint();
        }
    }

});

addMouseListener(new MouseAdapter()
{

    @Override
    public void mouseReleased(MouseEvent e)
    {
        System.out.println(e.getX() + " " + e.getY() + "mouse");
        if (isNewLine == true)
        {
            xbegin = xend = e.getX();
            ybegin = yend = e.getY();

            //NEW
            Point2D p = calcCoordinates(e);
            xbegin = xend = (int) p.getX();
            ybegin = yend = (int) p.getY();

            isNewLine = false;
            box = new Rectangle2D.Float(xend - 5, yend - 5, 12, 12);

            boxContainer.add(box);
        }
        else
        {

            linebuffer = new Line2D.Float((float) xbegin, (float) ybegin, (float) xend, (float) yend);

            System.out.println("xbegin: " + xbegin + " " + ybegin + " " + xend + " " + yend);
            lineContainer.add(linebuffer);

            repaint();

            xbegin = e.getX();
            ybegin = e.getY();

            //NEW
            Point2D p = calcCoordinates(e);
            xbegin = (int) p.getX();
            ybegin = (int) p.getY();

            if (box.contains(xend, yend))
            {
                xend = (int) box.getCenterX();
                yend = (int) box.getCenterY();
                isNewLine = true;
                return;
            }

            box = new Rectangle2D.Float(xend - 6, yend - 6, 12, 12);

            boxContainer.add(box);
            return;
        }
    }

【讨论】:

  • 感谢 inverseTransform 的想法。真的做到了。老实说,我想过类似的事情。我所做的是我反转了 2D 图形的转换并且它起作用了,但是当我放大/缩小时,这些点保持不变。
  • 这是否意味着我的解决方案有效?我的解决方案应该使点随图像移动。我想知道,因为我今天早上看到答案有一个绿色复选标记,而现在两个小时后却没有。
  • 成功了。但我改变了我的实现。我在图像中添加了JScrollPane,而不是使用drawImage,而是使用drawRenderedImage 使图像即使在我向上或向下滚动时仍然可见。
  • 所以我将AffineTrasform 删除到graphich2D 实例并作为参数放置到g2.drawRenderedImage(image,at); 中,结果搞砸了所有的点。
  • 当然,因为点/线画也使用了改变后的变换。而使用 JScrollPane 则有所不同(尽管有趣且有用)。
猜你喜欢
  • 2016-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-03
  • 2012-06-06
  • 2017-08-14
  • 1970-01-01
  • 2021-09-10
相关资源
最近更新 更多