我有一张图片,我想反转它。我写了算法,它工作正常。 但是我想逐渐显示反转(显示第1列的像素,然后显示第2列的像素等),因为它更好!
所以我使用Service
和Task
类来使包含此算法的类(GraphicEngine
)成为一个线程。后者将由另一个类(Gui
)启动,这是GUI。在JavaFX中这样做是很常见的。
问题在于反转的显示卡在图像的开头或中间......它是随机的。我不知道为什么。
以下是源代码:
启动器类:
import javafx.application.Application;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Launcher extends Application {
public static void main(String args[]) {
launch(args);
}
public void start(Stage stage) {
stage.setWidth(700);
stage.setHeight(700);
stage.setMaximized(true);
Gui gui = new Gui(stage, new BorderPane(), 700, 500);
gui.fill();
stage.setScene(gui);
stage.show();
}
}
在Gui.java中(扩展场景):
this.button_reverse_image.setOnAction(button -> {
this.graphic_engine.restart();
});
在GraphicEngine.java中:
public class GraphicEngine extends Service<Void> {
private WritableImage writable_image;
private PixelReader writable_pixel_reader;
private PixelWriter writable_pixel_writer;
public Task<Void> createTask() {
return new Task<Void>() {
protected Void call() {
double r, g, b;
for(int x = 0; x < writable_image.getWidth(); x++) {
for(int y = 0; y < writable_image.getHeight(); y++) {
r = writable_pixel_reader.getColor(x, y).getRed()*255;
g = writable_pixel_reader.getColor(x, y).getGreen()*255;
b = writable_pixel_reader.getColor(x, y).getBlue()*255;
writable_pixel_writer.setColor(x, y, Color.rgb((int) (255 - r), (int) (255 - g), (int) (255 - b)));
}
}
return null;
}
};
}
答案 0 :(得分:1)
您无法从后台线程修改UI。相反,你应该使用动画(因为动画新图像实际上就是你正在做的事情)。
E.g。
private void progressivelyWriteImage(PixelReader source, WritableImage target) {
Duration animationDuration = Duration.seconds(1);
int width = target.getWidth();
int height = target.getHeight();
PixelWriter pixelWriter = target.getPixelWriter();
IntegerProperty columnProgression = new SimpleIntegerProperty(0);
columnProgression.addListener((obs, oldX, newX) -> {
int progWidth = newX.intValue() - oldX.intValue();
int[] pixels = new int[progWidth*height];
source.getPixels(oldX.intValue(), 0, progWidth, height,
PixelFormat.getIntArgbInstance(),
pixels, 0, progWidth);
int[] newPixels = new int[pixels.length];
for (int i = 0; i < pixels.length ; i++) {
int a = pixels[i] & 0xFF000000 ;
int rgb = 0xFFFFFF - (pixels[i] & 0xFFFFFF) ;
newPixels[i] = a | rgb ;
}
pixelWriter.setPixels(oldX.intValue(), 0, progWidth, height,
PixelFormat.getIntArgbInstance(),
newPixels, 0, progWidth);
});
Timeline timeline = new Timeline(new KeyFrame(animationDuration,
new KeyValue(columnProgression, width)));
timeline.play();
}
这是一个SSCCE:
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.PixelWriter;
import javafx.util.Duration;
public class GraphicEngine() {
public negateImage(PixelReader source, WritableImage target) {
Duration animationDuration = Duration.seconds(1);
int width = (int) target.getWidth();
int height = (int) target.getHeight();
PixelWriter pixelWriter = target.getPixelWriter();
IntegerProperty columnProgression = new SimpleIntegerProperty(0);
columnProgression.addListener((obs, oldX, newX) -> {
int progWidth = newX.intValue() - oldX.intValue();
int[] pixels = new int[progWidth*height];
source.getPixels(oldX.intValue(), 0, progWidth, height,
PixelFormat.getIntArgbInstance(),
pixels, 0, progWidth);
int[] newPixels = new int[pixels.length];
for (int i = 0; i < pixels.length ; i++) {
int a = pixels[i] & 0xFF000000 ;
int rgb = 0xFFFFFF - (pixels[i] & 0xFFFFFF) ;
newPixels[i] = a | rgb ;
}
pixelWriter.setPixels(oldX.intValue(), 0, progWidth, height,
PixelFormat.getIntArgbInstance(),
newPixels, 0, progWidth);
});
Timeline timeline = new Timeline(new KeyFrame(animationDuration,
new KeyValue(columnProgression, width)));
timeline.play();
}
}
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ImageModifyDemo extends Application {
@Override
public void start(Stage primaryStage) {
GraphicEngine engine = new GraphicEngine();
Image initialImage = createImage();
int width = (int) initialImage.getWidth();
int height = (int) initialImage.getHeight();
WritableImage target = new WritableImage(width, height);
Button demoChange = new Button("Run demo");
demoChange.setOnAction(e -> {
target.getPixelWriter().setPixels(0, 0, width, height, PixelFormat.getIntArgbInstance(), new int[width], 0, 0);
engine.negateImage(initialImage.getPixelReader(), target);
});
VBox root = new VBox(10, new ImageView(initialImage), new ImageView(target), demoChange);
root.setPadding(new Insets(10));
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
private Image createImage() {
Label label = new Label("Hello world");
label.setStyle("-fx-background-color: -fx-background; -fx-background: salmon; -fx-font-size:72;");
new Scene(label);
return label.snapshot(null, null);
}
public static void main(String[] args) {
launch(args);
}
}