使用PixelWriter / Reader滚动图像

时间:2017-04-01 15:25:23

标签: image-processing javafx

我正在尝试创建一个滚动图像,它围绕一个画布来跟随它自己的尾巴。我一直在尝试使用PixelWriters和Readers来保存从屏幕滚动到西方的垂直像素线,并将它们附加到一个新的图像上,该图像应该在屏幕的RHS(东)上增长。

它滚动,但就是这一切。我不明白如何计算扫描线,所以对这部分道歉。

任何帮助表示感谢。

package controller;

import javafx.animation.AnimationTimer;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import util.GraphicsUtils;

import java.io.File;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.nio.file.Paths;

class ImageContainer extends HBox {
int w, h;
int translatedAmount = 0;
Image image;
Canvas canvas;
long startNanoTime = System.nanoTime();
WritableImage eastImage = null;

public ImageContainer() {
    setVisible(true);
    load();
    w = (int) image.getWidth();
    h = (int) image.getHeight();
    canvas = new Canvas(w, h);
    int edgeX = (int) canvas.getWidth(); //You can set this a little west for visibility sake...whilst debugging
    getChildren().addAll(canvas);
    GraphicsContext gc = canvas.getGraphicsContext2D();
    canvas.setVisible(true);
    gc.drawImage(image, 0, 0, w, h);
    setPrefSize(w, h);
    eastImage = new WritableImage(translatedAmount+1, h); //create a new eastImage

    new AnimationTimer() {
        public void handle(long currentNanoTime) {
            if (((System.nanoTime() - startNanoTime) / 1000000000.0) < 0.05) {
                return;
            } else {
                startNanoTime = System.nanoTime();
            }

            translatedAmount++;

            Image westLine = getSubImageRectangle(image, 1, 0, 1, h); //get a 1 pixel strip from west of main image
            PixelReader westLinepixelReader = westLine.getPixelReader(); //create a pixel reader for this image
            byte[] westLinePixelBuffer = new byte[1 * h * 4]; //create a buffer to store the pixels collected from the about to vanish westLine
            westLinepixelReader.getPixels(0, 0, 1, h, PixelFormat.getByteBgraInstance(), westLinePixelBuffer, 0, 4); //collect the pixels from westLine strip

            Image tempImg = eastImage; //save away the current east side image

            byte[] tempBuffer = new byte[(int)tempImg.getWidth() * h * 4];
            PixelReader tempImagePixelReader = tempImg.getPixelReader(); //create a pixel reader for our temp copy of the east side image
            tempImagePixelReader.getPixels(0, 0, (int)tempImg.getWidth(), h, PixelFormat.getByteBgraInstance(), tempBuffer, 0, 4); //save the tempImage into the tempBuffer

            eastImage = new WritableImage(translatedAmount+1, h); //create a new eastImage, but one size larger
            PixelWriter eastImagePixelWriter = eastImage.getPixelWriter(); //create a pixel writer for this new east side image
            eastImagePixelWriter.setPixels(1, 0, (int)tempImg.getWidth(), h, PixelFormat.getByteBgraInstance(), tempBuffer, 0, 4); //copy the temp image in at x=1
            eastImagePixelWriter.setPixels((int)tempImg.getWidth(), 0, 1, h, PixelFormat.getByteBgraInstance(), westLinePixelBuffer, 0, 4); //copy the westLine at x=tempImg.width

            image = getSubImageRectangle(image, 1, 0, (int) image.getWidth() - 1, h);
            gc.drawImage(image, 0, 0); //draw main image
            System.out.println(edgeX-eastImage.getWidth());
            gc.drawImage(eastImage, edgeX-eastImage.getWidth(), 0); //add lost image lines
        }
    }.start();
}

public void load() {
    Path imagePath = Paths.get("./src/main/resources/ribbonImages/clouds.png");
    File f = imagePath.toFile();
    assert f.exists();
    image = new Image(f.toURI().toString());
}

public Image getSubImageRectangle(Image image, int x, int y, int w, int h) {
    PixelReader pixelReader = image.getPixelReader();
    WritableImage newImage = new WritableImage(pixelReader, x, y, w, h);
    ImageView imageView = new ImageView();
    imageView.setImage(newImage);
    return newImage;
}
}

1 个答案:

答案 0 :(得分:1)

为什么这比必要的更难?只需将图像绘制到Canvas两次:

public static void drawImage(Canvas canvas, Image sourceImage, double offset, double wrapWidth) {
    GraphicsContext gc = canvas.getGraphicsContext2D();
    gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());

    // make |offset| < wrapWidth
    offset %= wrapWidth;
    if (offset < 0) {
        // make sure positive offsets do not result in the previous version
        // of the image not being drawn
        offset += wrapWidth;
    }
    gc.drawImage(sourceImage, -offset, 0);
    gc.drawImage(sourceImage, wrapWidth - offset, 0);
}

@Override
public void start(Stage primaryStage) {
    Image image = new Image("https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg/402px-Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg");
    Canvas canvas = new Canvas(image.getWidth(), image.getHeight());
    primaryStage.setResizable(false);

    Scene scene = new Scene(new Group(canvas));

    DoubleProperty offset = new SimpleDoubleProperty();
    offset.addListener((observable, oldOffset, newOffset) -> drawImage(canvas, image, newOffset.doubleValue(), canvas.getWidth()));
    Timeline timeline = new Timeline(
            new KeyFrame(Duration.ZERO, new KeyValue(offset, 0, Interpolator.LINEAR)),
            new KeyFrame(Duration.seconds(10), new KeyValue(offset, image.getWidth()*2, Interpolator.LINEAR))
    );
    timeline.setCycleCount(Animation.INDEFINITE);
    timeline.play();

    primaryStage.setScene(scene);
    primaryStage.sizeToScene();
    primaryStage.show();
}