0

I hope my first post isn't too basic for y'all.

I'm trying to do some per-pixel drawing on a JCanvas using a BufferedImage (using setRGB()). I thought I would test all was working with a single diagonal line from the origin to the width/height of the JCanvas. The trouble is that I get a strange offset in the x axis that I can't seem to fix!

Here's a link to the problem: http://i811.photobucket.com/albums/zz31/bohngy/problemMandel_zpsae20713a.jpeg

enter image description here

Here's the code:

public class Mandelbrot extends JFrame {

private BufferedImage I;

public Mandelbrot() {
    super("Mandelbrot Set");
    setSize(600, 600);
    setResizable(false);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    I = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
    for (int x = 0; x < getHeight(); x++) {
        for (int y = 0; y < getWidth(); y++) {
            I.setRGB(x, x, Color.GREEN.getRGB());
        }
    }
}

@Override
public void paint(Graphics g) {
    g.drawImage(I, 0, 0, this);
}

public static void main(String[] args) {
    new Mandelbrot().setVisible(true);
  }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
kingBenny
  • 21
  • 5
  • This line makes me a little nervous: `I.setRGB(x, x, Color.GREEN.getRGB());` with the use of `x` twice as a parameter – BitNinja Mar 30 '14 at 20:05

2 Answers2

3

General issues

  • Don't extend JFrame (particularly, don't override the paint method of JFrame). Instead, do the painting in the paintComponent method a class that extends JPanel
  • Create the GUI from the Event Dispatch Thread

The main reason for the unexpected result is that you are creating an image that has the size of the frame - but the frame also has a title bar and a border, and these are "covering" parts of the image. The size of the area that is actually available for painting is smaller than the total frame size. Additionally, the getWidth() and getHeight() methods may return garbage as long as the frame is not yet visible on the screen.

One approach considering all this could look like in this snippet:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Mandelbrot 
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new GridLayout(1, 1));

        BufferedImage image = createImage(500, 500);
        ImagePanel imagePanel = new ImagePanel(image);
        frame.getContentPane().add(imagePanel);

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

    private static BufferedImage createImage(int w, int h)
    {
        BufferedImage image = new BufferedImage(w, h,
            BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < w; x++)
        {
            image.setRGB(x, x, Color.GREEN.getRGB());
        }
        return image;
    }

    static class ImagePanel extends JPanel
    {
        private final BufferedImage image;

        ImagePanel(BufferedImage image)
        {
            this.image = image;
        }

        @Override
        public Dimension getPreferredSize()
        {
            if (super.isPreferredSizeSet())
            {
                return super.getPreferredSize();
            }
            return new Dimension(image.getWidth(), image.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            g.drawImage(image, 0, 0, null);
        }
    }

}
Marco13
  • 53,703
  • 9
  • 80
  • 159
  • 1
    While I'll except your answer as been relatively correct, you could also achieve the same thing by using a JLabel instead of the ImagePanel, just saying +1 – MadProgrammer Mar 30 '14 at 21:31
  • @MadProgrammer: Originally, he also was painting the image manually, and the ImagePanel shows how this can be done in a `JPanel#paintComponent`. But of course, if it's just about *somehow displaying* the image, an `...add(new JLabel(new ImageIcon(image)));` would do it, that's correct. – Marco13 Mar 30 '14 at 23:23
0

All BufferedImage objects have an upper left corner coordinate of (0, 0). Any Raster used to construct a BufferedImage must therefore have minX=0 and minY=0.

Therein lies your problem.

JavaDoc for BufferedImage

Edit:

Also remove this from your loop:

for (int y = 0; y < getWidth(); y++) {
    I.setRGB(x, x, Color.GREEN.getRGB());
}
Zyn
  • 614
  • 3
  • 10