Reputation: 95
I have a javafx
application and I have a rectangle in my ancorpane and I use rectangle.setFill()
to fill the rectangle with an image. Now assume the image is a round red ball but we all know that the png file is a rectangle. ( with a width and height ) so there are some parts of this png file that are white. ( outside the red circle ). I want to know if it's possible to change this white part of the image with another color, let's say blue.
So I don't want to set a background color to my anchorpane, if I did that, after rectangle.setFill()
line gets executed, it fills the rectangle with the image I put in the command without considering the background color of anchorpane. I want to change the color of the background of the "png file" I put in the rectangle.setFill()
inside the code.
If you need to know a specific definition of background, lets say that I want to change the color of every white colored pixel in my png file to blue color. (Not manually before running program but inside the code)
Upvotes: 0
Views: 600
Reputation: 114
Here is another way:
package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelReader;
import javafx.scene.image.PixelWriter;
import javafx.scene.paint.Color;
import javafx.scene.image.WritableImage;
public class ImageOpsTest extends Application {
@Override
public void start(Stage primaryStage) {
// Create Image and ImageView objects
Image image = new Image("file:///home/paradigma/Imagens/photo.png");
ImageView imageView = new ImageView();
imageView.setImage(image);
// Obtain PixelReader
PixelReader pixelReader = image.getPixelReader();
System.out.println("Image Width: "+image.getWidth());
System.out.println("Image Height: "+image.getHeight());
System.out.println("Pixel Format: "+pixelReader.getPixelFormat());
// Create WritableImage
WritableImage wImage = new WritableImage(
(int)image.getWidth(),
(int)image.getHeight());
PixelWriter pixelWriter = wImage.getPixelWriter();
// Determine the color of each pixel in a specified row
for(int readY=0;readY<image.getHeight();readY++){
for(int readX=0; readX<image.getWidth();readX++){
Color color = pixelReader.getColor(readX,readY);
System.out.println("\nPixel color at coordinates ("+
readX+","+readY+") "
+color.toString());
System.out.println("R = "+color.getRed());
System.out.println("G = "+color.getGreen());
System.out.println("B = "+color.getBlue());
System.out.println("Opacity = "+color.getOpacity());
System.out.println("Saturation = "+color.getSaturation());
if (color.equals(Color.WHITE)) color = color.BLUE;
pixelWriter.setColor(readX,readY,color);
}
}
// Display image on screen
imageView.setImage(wImage);
StackPane root = new StackPane();
root.getChildren().add(imageView);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Image Write Test");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The "System.out.println" codes is present to give a idea of the components colors of each pixel, nevertheless, make the code slow. If this information is irrelevant the print's can be commented (this will make the code faster).
Upvotes: 0
Reputation: 209330
You can get a PixelReader
from the original image which you can use to query the color of the individual pixels.
You can then create a PixelBuffer
and copy the pixels over to it, adjusting any that need to be adjusted.
Then create a WritableImage
from the PixelBuffer
. You can even adjust the pixel data dynamically, calling updateBuffer
on the buffer to make sure the image updates.
Here's an example, where you can choose a color to replace the white background with:
import java.nio.IntBuffer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ColorPicker;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelBuffer;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.PixelReader;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class App extends Application {
@Override
public void start(Stage stage) {
Image originalImage = createImage();
ImageView orig = new ImageView(originalImage);
ColorPicker colorPicker = new ColorPicker(Color.BLUE);
int width = (int) originalImage.getWidth();
int height = (int) originalImage.getHeight();
int[] pixels = new int[width * height];
PixelBuffer<IntBuffer> pixelBuffer = new PixelBuffer<IntBuffer>(width, height, IntBuffer.wrap(pixels), PixelFormat.getIntArgbPreInstance());
adjustImage(originalImage, colorPicker.getValue(), pixelBuffer, pixels);
ImageView adjusted = new ImageView(new WritableImage(pixelBuffer));
HBox images = new HBox(5, orig, adjusted);
colorPicker.valueProperty().addListener((obs, oldColor, newColor) -> adjustImage(originalImage, newColor, pixelBuffer, pixels));
HBox controls = new HBox(5, colorPicker);
BorderPane root = new BorderPane(images);
root.setTop(controls);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
private void adjustImage(Image original, Color newColor, PixelBuffer<IntBuffer> buffer, int[] pixels) {
int alpha = (int)(newColor.getOpacity() * 255) ;
int r = (int)(newColor.getRed() * 255);
int g = (int)(newColor.getGreen() * 255);
int b = (int)(newColor.getBlue() * 255);
int replacement = alpha << 24 | r << 16 | g << 8 | b ;
int width = (int)original.getWidth() ;
int height = (int)original.getHeight();
PixelReader pixelReader = original.getPixelReader() ;
for (int y = 0 ; y < height ; y++) {
for (int x = 0 ; x < width ; x++) {
int argb = pixelReader.getArgb(x, y);
if (argb == 0xFFFFFFFF) {
pixels[x+y*width] = replacement ;
} else {
pixels[x+y*width] = argb ;
}
}
}
buffer.updateBuffer(buff -> null);
}
private Image createImage() {
// In real life here you can just read an image from a resource in the normal way
// This just creates an image on the fly to make the example stand alone
int width = 400 ;
int height = 400 ;
int[] pixels = new int[width*height];
for (int y = 0 ; y < height ; y++) {
for (int x = 0 ; x < width ; x++) {
if ((x-200)*(x-200) + (y-200)*(y-200) < 40000) {
pixels[x+y*width] = 0xffff0000 ;
} else {
pixels[x+y*width] = 0xffffffff ;
}
}
}
return new WritableImage(new PixelBuffer<IntBuffer>(width, height, IntBuffer.wrap(pixels), PixelFormat.getIntArgbPreInstance()));
}
public static void main(String[] args) {
launch();
}
}
Upvotes: 2