BiLinear gradient:
Yes, again...but this time in JavaFX. So you might now that stuff already from former blogposts and for those of you that do not know what I'm talking about, here is a little image that explains it...
To create the image above I've used the following code...
public class BiLinearGradient {
private final Color COLOR_00; // upper left corner
private final Color COLOR_10; // upper right corner
private final Color COLOR_01; // lower left corner
private final Color COLOR_11; // lower right corner
public BiLinearGradient(Color c00, Color c10, Color c01, Color c11) {
COLOR_00 = c00;
COLOR_10 = c10;
COLOR_01 = c01;
COLOR_11 = c11;
}
private Color interpolateColor(Color c1, Color c2, double frac) {
double red = c1.getRed() + (c2.getRed() - c1.getRed()) * frac;
double green = c1.getGreen() + (c2.getGreen() - c1.getGreen()) * frac;
double blue = c1.getBlue() + (c2.getBlue() - c1.getBlue()) * frac;
double alpha = c1.getOpacity() + (c2.getOpacity() - c1.getOpacity()) * frac;
red = red < 0 ? 0 : (red > 1 ? 1 : red);
green = green < 0 ? 0 : (green > 1 ? 1 : green);
blue = blue < 0 ? 0 : (blue > 1 ? 1 : blue);
alpha = alpha < 0 ? 0 : (alpha > 1 ? 1 : alpha);
return Color.color(red, green, blue, alpha);
}
private Color biLinearInterpolateColor(Color c00, Color c10, Color c01,
Color c11, double fracX, double fracY) {
Color interpolatedColX1 = interpolateColor(c00, c10, fracX);
Color interpolatedColX2 = interpolateColor(c01, c11, fracX);
return interpolateColor(interpolatedColX1, interpolatedColX2, fracY);
}
public Image getImage(double w, double h) {
int width = (int) w <= 0 ? 100 : (int) w;
int height = (int) h <= 0 ? 100 : (int) h;
double fractionX = 0;
double fractionY = 0;
WritableImage raster = new WritableImage(width, height);
PixelWriter pixelWriter = raster.getPixelWriter();
double fractionStepX = 1.0 / (w - 1);
double fractionStepY = 1.0 / (h - 1);
for (int y = 0; y < h ; y++) {
for (int x = 0 ; x < w ; x++) {
pixelWriter.setColor(x, y,
biLinearInterpolateColor(COLOR_00, COLOR_10,
COLOR_01, COLOR_11,
fractionX, fractionY));
fractionX += fractionStepX;
fractionX = fractionX > 1 ? 1 : fractionX;
}
fractionY += fractionStepY;
fractionY = fractionY > 1 ? 1 : fractionY;
fractionX = 0;
}
return raster;
}
}
The important thing in the code above is the interpolateColor() method because this method is able to calculate a color between two given colors by a given fraction between 0.0 - 1.0.
When I was scanning the web I've found a script written in PHP that pixelates a given image...I know...PHP...there are better implementations I'm sure but I found it and converted the code to JavaFX and now I could pixelate a given image too...oh look whose that...
Original and pixelated version (12 px blocksize) |
private Group pixelate(Image image, int blockSize) {
PixelReader pixelReader = image.getPixelReader();
int width = (int) IMAGE.getWidth();
int height = (int) IMAGE.getHeight();
Group newImage = new Group();
List<Color> colors = new ArrayList<Color>();
for (int y = 0; y < height; y += blockSize) {
for (int x = 0; x < width; x += blockSize) {
Color col = pixelReader.getColor(x, y);
int newRed = 0;
int newGreen = 0;
int newBlue = 0;
colors.clear();
for (int blockY = y; blockY < y + blockSize; ++blockY) {
for (int blockX = x; blockX < x + blockSize; ++blockX) {
if (blockX < 0 || blockX >= width) {
colors.add(col);
continue;
}
if (blockY < 0 || blockY >= height) {
colors.add(col);
continue;
}
colors.add(pixelReader.getColor(blockX, blockY));
}
}
for(Color color : colors) {
newRed += (int) (color.getRed() * 255) & 0xFF;
newGreen += (int) (color.getGreen() * 255) & 0xFF;
newBlue += (int) (color.getBlue() * 255) & 0xFF;
}
int noOfColors = colors.size();
newRed /= noOfColors;
newGreen /= noOfColors;
newBlue /= noOfColors;
Rectangle box = new Rectangle(x + blockSize - 1, y + blockSize -1,
blockSize, blockSize);
box.setFill(Color.rgb(newRed, newGreen, newBlue));
newImage.getChildren().add(box);
}
}
return newImage;
}
During my trip to Heidelberg yesterday I suddenly got the idea to use one of my led controls instead of rectangles to pixelate the image which gaves me the following image...
Like I always say...it's all about having fun... :)
Plasma:
Well the next one was really just for fun and is based on some quite old code I've found on the web (to be honest I was not searching for it but simply found it randomly). Again I've converted it to JavaFX and here you go, a plasma implementation...
To achieve that effect you need the following piece of code...
public class Plasma {
private static final Random RND = new Random();
private int gridMX, gridMY;
private int x, y;
private double maxC, cScale;
private double rX2, rY2, gX2, gY2, bX2, bY2;
private double rXA2, rYA2, gXA2, gYA2, bXA2, bYA2;
private double rX1, rY1, gX1, gY1, bX1, bY1;
private double rXA1, rYA1, gXA1, gYA1, bXA1, bYA1;
private double[][] redLookup;
private double[][] greenLookup;
private double[][] blueLookup;
private PixelWriter pixelWriter;
private WritableImage plasmaImage;
private AnimationTimer timer;
public Plasma(double width, double height) {
gridMX = (int) width;
gridMY = (int) height;
plasmaImage = new WritableImage(gridMX, gridMY);
pixelWriter = plasmaImage.getPixelWriter();
maxC = Math.sqrt(((gridMX - 1.0) * (gridMX - 1.0))
+ ((gridMY - 1.0) * (gridMY - 1.0)));
cScale = (maxC / 100.0);
redLookup = new double[gridMX + 1][gridMY + 1];
greenLookup = new double[gridMX + 1][gridMY + 1];
blueLookup = new double[gridMX + 1][gridMY + 1];
rX1 = RND.nextInt(gridMX);
rY1 = RND.nextInt(gridMY);
gX1 = RND.nextInt(gridMX);
gY1 = RND.nextInt(gridMY);
bX1 = RND.nextInt(gridMX);
bY1 = RND.nextInt(gridMY);
rX2 = RND.nextInt(gridMX);
rY2 = RND.nextInt(gridMY);
gX2 = RND.nextInt(gridMX);
gY2 = RND.nextInt(gridMY);
bX2 = RND.nextInt(gridMX);
bY2 = RND.nextInt(gridMY);
double xr = gridMX / 20.0;
double yr = gridMY / 20.0;
rXA1 = RND.nextInt((int) (xr * 10)) / xr - (xr / 2.0);
rYA1 = RND.nextInt((int) (yr * 10)) / yr - (yr / 2.0);
gXA1 = RND.nextInt((int) (xr * 10)) / xr - (xr / 2.0);
gYA1 = RND.nextInt((int) (yr * 10)) / yr - (yr / 2.0);
bXA1 = RND.nextInt((int) (xr * 10)) / xr - (xr / 2.0);
bYA1 = RND.nextInt((int) (yr * 10)) / yr - (yr / 2.0);
rXA2 = RND.nextInt((int) (xr * 10)) / xr - (xr / 2.0);
rYA2 = RND.nextInt((int) (yr * 10)) / yr - (yr / 2.0);
gXA2 = RND.nextInt((int) (xr * 10)) / xr - (xr / 2.0);
gYA2 = RND.nextInt((int) (yr * 10)) / yr - (yr / 2.0);
bXA2 = RND.nextInt((int) (xr * 10)) / xr - (xr / 2.0);
bYA2 = RND.nextInt((int) (yr * 10)) / yr - (yr / 2.0);
for (x = 0; x < gridMX; x++) {
for (y = 0; y < gridMY; y++) {
redLookup[x][y] = (int)(((double) x / (double)gridMX) * 255.0);
greenLookup[x][y] = (int)(((double) y / (double)gridMY) * 255.0);
blueLookup[x][y] = 127;
}
}
timer = new AnimationTimer() {
@Override public void handle(long now) {
update();
}
};
}
public Image getImage() {
return plasmaImage;
}
public void start() {
timer.start();
}
public void stop() {
timer.stop();
}
private double getShade(double a, double b) {
return (1.0 - (Math.sqrt(a * a + b * b) / maxC)) * cScale;
}
private void update() {
if (((rX1 + rXA1) >= gridMX) || ((rX1 + rXA1) < 0)) {
rXA1 = -rXA1;
}
if (((rY1 + rYA1) >= gridMY) || ((rY1 + rYA1) < 0)) {
rYA1 = -rYA1;
}
if (((gX1 + gXA1) >= gridMX) || ((gX1 + gXA1) < 0)) {
gXA1 = -gXA1;
}
if (((gY1 + gYA1) >= gridMY) || ((gY1 + gYA1) < 0)) {
gYA1 = -gYA1;
}
if (((bX1 + bXA1) >= gridMX) || ((bX1 + bXA1) < 0)) {
bXA1 = -bXA1;
}
if (((bY1 + bYA1) >= gridMY) || ((bY1 + bYA1) < 0)) {
bYA1 = -bYA1;
}
if (((rX2 + rXA2) >= gridMX) || ((rX2 + rXA2) < 0)) {
rXA2 = -rXA2;
}
if (((rY2 + rYA2) >= gridMY) || ((rY2 + rYA2) < 0)) {
rYA2 = -rYA2;
}
if (((gX2 + gXA2) >= gridMX) || ((gX2 + gXA2) < 0)) {
gXA2 = -gXA2;
}
if (((gY2 + gYA2) >= gridMY) || ((gY2 + gYA2) < 0)) {
gYA2 = -gYA2;
}
if (((bX2 + bXA2) >= gridMX) || ((bX2 + bXA2) < 0)) {
bXA2 = -bXA2;
}
if (((bY2 + bYA2) >= gridMY) || ((bY2 + bYA2) < 0)) {
bYA2 = -bYA2;
}
rX1 += rXA1;
rY1 += rYA1;
gX1 += gXA1;
gY1 += gYA1;
bX1 += bXA1;
bY1 += bYA1;
rX2 += rXA2;
rY2 += rYA2;
gX2 += gXA2;
gY2 += gYA2;
bX2 += bXA2;
bY2 += bYA2;
for (x = 0; x < gridMX; x++) {
for (y = 0; y < gridMY; y++) {
redLookup[x][y] += getShade(x - rX1, y - rY1);
greenLookup[x][y] += getShade(x - gX1, y - gY1);
blueLookup[x][y] += getShade(x - bX1, y - bY1);
redLookup[x][y] -= getShade(x - rX2, y - rY2);
greenLookup[x][y] -= getShade(x - gX2, y - gY2);
blueLookup[x][y] -= getShade(x - bX2, y - bY2);
redLookup[x][y] = redLookup[x][y] > 255 ? redLookup[x][y] = 255 :
(redLookup[x][y] < 0 ? 0 : redLookup[x][y]);
greenLookup[x][y] = greenLookup[x][y] > 255 ? greenLookup[x][y] = 255 :
(greenLookup[x][y] < 0 ? 0 : greenLookup[x][y]);
blueLookup[x][y] = blueLookup[x][y] > 255 ? blueLookup[x][y] = 255 :
(blueLookup[x][y] < 0 ? 0 : blueLookup[x][y]);
pixelWriter.setColor(x, y, Color.rgb((int) redLookup[x][y], (int)
greenLookup[x][y], (int) blueLookup[x][y]));
}
}
}
}
That's it for another week of JavaFX fun...keep coding...
Hi Gerrit,
ReplyDeleteWhich LED control of yours did you use, instead of Rectangle, for the second pixelated example?
Thanks
Hi Roberto,
DeleteYou could find additional JavaFX controls in the JFXtras project at jfxtras.org. The code is hosted on github in the jfxtras-labs project. The Led control is part of this project. So feel free to take a look.
Cheers,
Gerrit