I made a little JavaFX app generating longshadows. At this point I struggle with the rendering (see picture).
- The missing line on the rectangle's corner seems hard to fix. Changing the loop, which applies the manipulation, will mess up other shapes' shadow (e.g. circle).
- The glitch at 'a' is related to the Bresenham algorithm, I guess.(?)
Additional info:
Changing the image resolution makes no difference: Gitches keep showing.
Question:
How to get it fixed? Does the SDK provide something helpful? Do I have to rewrite the code?
Code
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import javax.imageio.ImageIO;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.stage.Stage;
public class Main extends Application {
private PrintWriter writer;
private String colorObjFilter = "0x009688ff";
private static final String IMG_PATH = "img/ls-test-1k.png";
private static final int LONGSHADOW_LENGTH = 100;
private static final String
ANSI_GREEN = "\u001B[32m",
ANSI_RESET = "\u001B[0m";
@Override
public void start(Stage stage) throws Exception {
writer = new PrintWriter("out.txt", "UTF-8");
InputStream is = new FileInputStream(new File(IMG_PATH));
ImageView imageView = new ImageView(new Image(is));
Image image = imageView.getImage();
StackPane root = new StackPane();
Scene scene = new Scene(root, image.getWidth(), image.getHeight(), Paint.valueOf
("#EEEEEE"));
scene.addEventFilter(KeyEvent.KEY_PRESSED, evt -> {
if (evt.getCode().equals(KeyCode.ESCAPE)) {
stage.close();
}
});
final Canvas canvas = new Canvas(image.getWidth(), image.getHeight());
canvas.setOnMouseClicked((MouseEvent e) -> {
Color color = image.getPixelReader().getColor((int) e.getX(), (int) e.getY());
System.out.println(ANSI_GREEN + " -> " + color.toString() + ANSI_RESET);
colorObjFilter = color.toString();
try {
processImage(root, canvas, image);
} catch (IOException e1) {
e1.printStackTrace();
}
});
root.getChildren().addAll(imageView, canvas);
stage.setScene(scene);
stage.show();
}
private void processImage(StackPane root, Canvas canvas, Image image) throws IOException {
long delta = System.currentTimeMillis();
int width = (int) image.getWidth();
int height = (int) image.getHeight();
GraphicsContext gc = canvas.getGraphicsContext2D();
System.out.println("width: " + width + "\theight: " + height);
BufferedImage bufferedImage = ImageIO.read(new File(IMG_PATH));
// keep threshold small to get clean paths to draw
edgeDetection(gc, image, 0.00000001d);
writer.close();
Label label = new Label();
root.setAlignment(Pos.BOTTOM_LEFT);
root.setOnMouseMoved(event -> label.setText(event.getX() + "|" + event.getY()
+ "|" + bufferedImage.getRGB((int) event.getX(), (int) event.getY())));
root.getChildren().addAll(label);
System.out.println("took: " + (System.currentTimeMillis() - delta) + " ms");
}
public void edgeDetection(GraphicsContext gc, Image image, double threshold) {
Color topPxl, lowerPxl;
double topIntensity, lowerIntensity;
PixelWriter pw = gc.getPixelWriter();
for (int y = 0; y < image.getHeight() - 1; y++) {
for (int x = 1; x < image.getWidth(); x++) {
topPxl = image.getPixelReader().getColor(x, y);
lowerPxl = image.getPixelReader().getColor(x - 1, y + 1);
topIntensity = (topPxl.getRed() + topPxl.getGreen() + topPxl.getBlue()) / 3;
lowerIntensity = (lowerPxl.getRed() + lowerPxl.getGreen() + lowerPxl.getBlue()) / 3;
if (Math.abs(topIntensity - lowerIntensity) > threshold) {
int y2 = y;
for (int x2 = x; x2 < x + LONGSHADOW_LENGTH; x2++) {
y2++;
try {
Color color = image.getPixelReader().getColor(x2, y2);
// colorObjFilter protects the purple letter being manipulated
if (!color.toString().toLowerCase()
.contains(colorObjFilter.toLowerCase())) {
pw.setColor(x2, y2, Color.color(.7f, .7f, .7f, .9f));
}
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
}
}
}
public static void main(String[] args) {
launch(args);
}
}