I have been working on a nonogram solver in Java, and all of my algorithm works fine, but I have been struggling with the visualization a little bit.
During the execution of the algorithm, I have access to two "solution-arrays". One is of type int[][]
, and contains values -1
for "certainly white", 0
for "uncertain" and 1
for "certainly black". Another array is of type float[][]
which contains values between 0
and 1
, here 0
is for certainly white, 1
is for certainly black and a value of .2
indicates it is more likely for the cell to be white than it to be black.
Since I've recently switched from PHP to Java programming (without proper introduction), I don't know much about visualizing this array properly. Of course I have first tried to simply print the first type of array to the console with characters like X
, .
and ?
, but this is far from nice. I then found something about BufferedImage
's, and I created the following function (for the float[][]
, the int[][]
is similar):
public void toImage(int w, int h, float[][] solution) throws IOException {
int[] data = toImage1(w, h, solution);
BufferedImage img = toImage2(data, w, h);
toImage3(img);
}
public int[] toImage1(int w, int h, float[][] solution) throws IOException {
int[] data = new int[w * h];
int i = 0;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int a = y / 100;
int b = x / 100;
int z = (int) (255 * Math.sqrt(1 - solution[a][b]));
if (solution[a][b] == 1 && ((((y % 100 >= 10 && y % 100 <= 15) || (y % 100 >= 85 && y % 100 <= 90)) && x % 100 >= 10 && x % 100 <= 90) || (((x % 100 >= 10 && x % 100 <= 15) || (x % 100 >= 85 && x % 100 <= 90)) && y % 100 >= 10 && y % 100 <= 90))) {
z = 100;
} else if (solution[a][b] == 0 && ((((y % 100 >= 10 && y % 100 <= 15) || (y % 100 >= 85 && y % 100 <= 90)) && x % 100 >= 10 && x % 100 <= 90) || (((x % 100 >= 10 && x % 100 <= 15) || (x % 100 >= 85 && x % 100 <= 90)) && y % 100 >= 10 && y % 100 <= 90))) {
z = 230;
}
data[i++] = z << 16 | z << 8 | z;
}
}
return data;
}
public BufferedImage toImage2(int[] data, int w, int h) {
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
img.setRGB(0, 0, w, h, data, 0, w);
return img;
}
public void toImage3(BufferedImage img) throws IOException {
File f = new File("Nonogram.png");
ImageIO.write(img, "PNG", f);
}
Here, w
and h
are supposed to be the amount of cells in each column resp. row multiplied by 100 (I want each cell to be represented by a block of 100x100 pixels).
I then also want an extra gray box in cells that are certain, that's what the if
and else if
are for.
This works beautifully, and creates images like this:
However, I run into two problems:
- This function is super slow. After profiling the execution, I see 90% of the execution time goes to this function. After breaking down my function into two bits, as suggested in the comments, I get the following profile:
- Instead of writing to a .png file, I would like a
JFrame
to display my image, but (again since I missed my proper introduction to Java),JFrame
's don't seem to be my best friends and I can't seem to work out how to use them.
Is there a possibility to fill entire 100x100 px cells at once? Is there a way to not have to create the entire BufferedImage
each time over, but just modify the bits that have changed in another method? Should I use something else than BufferedImage
? What elements does my code need, could someone code out an example method, or the needed code snippets?