简体   繁体   English

用Java精确绘制图像

[英]Draw accurately on an image in Java

In the code below I convert a 2dim array to a buffered image (which works, the image is binary (back and white)). 在下面的代码中,我将2dim数组转换为缓冲图像(有效,图像为二进制(背面和白色))。 Then I display this image. 然后我显示这个图像。

My question now is how can I update this image (because I want to draw something in every run of a loop which is not displayed here). 我现在的问题是如何更新这个图像 (因为我想在循环的每次运行中绘制一些东西,这里没有显示)。

This also brings me to my second question: how can I draw a point on this image . 这也引出了我的第二个问题: 我怎样才能在这张图片上画出一点 (This also means that if I want to draw a point on 150,100 ; it should be on pixel 150,100 of the image). (这也意味着如果我想在150,100上画一个点;它应该在图像的150,100像素上)。

public void showImage(int xPoint, int yPoint) throws IOException {

    // Two dim array conversion to a bufferedImage
    BufferedImage bimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    for (int y = 0; y < width; y++) {
        for (int x = 0; x < height; x++) {

            tempValue = (pixelArray[y][x]==1) ? 255 : 0;
            int value = tempValue << 16 | tempValue << 8 | tempValue;
            bimg.setRGB(x, y, value);

        }
    }

    JFrame canvas = new JFrame();
    canvas.setSize(bimg.getWidth(), bimg.getHeight());
    canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    canvas.setTitle("Contour");
    Container pane = canvas.getContentPane();
    ColorPanel panel = new ColorPanel(bimg,xPoint,yPoint);
    pane.add(panel);
    canvas.setVisible(true);
}

and

    class ColorPanel extends JPanel {
    BufferedImage bimg;
    int x;
    int y;

    public ColorPanel(BufferedImage image,int _x, int _y) {
        bimg = image;
        x = _x;
        y = _y;
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.drawImage(bimg, null, 0, 0);
    }
}

what I tried was: 我试过的是:

  g2d.setColor(Color.RED);
  g2d.drawLine(x, y, x, y);

Though a new window opened on every run and I don't think the point was on the right 虽然每次运行都会打开一个新窗口,但我认为这一点并不在右边

I did a small example for you. 我为你做了一个小例子。

Basically it is a JFrame with a custom JPanel called ColorPanel (which is much like yours with a few extra methods namely drawDot(..) and setBufferedImage(..) ) 基本上它是一个JFrame带有一个名为ColorPanel自定义 JPanel (与你的一些额外的方法很相似,即drawDot(..)setBufferedImage(..)

The JFrame will initialize and add the JPanel with an BufferedImage (completely black in this case). JFrame将初始化并添加带有BufferedImageJPanel (在本例中为全黑)。 Thereafter white dots/pixels will be drawn on the Image at random co-ordinates (within the images bounds) every 2 seconds using BufferedImage#setRGB(...) . 此后,使用BufferedImage#setRGB(...)每2秒在Image以随机坐标(在图像边界内)绘制点/像素。

I set the timer to faster (200milis) and this is what the picture begins to look like: 我将计时器设置得更快(200milis),这就是图片看起来像:

NB its accurate, make it color an obvious co-ordinate like drawPoint(0,0) and you will see ( i did not demonstrate this as a screenshot would than not be possible or of any use) NB它的准确性,使它成为一个明显的坐标,如drawPoint(0,0) ,你会看到(我没有证明这是一个截图不可能或任何使用)

在此输入图像描述

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class PixelDotOnImage {

    public PixelDotOnImage() throws Exception {
        JFrame frame = new JFrame();
        frame.setTitle("Random Pixel Dots On Image with Timer");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);

        initComponents(frame);

        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {

        //create frame and components on EDT
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    new PixelDotOnImage();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    private void initComponents(JFrame frame) throws Exception {

        final BufferedImage bi = ImageIO.read(new URL("http://2.bp.blogspot.com/_KI3IRH6RxSs/S-uuLsgGJ3I/AAAAAAAAA5E/AA5mWBMLIvo/s1600/mat-black-lg.jpg"));
        final ColorPanel cPanel = new ColorPanel(bi);
        frame.add(cPanel);

        //create timer to color random pixels
        Timer timer = new Timer(2000, new AbstractAction() {
            int xMax = bi.getWidth(), yMax = bi.getHeight();
            Random rand = new Random();

            @Override
            public void actionPerformed(ActionEvent ae) {

                int x = rand.nextInt(xMax);
                int y = rand.nextInt(yMax);

                if (cPanel.drawDot(x, y)) {
                    System.out.println("Drew white dot at: (" + x + "," + y + ")");
                } else {
                    System.out.println("Cant draw white dot at: (" + x + "," + y + ")");
                }

            }
        });

        timer.start();
    }
}

class ColorPanel extends JPanel {

    private BufferedImage bimg;
    private Dimension dims;

    public ColorPanel(BufferedImage image) {
        bimg = image;
        dims = new Dimension(bimg.getWidth(), bimg.getHeight());
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.drawImage(bimg, 0, 0, null);
    }

    //this method will allow the changing of image
    public void setBufferedImage(BufferedImage newImg) {
        bimg = newImg;
    }

    //ths method will colour a pixel white
    public boolean drawDot(int x, int y) {

        if (x > dims.getWidth() || y > dims.getHeight()) {
            return false;
        }

        bimg.setRGB(x, y,  0xFFFFFFFF);//white

        repaint();
        return true;
    }

    @Override
    public Dimension getPreferredSize() {
        return dims;
    }
}

Hope this helps. 希望这可以帮助。

Rather than building an image then adding it to a JPanel, you might consider looking into drawing right on the panel by overriding it's paintComponent method, like so: 而不是构建图像然后将其添加到JPanel,您可以考虑通过覆盖它的paintComponent方法在面板上查看绘图,如下所示:

public class PainterPanel extends JPanel {
    public void paintComponent(Graphics g){     
        super.paintComponent(g);

        // draw a diagonal line from top left to bottom right
        Dimension d = getSize();
        g2.draw(new Line2D.Double(0,0,d.width,d.height));
    }
}

This method gets called every time the repaint() method is called (for instance by resizing the frame, or by calling it manually yourself). 每次调用repaint()方法时都会调用此方法(例如,通过调整框架大小或通过自己手动调用它)。 You can do any sort of complex processing you need including plotting a matrix of points. 您可以进行任何需要的复杂处理,包括绘制点矩阵。

The only catch (and this would be true if you stuck with your original behavior too) is the repainting happens in a separate thread, so you need to be careful about when and how you update your data, so that it's done in a threadsafe way. 唯一的问题(如果你坚持原来的行为也是如此)是重新绘制发生在一个单独的线程中,所以你需要注意何时以及如何更新数据,以便以线程安全的方式完成。

how can I update this image 我该如何更新此图片

  • To draw on the image use the graphics obtained by bimg.getGraphics() (and then use it just like you would in a paintComponent ). 要在图像上绘制,请使用bimg.getGraphics()获得的图形(然后像在paintComponent一样使用它)。 See Javadocs 见Javadocs

how can I draw a point on this image 我怎样才能在这张图片上画一个点

  • To paint on a specific point of the Buffered Image, use any method of the graphics object retrieved from above answer. 要在缓冲图像的特定点上绘制,请使用从上面的答案中检索到的图形对象的任何方法。 Example g.drawLine(150,100,150,100) 示例g.drawLine(150,100,150,100)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM