Draw a pixel-by-pixel image

Asked

Viewed 1,749 times

2

I’m trying to make a stupid little program but I’m not getting it.

I want to randomly redraw a pixel-by-pixel image, doing this with multiple threads.

I don’t know much about Java Swing, so I’m hitting myself pretty hard.

I did some research before posting, I understood I should use the BufferedImage for this.

I found an example of multi-processing that approaches what I would like to do. The difference is that he actually draws an image and does it line by line, I’d like to upload it, but I couldn’t adapt it to my need.

Here is the full source: Multiprocessing - Image.

And here where he draws the picture:

private class Runner extends Thread {
    double xmin, xmax, ymin, ymax;
    int maxIterations;
    int[] rgb;
    int[] palette;
    int width, height;
    int startRow, endRow;

    Runner(int startRow, int endRow) {
        this.startRow = startRow;
        this.endRow = endRow;
        width = image.getWidth();
        height = image.getHeight();
        rgb = new int[width];
        palette = new int[256];
        for (int i = 0; i < 256; i++)
            palette[i] = Color.getHSBColor(i / 255F, 1, 1).getRGB();
        xmin = -1.6744096740931858;
        xmax = -1.674409674093473;
        ymin = 4.716540768697223E-5;
        ymax = 4.716540790246652E-5;
        maxIterations = 10000;
    }

    public void run() {
        try {
            double x, y;
            double dx, dy;
            dx = (xmax - xmin) / (width - 1);
            dy = (ymax - ymin) / (height - 1);

            for (int row = startRow; row <= endRow; row++) { 
                y = ymax - dy * row;
                for (int col = 0; col < width; col++) {
                    x = xmin + dx * col;
                    int count = 0;
                    double xx = x;
                    double yy = y;
                    while (count < maxIterations && (xx * xx + yy * yy) < 4) {
                        count++;
                        double newxx = xx * xx - yy * yy + x;
                        yy = 2 * xx * yy + y;
                        xx = newxx;
                    }
                    if (count == maxIterations)
                        rgb[col] = 0;
                    else
                        rgb[col] = palette[count % palette.length];
                }
                if (!running) { 
                    return;
                }
                synchronized (image) {
                    image.setRGB(0, row, width, 1, rgb, 0, width);
                }
                display.repaint(0, row, width, 1); 
            }
        } finally {
            threadFinished();
        }
    }
}

How can I upload my own image and redraw the pixels?


EDITED:

I tested as the example below, but it does not draw pixel by pixel as the example, it seems that is drawn in rectangles.

It follows the way I did. What could be wrong?? I am using Jpanel and not Canvas.

private class Runner extends Thread {
    int width, height;
    Random randomi = new Random();
    Random randomj = new Random();
    Graphics g = image.getGraphics();

    Runner(int startRow, int endRow) {
        width = image.getWidth();
        height = image.getHeight();
    }

    public void run() {
        try {

            for (int xx = 0; xx < (width + height); xx++) {

                int i = randomi.nextInt(width);
                int j = randomj.nextInt(height);
                
                //System.out.println("i = " + i + "  j = " + j);
                //g.setColor(getColor(i, j));
                //g.drawLine(i, j, i, j);

                image.setRGB(i, j, getColor(i, j).getRGB());
                display.repaint(i, j, i, j);

                try {
                    Thread.sleep(5);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }    
            }    
        } finally {
            threadFinished();
        }
    }
}

2 answers

2

I find it difficult to take pixels randomly because you strong chance to forget some. This is what happens in the solution given by jsantos.

The solution is to place all pixel coordinates (x, y) in a table. If the image is 60x60, then you will have an array with 3600 entries. Then you mix the array. Then it would be enough to read the 'mixed' array and each time, you will be sure to have a new pixel. To "mix" an array in Java, you can use:

 Collections.shuffle(arrayList);

1


It’s far from a good code, but you can get an idea of how it works at least.

This code makes

  • picks up the image
  • then draw the pixel image by pixel at random

In my test the image was 60 by 60, as it is random there are always points that the function did not fetch, so did not paint on the screen the full picture...

Test yourself and see if you can get ideas for what you want to do.

Code:

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;

import javax.swing.JFrame;
import org.openide.util.Exceptions;

public class PixelCanvas extends Canvas {

    private static final int WIDTH = 100;
    private static final int HEIGHT = 100;
    private static final Random random = new Random();
    private static final Random randomi = new Random();
    private static final Random randomj = new Random();
    private static BufferedImage image = null;

    public PixelCanvas() {
        getImg();
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        for (int xx = 0; xx < 10000; xx++) {

            int i = randomi.nextInt(image.getWidth());
            int j = randomj.nextInt(image.getHeight());
            g.setColor(getColor(i, j));
            g.drawLine(i, j, i, j);


            try {
                Thread.sleep(1);
            } catch (InterruptedException ex) {
                Exceptions.printStackTrace(ex);
            }

        }



    }

    private Color getColor(int i, int j) {
        return marchThroughImage(image, i, j);
    }

    public void getImg() {
        try {
            // get the BufferedImage, using the ImageIO class
            image = ImageIO.read(this.getClass().getResource("sms2.png"));
            System.out.println(" with" + image.getWidth());
            System.out.println(" height" + image.getHeight());
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
    }

    private Color marchThroughImage(BufferedImage image, int i, int j) {
        System.out.println("width, height: " + randomi + ", " + randomj);

        Color cor = new Color(image.getRGB(i, j));
        return cor;

    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(WIDTH, HEIGHT);
        frame.add(new PixelCanvas());


        frame.setVisible(true);
    }
}

Image used: img

As it turned out: imgalterada

attention: the image should be in the same place where the file . java if you do not want there you have to change the path in this code:

 ImageIO.read(this.getClass().getResource("sms2.png"));

CODE EDITING

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;

import javax.swing.JFrame;
import javax.swing.JPanel;
import org.openide.util.Exceptions;

public class PixelCanvas extends Canvas {

    private static final int WIDTH = 100;
    private static final int HEIGHT = 100;
    private static BufferedImage image = null;
    private List<imgByPosicaoCor> listpixel = new ArrayList<>();

    public PixelCanvas() {
        getImg();
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);

        Collections.shuffle(listpixel);

        for (imgByPosicaoCor pixel : listpixel) {
            g.setColor(pixel.getCor());
            g.drawLine(pixel.getI(), pixel.getJ(), pixel.getI(), pixel.getJ());

            try {
                Thread.sleep(5);
            } catch (InterruptedException ex) {
                Exceptions.printStackTrace(ex);
            }

        }

    }

    public void getImg() {
        try {
            // get the BufferedImage, using the ImageIO class
            image = ImageIO.read(this.getClass().getResource("sms2.png"));
            int whith = image.getWidth();
            int heigth = image.getHeight();

            System.out.println(" with" + image.getWidth());
            System.out.println(" height" + image.getHeight());

            for (int i = 0; i < whith; i++) {
                for (int j = 0; j < heigth; j++) {
                    imgByPosicaoCor pixel = new imgByPosicaoCor(i, j, new Color(image.getRGB(i, j)));
                    listpixel.add(pixel);
                }
            }
            System.out.println("TOTAL NA LISTA" + listpixel.size());
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(WIDTH, HEIGHT);
        frame.add(new PixelCanvas());
        frame.setVisible(true);
    }

}

@Peter thanks for the tip, now the code is much better (compared to the first).

  • Dude, ball show. I’m gonna try to apply this to that fountain I found, simpler than I thought. With multiple threads should get super fast, I’ll test there put here again.

  • I tried as you suggested, but I didn’t get the same effect. It looks like it’s drawn by rectangles. What could be wrong? I edited my question and added the font. Thank you.

  • increase the time he falls asleep drawing each stitch, here Thread.sleep(100) in my right spot...

  • I edited the code, but the logic remains the same, I only applied peter’s help.

  • Show Showww... I will try to apply in my example Multithread this solution.. To see how it looks.

  • It was cool guys.. Thanks for the tip.. Now I have to make each thread work with an X amount of pixels.. Because they all update everything.. But that’s another 500. Thank you.

  • yes I think the logic now is not very difficult, you just have to divide this array into several and have each thread do one of these array

  • 1

    Yes, I made a limiter for the number of threads selected, it was good show. Thanks for the help.

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.