Java: basic plotting, drawing a point/dot/pixel
Asked Answered
R

6

6

I need to just have a panel inside of which i'd be able to draw. I want to be able to draw pixel by pixel.

ps: I don't need lines/circles other primitives. pps: the graphics library does not really matter, it can be awt, swing, qt.. anything. I just want to have something that is usually represented by Bufferedimage or somethign like that where you set colors of single pixels and then render it to the screen.

Rebozo answered 13/2, 2013 at 17:39 Comment(2)
Unfortunately java does not have any method for drawing a single point, instead you have to use drawLine with a same point for both start & end.Cozart
@ExtremeCoders: that is a pitty, and doesn't this add a horrible overhead? I just want to be able to display large datasets..Rebozo
M
2

represented by Bufferedimage ..

I suggest a BufferedImage for that, displayed..

..or something like that where you set colors of single pixels and then render it to the screen.

..in a JLabel - as seen in this answer.

Of course, once we have an instance of BufferedImage, we can setRGB(..).

Mccully answered 13/2, 2013 at 17:51 Comment(0)
G
5

An example of one way to do it:

// Create the new image needed
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB );

for ( int rc = 0; rc < height; rc++ ) {
  for ( int cc = 0; cc < width; cc++ ) {
    // Set the pixel colour of the image n.b. x = cc, y = rc
    img.setRGB(cc, rc, Color.BLACK.getRGB() );
  }//for cols
}//for rows


and then from within overridden paintComponent(Graphics g)

((Graphics2D)g).drawImage(img, <args>)
Grazier answered 13/2, 2013 at 18:39 Comment(2)
Thanks, i will try something like that. Do you have anything on your mind to suggest me for further reading about this kind of graphics in Java?Rebozo
You may know this already, but just in case: http://docs.oracle.com/javase/tutorial/2d/index.htmlGrazier
M
2

represented by Bufferedimage ..

I suggest a BufferedImage for that, displayed..

..or something like that where you set colors of single pixels and then render it to the screen.

..in a JLabel - as seen in this answer.

Of course, once we have an instance of BufferedImage, we can setRGB(..).

Mccully answered 13/2, 2013 at 17:51 Comment(0)
A
2

If you honestly need to render pixel-by-pixel, I have done this at-length for hotspot visualization piece of software I wrote for a research lab.

What you want is BufferedImage.setRGB(..) -- if you are drawing pixel-by-pixel, I assume you have implemented an algorithm that will render the RGB values for each pixel (much like we did with the heat-maps). This is what we used in an old IE-compatible Applet back in the day. Worked like a charm and was relatively fast given what it was doing.

Unfortunately any time you manipulate the RGB values directly in a BufferedImage, it will become uncached by the backing video memory.

Since Java 7 though, I heard that the underlying J2D implementation will make an attempt at re-caching the image into video memory once the manipulations stop and rendering is done over-and-over again -- for example, while you are rendering the heat map it is not accelerated, but once it is rendered, as you drag the window around and work with the app, the backing image data can become re-accelerated.

Adamik answered 13/2, 2013 at 17:58 Comment(2)
thank you, i'm trying to do something similar - i have a series of spectra (measured continuously in time) and i want to plot them as a 2D map, coloring spots according to intensity. So it will look just like a heatmap. But there is a lot of data to plot, and i'm hoping to implement some smart buffering and threaded loading of data, so we could zoom in/out at a decent speed.Rebozo
@chhh - most welcome! When we implemented zoom, we kept around the final BufferedImage's at each zoom level (so they didn't have to be re-rendered) but if the resolution is too high, this blows your HEAP so you can write them out as a PNG to disk and load/re-render them on the fly or some equal trick if you need to. For us at least, it was still faster to do that than recalculate-and-rerender the frame.Adamik
R
2

If you want to do something quickly, you can just use the Graphics methods setColor and drawLine. For example:

public void paintComponent(Graphics g) {
    super.paintComponent(g);       

    // Set the colour of pixel (x=1, y=2) to black
    g.setColor(Color.BLACK);
    g.drawLine(1, 2, 1, 2);
}

I have used this technique and it wasn't terribly slow. I haven't compared it to using BufferedImage objects.

Roband answered 3/4, 2014 at 0:29 Comment(0)
E
0

A little late here, but you could always do it the way Java game programmers do, with a Screen class:

public class Screen {

    private int width, height;  

    public int[] pixels;

    public Screen(int width, int height) {
        this.width = width;
        this.height = height;

        pixels = new int[width * height];
    }

    public void render() {
        for(int y = 0; y < height; y++) {
            for(int x = 0; x < width; x++) {
                pixels[x + y * width] = 0xFFFFFF; //make every pixel white
            }
        }
    }

public void clear() {
            for(int i = 0; i < pixels.length; i++) {
                    pixels[i] = 0; //make every pixel black
            }
    }

}

And then in your main class:

    private Screen screen;

    private BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();

    public void render() {
         BufferStrategy bs = getBufferStrategy();
        if (bs == null) {
            createBufferStrategy(3);
            return;
        }

        screen.clear();
        screen.render();

         for(int i = 0; i < pixels.length; i++) {
            pixels[i] = screen.pixels[i];
         }

        Graphics g = bs.getDrawGraphics();
        g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
        g.dispose();
        bs.show();
}

That should work, I think.

Encrimson answered 27/6, 2014 at 10:41 Comment(0)
R
0

I'm coming with a solution which is fast and yet compatible with Graphics2D, in the sense that it doesn't draw from a detached pixel array.

fun drawLand(area: Rectangle): BufferedImage {
    val height = area.height

    val image = BufferedImage(area.width, height, BufferedImage.TYPE_INT_ARGB)
    val g2 = image.createGraphics()
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
    g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY)
    g2.background = Color.PINK
    g2.clearRect(area.x, area.y, area.width, area.height)

    val squares: Sequence<Square> = repo.getSquares(area)

    val pixels: IntArray = (image.raster.dataBuffer as DataBufferInt).data

    for (square in squares) {
        val color = square.color or OPAQUE // 0xFF000000.toInt()
        val base = square.location.y * height + square.location.x
        pixels[base] = color
    }

    g2.dispose()

    return image
}

Legend:

In the background, the image is backed by an Array of some Java primitives, depending on BufferedImage.TYPE_.

Here I opted for TYPE_INT_ARGB, so each pixel is conveniently an Int. Then you can go row by row and tamper with the underlying pixels.

Rakes answered 13/7, 2022 at 21:1 Comment(3)
Are you aiming for Necromancer badge? 9 years after the question got an accepted answer you re-post the same answer, but translated into KotlinRebozo
I work for the Kotlin marketing dept :) Hmm I thought the Jimmy's answer was different. But it is rather a bit obfuscated by the Screen class separation and a too wide line.Twombly
It's not his answer, look at the accepted answer by Andrew Thompson (use BufferImage and a link to another answer with complete code sample)Rebozo

© 2022 - 2024 — McMap. All rights reserved.