On 31.05.13 23:35, Richard Bair wrote:
We should start simple and work our way up. Since we've spent most of our time
working on raw frame rates, perhaps it would be best to face down the jitter
problem first. Lets start with something simple: a basic translate transition
of a rectangle, and see how that goes.
Hi,
I'd like to add a very similar problem - a translate transition of a
simple image.
This is something you see very often in animation examples but although the
JavaFX problem associated with this has already been reported many years ago
(on monday it will be exactly 3 years) this has not been fixed until now.
(I just checked it with JDK8 b92) My original report
<https://javafx-jira.kenai.com/browse/RT-8799> was marked as a duplicate,
although I am still not sure it really is but I can't check this because
the explanation
of the possible reason in RT-6933 is kept secret.
Anyway - you still can't animate images smoothly with JavaFX out of the box
because although the image itself is placed at sub-pixel positions the
border
of the image is clipped to exact pixel boundaries which makes the
animation look bad.
I have attached code to show this. You can also switch between a smooth
and a
non-smooth animation by clicking into the image with the mouse. When you
click into the image I apply a little hack so the animation becomes
smooth. But
one should not be forced to use such tricks with a framework like JavaFX
in order
to get a smooth animation for such a trivial use case.
Here comes the code: (You can use the image from the original bug report)
<https://javafx-jira.kenai.com/secure/attachment/21378/image1.jpg>
package bugs.smoothness;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import javafx.animation.Animation;
import javafx.animation.Interpolator;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;
import javax.imageio.ImageIO;
public class ImageAnimation extends Application {
private static final String INPUT_IMAGE = "image1.jpg";
private static final double WIDTH = 1024;
private static final double HEIGHT = 768;
private static final Duration DURATION = Duration.millis(100000);
private Image image1;
private Image image2;
private ImageView imageView;
private TranslateTransition moveAnim;
private Stage currentStage;
public Image createImage(String relFilePath, boolean smooth) {
InputStream is = getClass().getResourceAsStream(relFilePath);
Image image = null;
if (smooth) {
try {
BufferedImage i1 = ImageIO.read(is);
BufferedImage i2 = new BufferedImage(i1.getWidth()+2,
i1.getHeight()+2, BufferedImage.TYPE_INT_ARGB);
i2.getGraphics().drawImage(i1, 1, 1, new
java.awt.Color(0, 0, 0, 0), null);
image = SwingFXUtils.toFXImage(i2, null);
} catch (IOException e1) {
e1.printStackTrace();
}
} else {
image = new Image(is);
}
if (image != null && !image.isError()) {
return image;
} else {
System.err.println("Could not open " + relFilePath);
return null;
}
}
public void adjustStageTitle() {
if (imageView.getImage() == image1) {
currentStage.setTitle("image1 - standard border");
} else {
currentStage.setTitle("image2 - one pixel transparent border");
}
}
@Override public void start(Stage stage) {
System.out.println("javafx.runtime.version: " +
System.getProperties().get("javafx.runtime.version"));
currentStage = stage;
image1 = createImage(INPUT_IMAGE, false);
image2 = createImage(INPUT_IMAGE, true);
imageView = new ImageView(image1);
imageView.setSmooth(true);
imageView.addEventHandler(MouseEvent.MOUSE_CLICKED, new
EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
Image currentImage = imageView.getImage();
if (currentImage == image1) {
imageView.setImage(image2);
} else {
imageView.setImage(image1);
}
adjustStageTitle();
}
});
Group root = new Group();
root.getChildren().add(imageView);
// create scene
Scene scene = new Scene(root, WIDTH, HEIGHT);
scene.setFill(Color.LIGHTGRAY);
stage.setScene(scene);
adjustStageTitle();
// show stage
stage.show();
// start animation
moveAnim = new TranslateTransition();
moveAnim.setNode(imageView);
moveAnim.setInterpolator(Interpolator.LINEAR);
moveAnim.setDuration(DURATION);
moveAnim.setCycleCount(Animation.INDEFINITE);
moveAnim.setAutoReverse(true);
moveAnim.setFromX(0f);
moveAnim.setFromY(0f);
moveAnim.setToX(WIDTH - imageView.getImage().getWidth());
moveAnim.setToY(HEIGHT - imageView.getImage().getHeight());
moveAnim.play();
}
public static void main(String[] args) {
Application.launch(args);
}
}