Optional anecdote
I find the Java library documentation very difficult to read and so I present here a similar discovery.
Most of what I report I did actually get from the manual but only with very critical help from a few Java gurus.
How to do pixels from a Java Program
Many grahics environments try to keep programmers away from pixels for good reason: such as they may change their nature in the future.
Indeed pixels are gradually getting smaller.
If you want to draw a fractal, however, imposing intermediate graphic abstraction degrades the power of the pixels to show the truth.
Even when you compute a smooth curve in order to plot it, it is only logical to compute it for just the points that you can plot—the pixels!
I provide a Java program that illustrates four ways of drawing from a Java application, of which three provide pixel access.
With Java 1.5 on my Mac I get:
pix.jpeg
pix.png (This should look like the image above.)
On my Mac (OS 10.4.10, Java build 1.5.0_07-87) I get such a picture on my screen with
javac JavaPix.java
java Main pix.png pix.jpeg
(The first command produces files MainCanvas.class and Main.class which the second command uses.)
Since the ellipse is drawn when paint is called, the ellipse but not the shading, remains tangent to the window edges.
The two files do not have the ellipse because it is only computed as the pixels are put on the screen.
The size of the png file produced by the program is 115KB.
If you read and write the file using the Preview program that comes with OS X, the new size is 1028 bytes.
Code Explanation
X and Y are the constant image sizes.
I is a BufferedImage which is in this case as a wrapper for an array of ints, one per pixel, which we can modify by one of two schemes:
- I.setRGB sets an addressed pixel to a color described in the right 24 bits of the
int.
With this method we set a tan background and scratch it just to prove that we were there.
(This takes 180 ms to set the 71K pixels. (400MHz PowerPC))
(It takes 4.8 ms on a 1.8 GHz Intel duo.)
- For better performance we extract a WritableRaster from our BufferedImage which is merely a different wrapper for the stored pixels.
The technique I show here requires an array of words, three per pixel, that we fill with a graduated color.
In this context “a[z] =” sets the red intensity, “a[z+1] =” the green and “a[z+2] =” the blue.
Then, with the wr.setPixels invocation, we send that array, a, to the WritableRaster which slurps up the color data.
(It takes 28 ms to copy these 71K pixels thus.
DVD players must find something faster!)
- Changing the if(true) to if(false) causes the program to produce the same result using setPixel instead of setPixels.
(This takes 7.5 ms.)
Now the picture, except for the oval, is in the shared pixels behind the BufferedImage and WritableRaster.
Having computed the picture once, the paint method of our MainCanvas class refers to the BufferedImage as Main.I, and then draws the oval.
Thus we access the constant image each time the window is resized.
More insights from Sun
Changing image
This program produces an image that changes with time.
It is paced by the computation in the main loop.