JavaFX渲染/图像处理

时间:2017-03-19 22:44:04

标签: java image-processing javafx bresenham

我做了一个小的JavaFX应用程序生成longshadows。在这一点上,我努力与渲染(见图)。

  1. 矩形角落上的缺失线似乎难以修复。改变应用操作的循环会弄乱其他形状。阴影(例如圆圈)。
  2. ' a'与Bresenham algorithm有关,我想。(?)
  3. 其他信息:

    更改图像分辨率没有区别:Gitch一直显示。

    问题:

    如何解决? SDK是否提供了有用的功能?我是否必须重写代码?

    Screenshot

    代码

    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);
        }
    }
    

1 个答案:

答案 0 :(得分:2)

我不知道为什么你的原始程序有一些渲染工件。

这是一个替代解决方案,它非常强力,因为它只是生成一个阴影图像,它在不同的偏移处反复渲染,最终形成一个长阴影。演示了几种生成shadowImage的方法,一种是对原始图像的ColorAdjust效果,另一种是使用PixelWriter生成阴影图像。

使用PixelWriter的原始解决方案适用于所有具有适当阴影生成算法的解决方案更优雅(如果您可以使其工作; - )。

shadow

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Label;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.Image;
import javafx.scene.image.PixelReader;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class ShadowSpray extends Application {
    private static final double W = 400;
    private static final double H = 400;
    private static final int SHADOW_LENGTH = 100;

    private static final double IMG_X = 20;
    private static final double IMG_Y = 20;

    private static final int FONT_SIZE = 200;

    private static final double SHADOW_SLOPE_FACTOR = 1.5;

    Color SHADOW_COLOR = Color.GRAY.brighter();

    @Override
    public void start(Stage stage) {
        Image image = getImage();

        Canvas canvas = new Canvas(W, H);
        GraphicsContext gc = canvas.getGraphicsContext2D();
//        drawWithShadowUsingStencil(gc, image, IMG_X, IMG_Y, SHADOW_LENGTH, SHADOW_COLOR);
        drawWithShadowUsingColorAdjust(gc, image, IMG_X, IMG_Y, SHADOW_LENGTH);

        stage.setScene(new Scene(new Group(canvas)));
        stage.show();
    }

    private void drawWithShadowUsingColorAdjust(GraphicsContext gc, Image image, double x, double y, int shadowLength) {
        // here the color adjust for the shadow is based upon the intensity of the input image color
        // which is a weird way to calculate a shadow color, but does come out nicely
        // because it appropriately handles antialiased input images.
        ColorAdjust monochrome = new ColorAdjust();
        monochrome.setBrightness(+0.5);
        monochrome.setSaturation(-1.0);

        gc.setEffect(monochrome);

        for (int offset = shadowLength; offset > 0; --offset) {
            gc.drawImage(image, x + offset, y + offset / SHADOW_SLOPE_FACTOR);
        }

        gc.setEffect(null);

        gc.drawImage(image, x, y);
    }

    private void drawWithShadowUsingStencil(GraphicsContext gc, Image image, double x, double y, int shadowLength, Color shadowColor) {
        Image shadow = createShadowImage(image, shadowColor);

        for (int offset = shadowLength; offset > 0; --offset) {
            gc.drawImage(shadow, x + offset, y + offset / SHADOW_SLOPE_FACTOR);
        }

        gc.drawImage(image, x, y);
    }


    private Image createShadowImage(Image image, Color shadowColor) {
        WritableImage shadow = new WritableImage(image.getPixelReader(), (int) image.getWidth(), (int) image.getHeight());
        PixelReader reader = shadow.getPixelReader();
        PixelWriter writer = shadow.getPixelWriter();
        for (int ix = 0; ix < image.getWidth(); ix++) {
            for (int iy = 0; iy < image.getHeight(); iy++) {
                int argb = reader.getArgb(ix, iy);
                int a = (argb >> 24) & 0xFF;
                int r = (argb >> 16) & 0xFF;
                int g = (argb >>  8) & 0xFF;
                int b =  argb        & 0xFF;

                // because we use a binary choice, we lose anti-alising info in the shadow so it looks a bit jaggy.
                Color fill = (r > 0 || g > 0 || b > 0) ? shadowColor : Color.TRANSPARENT;

                writer.setColor(ix, iy, fill);
            }
        }
        return shadow;
    }

    private Image getImage() {
        Label label = new Label("a");
        label.setStyle("-fx-text-fill: forestgreen; -fx-background-color: transparent; -fx-font-size: " + FONT_SIZE + "px;");
        Scene scene = new Scene(label, Color.TRANSPARENT);
        SnapshotParameters snapshotParameters = new SnapshotParameters();
        snapshotParameters.setFill(Color.TRANSPARENT);
        return label.snapshot(snapshotParameters, null);
    }

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

Inbuilt,JavaFX具有DropShadow效果,几乎是您想要的效果,特别是当您将展开设置为1并将半径设置为0时,它只会生成单个偏移阴影图像而不是长图像阴影效应。

使用一些替代文字和较短的“长影”:

Cat