drewpol drewpol - 17 days ago 5
Java Question

Letter visualisation in TilePane in JavaFX

What I need to do:

I trying to write some code for visualise every pixel of any character. I decided best way for it will be show pixels as rectangle in Tile Pane. So this is effect which i need to reach:

enter image description here

What's my problem:

I wrote some code to make it by take snaphost of

text1
and save it as
WritableImage
. Then i use
PixelReader
for read each pixel of this image by
argb
method. In loop when each integer rgb value is greater than TRESHOLD (is brighter) I add new tile with white background. Unless I add tile with black background. But something is still wrong with my idea and I get this effect:

enter image description here

There is my code:

public class Main extends Application {

@Override
public void start(Stage primaryStage) throws Exception{
//Create single letter string
String letter = "a";
//Create new text
Text text1 = new Text(letter);
//Set font for text
text1.setFont(Font.font("Calibri", FontWeight.NORMAL, 12));

//Save text1 as writable image
WritableImage newImg = text1.snapshot(null, null);

//Take bounds of letter
int imgHeight = (int) newImg.getHeight();
int imgWidth = (int) newImg.getWidth();

//Create pixel reader from newImg
PixelReader reader = newImg.getPixelReader();

//This is for preview image
ImageView imgPreview = new ImageView(newImg);

//Create tilePane
TilePane tilePane = new TilePane();
//New group with tilePane inside
Group display = new Group(tilePane);

//Bg color
tilePane.setStyle("-fx-background-color: gray;");
//Small gaps between tiles
tilePane.setHgap(2);
tilePane.setVgap(2);

//Set quantity of columns equals image width
tilePane.setPrefColumns(imgWidth);
//Set quantity of rows equals image height
tilePane.setPrefRows(imgHeight );

//Here I set tolerance treshold
int TOLERANCE_THRESHOLD = 0xf0;


for (int x = 0; x < imgWidth; x++) {
for (int y = 0; y < imgHeight; y++) {

int argb = reader.getArgb(x, y);

int r = (argb >> 16) & 0xFF;
int g = (argb >> 8) & 0xFF;
int b = argb & 0xFF;

if (r >= TOLERANCE_THRESHOLD
&& g >= TOLERANCE_THRESHOLD
&& b >= TOLERANCE_THRESHOLD) {
tilePane.getChildren().add(createElement(Color.WHITE));
}
else tilePane.getChildren().add(createElement(Color.BLACK));

}
}

// Create new stage
Stage stage = new Stage();
//Create new group
Group grupa = new Group();
Scene scene = new Scene(grupa, 400, 300, Color.GRAY);

grupa.getChildren().addAll(display);
stage.setScene(scene);
stage.show();
}

private Rectangle createElement(Color color) {
Rectangle rectangle = new Rectangle(15, 15);
//rectangle.setStroke(Color.ORANGE);
rectangle.setFill(color);

return rectangle;
}

public static void main(String[] args) {
launch(args);
}
}


What I doing wrong? Maby are other ways to take this effect?

Answer

Your outer loop variable is the x-coordinate and the inner loop variable is the y-coordinate.

This means you read the pixels column by column left to right. TilePane however requires the children list to be ordered row by row from top to bottom.

To fix the issue simply swap the loops. Use:

for (int y = 0; y < imgHeight; y++) {
    for (int x = 0; x < imgWidth; x++) {
        ...
    }
}

Instead of

for (int x = 0; x < imgWidth; x++) {
    for (int y = 0; y < imgHeight; y++) {
        ...
    }
}