鉴于BufferedImage
中的真彩色全帧列表和帧持续时间列表,我如何无损地创建图像,当放在JLabel上时,会动画?
从find开始,我可以创建ImageWriter
包裹ByteArrayOutputStream
,向其中写IIOImage
帧,然后Toolkit.getDefaultToolkit().createImage
将流转换为ToolkitImage
。
此尝试存在两个问题。
[编辑]
一些更简洁的约束和要求。请不要提出任何使这些规则发生变化的事情。
我不想要的东西:
sun.*
包我做想要的事情:
Image
子类。我应该能够像g.drawImage(ani, 0, 0, this)
那样绘制图像,它会动画,或者将它包装在ImageIcon
中并将其显示在JLabel / JButton / etc上,它会动画,可选:
Image
并在那里添加一个与ImageObserver
合作的动画线程,或者写我自己的InputStreamImageSource
,但我不知道不知道怎么做。答案 0 :(得分:1)
你是对的,ImageIO不是一个选项,因为保证支持的唯一动画格式是GIF。
你说你不想制作动画线程,但是像Timeline那样的JavaFX动画对象呢?
public JComponent createAnimationComponent(List<BufferedImage> images,
List<Long> durations) {
Objects.requireNonNull(images, "Image list cannot be null");
Objects.requireNonNull(durations, "Duration list cannot be null");
if (new ArrayList<Object>(images).contains(null)) {
throw new IllegalArgumentException("Null image not permitted");
}
if (new ArrayList<Object>(durations).contains(null)) {
throw new IllegalArgumentException("Null duration not permitted");
}
int count = images.size();
if (count != durations.size()) {
throw new IllegalArgumentException(
"Lists must have the same number of elements");
}
ImageView view = new ImageView();
ObjectProperty<Image> imageProperty = view.imageProperty();
Rectangle imageSize = new Rectangle();
KeyFrame[] frames = new KeyFrame[count];
long time = 0;
for (int i = 0; i < count; i++) {
Duration duration = Duration.millis(time);
time += durations.get(i);
BufferedImage bufImg = images.get(i);
imageSize.add(bufImg.getWidth(), bufImg.getHeight());
Image image = SwingFXUtils.toFXImage(bufImg, null);
KeyValue imageValue = new KeyValue(imageProperty, image,
Interpolator.DISCRETE);
frames[i] = new KeyFrame(duration, imageValue);
}
Timeline timeline = new Timeline(frames);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
JFXPanel panel = new JFXPanel();
panel.setScene(new Scene(new Group(view)));
panel.setPreferredSize(imageSize.getSize());
return panel;
}
(我不知道为什么必须明确设置JFXPanel的首选大小,但确实如此。可能是一个错误。)
请注意,与所有JavaFX代码一样,它必须在JavaFX Application Thread中运行。如果您从Swing应用程序中使用它,您可以执行以下操作:
public JComponent createAnimationComponentFromAWTThread(
final List<BufferedImage> images,
final List<Long> durations)
throws InterruptedException {
final JComponent[] componentHolder = { null };
Platform.runLater(new Runnable() {
@Override
public void run() {
synchronized (componentHolder) {
componentHolder[0] =
createAnimationComponent(images, durations);
componentHolder.notifyAll();
}
}
});
synchronized (componentHolder) {
while (componentHolder[0] == null) {
componentHolder.wait();
}
return componentHolder[0];
}
}
但这还不够。首先必须通过使用显式方法调用调用Application.launch来初始化JavaFX,或者通过将Application子类指定为主类来隐式地初始化JavaFX。
答案 1 :(得分:0)
类似
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(getImageForCurrentTime(), 3, 4, this);
}