JavaFX ImageView display GIFanimation high GPU [closed] - java

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I am creating JavaFX application and made a loading scene. In this scene i want to show some text like loading or initializing and add some loading spinner animated image as a visual notification that something is loading.
I generate a loading .gif animation created via https://loading.io/ and also downloaded it like frames of animation (multiple .png files).
I noticed that in the JavaFX Scene Builder 8.5.0 when I set the .gif in ImageView, my GPU in Windows task manager went up to 20%, on NVidia GeForce RTX 2070 graphic card and in my opinion this is a problem. I tested with a javafx desktop application, to rule out that is not a problem generated by the scene builder application and got similar results.
The next step that i tried is to create my custom animation using javafx.​animation.Timeline. This is the initializing function that i call from the controller initialize(URL location, ResourceBundle resources) function. This function doesn't use the .gif image, it uses the multiple .png images of the same .gif image as frames.
private void initializeAnimation() {
imgLoading.setCache(true);
imgLoading.setCacheHint(CacheHint.SPEED);
Image[] images = new Image[31];
for(int i = 0; i <= 30; i++){
images[i] = new Image(getClass().getResourceAsStream("/es/main/gui/javafx/images/loading/frame-" + i + ".png"));
}
Timeline timeLine = new Timeline();
Collection<KeyFrame> frames = timeLine.getKeyFrames();
Duration frameGap = Duration.millis(100);
Duration frameTime = Duration.ZERO;
for (Image img : images) {
frameTime = frameTime.add(frameGap);
frames.add(new KeyFrame(frameTime, e -> imgLoading.setImage(img)));
}
timeLine.setCycleCount(Timeline.INDEFINITE);
timeLine.play();
}
In the first version i didn't call .setCache() and .setCacheHint() functions, I added them later while testing different variations of the same code. Also i tried adding
-Dprism.forceGPU=true -Dsun.java2d.opengl=true -Dprism.order=es2,es1,sw,j2d
as VMOption or some variants that I have read on this forum on improving graphic related settings for java. At the end, after all the changes, results in my task manager didn't change drastically. In the current version i use up to 17% of my GPU on this scene.
When the scene ends, in the next scene with no .gif images or Timeline's my GPU drops to almost 0%.
Running configurations:
Processor: i9-9900KF
Graphic card: GeForce RTX 2070
Java version "1.8.0_251"
JavaFX version "8.0.251-b08"
Short summary question: How to display animated .gif images correctly in JavaFX without having drastic overhead on the GPU (or CPU when with integrated graphics).
(Edit) 14.09.2020 - Java naming conventions
First thing I didn't noticed that i was not using the same size on my ImageView, so the first thing i changed for testing is adjusting the ImageView the same size as my .gif image (same width and height on both ImageView and .gif image). With this change the GPU percentage lowered to about %5.
As suggested I also upgrading the Java and JavaFX versions:
Tried using the jdk 1.8.0_261 with JavaFX built in version 8.0.261-b12 and got similar results.
Tried using jdk 14.0.2 with JavaFX version 15+9 (latest openjfx-15) and still got similar results.
Short summary: Upgrading the Java and JavaFX version didn't change anything relating this issue. Using the same size helped, but I think I can improve even better with your help.

My guess is you'd probably see some performance gains if you used one or more RotateTransition rather than key frame animation.
Here's a simple example using multiple transitions in a ParallelTransition:
import javafx.animation.RotateTransition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
#Override
public void start(Stage stage) {
Group root = new Group();
Scene scene = new Scene(root, 500, 200);
stage.setScene(scene);
Rectangle rect = new Rectangle (100, 40, 100, 100);
rect.setArcHeight(50);
rect.setArcWidth(50);
rect.setFill(Color.VIOLET);
RotateTransition rt = new RotateTransition(Duration.millis(3000));
rt.setByAngle(180);
rt.setAutoReverse(true);
FadeTransition ft = new FadeTransition(Duration.millis(3000));
ft.setFromValue(1.0);
ft.setToValue(0.3);
ft.setCycleCount(4);
ft.setAutoReverse(true);
ParallelTransition pt = new ParallelTransition(rect, ft, rt);
pt.play();
root.getChildren().add(rect);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Related

JavaFX MediaView rendering a white video

TL;DR : Solution : Increase the JavaFX version to 15.0.1.
I am re-writing the question I asked yesterday because it was poorly formulated and poorly explained.
What I do : I use JavaFX to create a Media and a MediaView to render a .mp4 video in a scene.
What happens : The screen stays blank.
What should happen : The video should be rendered properly and visible by the user.
What I've tried :
Changing the file encoding (from H.264 to QuickTime (outputs as .mov)).
Result : QuickTime encoding isn't recognized by JavaFX.
Changing the FPS value from 30 to 60 and from 60 to 30.
Result : no difference.
Tweaking the file size by shortening the video.
Result : no difference.
Changing the video resolution scale from 16:9 to 16:10.
Result : no difference.
Changing the video resolution value from 2560x1440 to 1920x1080.
Result : the video is shown on the screen, but I need a 2560x1440 video to fill the screen. I will take care of different resolutions later on by myself.
Using different videos from my computer.
Result : resolutions less or equal to 1920x1080 are working fine. I tried video a different video with a 2560x1440 resolution and it does not work.
Using a 2560x1440 video referenced by an internet URL.
Result : same behavior as described above.
My code :
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.Stage;
import java.io.File;
public class Application extends javafx.application.Application {
Stage window;
#Override
public void start(Stage primaryStage) {
window = primaryStage;
window.setWidth(2560);
window.setHeight(1440);
window.setX(0);
window.setY(0);
window.setResizable(false);
window.setFullScreen(true);
window.setFullScreenExitHint("");
Pane pane = new Pane();
// Example to show that adding a simple figure to the pane works fine.
javafx.scene.shape.Rectangle r = new javafx.scene.shape.Rectangle(0, 0, 150, 150);
Media media = new Media(new File(/*Insert file name you own for testing purposes*/).toURI().toString());
// The path I would use : "src\\main\\resources\\img\\Animated Titlescreen Background.mp4".
// This is obtained using other classes and methods that read the computer directories,
// so it works fine across different computers.
MediaPlayer mediaPlayer = new MediaPlayer(media);
mediaPlayer.setAutoPlay(true);
MediaView mediaView = new MediaView(mediaPlayer);
pane.getChildren().addAll(mediaView, r);
Scene scene = new Scene(pane, 2560, 1440);
window.setScene(scene);
window.show();
}
public static void main(String[] args) {
launch(args);
}
}
After reading more on this link, it says Windows 8 increase H.264 decoder resolution to 4096x2304, which is available on JavaFX version 15.0.1. I was using version 12.0.1 because of a critical issue on Linux with version 15.0.1.
Solution : Increase the JavaFX version to 15.0.1.

How to convert an image into a shape in Java?

I'm currently working on a stock market program that teaches students how to interact with the stock market. An issue that I'm working on right now revolves around the issue of efficiency and memory. I make all of my 2D icons (such as a settings icon, portfolio icons, etc) in adobe illustrator, I export those files as png files, and throw them into my program. I currently use JavaFX, and one of the features of JavaFX is what's called imageView, which is a method that handles the opening and viewing of images.
So let's say that the user would like to press on the Settings icon in the game, I would like to change the settings icon to a darker or lighter color when the user hovers over that icon in order to provide the user with a better user experience (UX) at the moment, I use two different images and remove one from the frame, and replace it with another, which is highly inefficient.
I know that JavaFX has a Shape class that inherits many methods such as Fill, or setFill, but these methods can only affect those of the Shape class.
My question is, "How can I convert an image that is imported into the project, into something that I can use methods such as setFill and Fill on"
If you're only aiming for basic changes such as darkening or lightning your icons, you can look at the Effects part of javaFx, you can read about it here, or else you can import your images as SVG as suggested in the comments
If you're planning to do it using Effects, you can achieve a darken-on-hover effect using the ColorAdjust Effect by setting the brightness value to something negative (the brightness in ColorAdjust ranges between -1 and +1 where 0 is the default) as in the following example
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage s) {
ImageView image = new ImageView(new Image("img.png"));
ColorAdjust darker = new ColorAdjust();
darker.setBrightness(-.3);
image.setOnMouseEntered(e-> {
image.setEffect(darker);
});
image.setOnMouseExited(e-> {
image.setEffect(null);
});
s.setScene(new Scene(new StackPane(image)));
s.show();
}
public static void main(String[] args) {
launch(args);
}
}
Changing the color of an image might involve adjusting the hue using ColorAdjust by setting the hue value
ColorAdjust hueShift = new ColorAdjust();
hueShift.setHue(-.3);
image.setOnMouseEntered(e-> {
image.setEffect(hueShift);
});
image.setOnMouseExited(e-> {
image.setEffect(null);
});
You can combine effects by setting effects as input to other effects, so for example, if you want to darken a Node and blur it at the same time you can set the blur effect as input to the darkening colorAdjust
GaussianBlur blur = new GaussianBlur();
blur.setRadius(10);
ColorAdjust darker = new ColorAdjust();
darker.setBrightness(-.3);
darker.setInput(blur);
image.setOnMouseEntered(e-> {
image.setEffect(darker);
});
image.setOnMouseExited(e-> {
image.setEffect(null);
});

Import STL file in JavaFX

My problem is that I am trying to import a 3D model from an STL file to a JavaFX application. I followed the code in this link How to create 3d shape from STL in JavaFX 8? and it's only working with the jewel file mentioned there, but I've tried with other STL files and it's not working!
I can't see why it's not working with the other files. Can anyone explain this?
Any help please, as soon as possible!
As you are already using an STL importer from this site, you will find in the same web a 3D model browser you can use to preview your models before importing them to your JavaFX application.
If they can't be imported with this browser, the problem may be related to a non valid STL format in your files.
If they are imported, then the problem may be in your application. Embed the call in a try-catch and post the exception you may enconter.
StlMeshImporter stlImporter = new StlMeshImporter();
try {
stlImporter.read(this.getClass().getResource("<STLfile>.stl"));
}
catch (ImportException e) {
e.printStackTrace();
return;
}
EDIT
If no exception is thrown while reading the model, the next step would be inserting the returned mesh into a MeshView and show it on our scene:
TriangleMesh mesh = stlImporter.getImport();
stlImporter.close();
MeshView mesh=new MeshView(cylinderHeadMesh);
Group root = new Group(mesh);
Scene scene = new Scene(root, 1024, 800, true);
Camera camera = new PerspectiveCamera();
scene.setCamera(camera);
primaryStage.setScene(scene);
primaryStage.show();
Since the model could be too small or too big for our scene (related to the camera and the point of view we are using), we should print the bounding box of our model, and then scale it up or down accordingly:
System.out.println("mesh: "+mesh.getBoundsInLocal().toString());
mesh.setScaleX(1d);
mesh.setScaleY(1d);
mesh.setScaleZ(1d);
Or we could change the camera parameters:
double max = Math.max(mesh.getBoundsInLocal().getWidth(),
Math.max(mesh.getBoundsInLocal().getHeight(),
mesh.getBoundsInLocal().getDepth()));
camera.setTranslateZ(-3*max);

Animated Splash Screen on Netbeans Platform app

Our maven/Netbeans platform application uses a custom image on startup, by replacing
Nbm-branding > core.jar > org.netbeans.core.startup > splash.gif
I tried making it an animated .gif, but only the first frame is displayed.
How would one possibly go about implementing an animated splash screen, maybe by running some JavaFX window animations?
I've seen another other SO question, but it wasn't really answered - please notice I'm asking about how to integrate a custom splash screen with my Netbeans Platform application, and not how to actually build it.
Surprisingly enough, I found out how to plug in a custom splash screen based on this post about user authentication and authorization.
Basically, one needs to write another start-up class, instead of the platform's default:
import java.lang.reflect.Method;
public class CustomStartup {
private static final String NB_MAIN_CLASS = "org.netbeans.core.startup.Main";
public static void main(String[] args) throws Exception {
// do whatever you need here (e.g. show a custom login form)
System.out.println("Hello world! I am a custom startup class");
JWindow splash = initSplash();
// once you're done with that, hand control back to NetBeans
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
Class<?> mainClass = Class.forName(NB_MAIN_CLASS, true, classloader);
Object mainObject = mainClass.newInstance();
Method mainMethod = mainClass.getDeclaredMethod("main", new Class[]{String[].class});
mainMethod.invoke(mainObject, (Object) args);
splash.setVisible(false);
}
}
In that class, one can create a JavaFX stage, embed it into a JWindow, and show it:
public JWindow initSplash(){
JWindow window = new JWindow();
final JFXPanel fxPanel = new JFXPanel();
window.add(fxPanel);
window.setVisible(true);
window.setLocationRelativeTo(null);
Platform.runLater(new Runnable() {
#Override
public void run() {
Scene scene = new Scene(new CustomFxSplash(), 475, 300, true);
fxPanel.setScene(scene);
}
}
return window;
}
Other things to remember are:
Suppress the original NetBeans splash screen by running your app with the --nosplash parameter.
Call your custom initialization class by running your app with the -J-Dnetbeans.mainclass=com.package.splash.CustomStartup parameter
As the link suggests this custom class has to be on the platform's initialization classpath, meaning inside the platform/core folder.
The current version of the NetBeans class that is responsible for rendering the splash screen can be viewed online here: org.netbeans.core.startup.
The culprit code that prevents the gif from animating is this line (line 546)
graphics.drawImage(image, 0, 0, null);
In order for the gif to animate the ImageObserver will have to be specified instead of being set to null and then repaint must be called when imageUpdate() is called on the ImageObserver.
An example of displaying an animated gif can be viewed here: Relationship Between Animated Gif and Image Observer
So as far as I can see you will either have to change the above NetBeans platform code and rebuild it for your application or you will have to create your own splash screen from scratch to use instead of the NetBeans one.
Hope you find this useful!

Libraries for pretty charts in SWT? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 4 years ago.
Improve this question
I know the following libraries for drawing charts in an SWT/Eclipse RCP application:
Eclipse BIRT Chart Engine (Links to an article on how to use it)
JFreeChart
Which other libraries are there for drawing pretty charts with SWT? Or charts in Java generally? After all, you can always display an image...
I have not used BIRT or JGraph, however I use JFreeChart in my SWT application. I have found the best way to use JFreeChart in SWT is by making a composite an AWT frame and using the AWT functionality for JFreeChart. The way to do this is by creating a composite
Composite comp = new Composite(parent, SWT.NONE | SWT.EMBEDDED);
Frame frame = SWT_AWT.new_Frame(comp);
JFreeChart chart = createChart();
ChartPanel chartPanel = new ChartPanel(chart);
frame.add(chartPanel);
There are several problems in regards to implementations across different platforms as well as the SWT code in it is very poor (in its defense Mr. Gilbert does not know SWT well and it is made for AWT). My two biggest problems are as AWT events bubble up through SWT there are some erroneous events fired and due to wrapping the AWT frame JFreeChart becomes substantially slower.
#zvikico
The idea of putting the chart into a web page is probably not a great way to go. There are a few problems first being how Eclipse handles integrating the web browser on different platforms is inconsistent. Also from my understanding of a few graphing packages for the web they are server side requiring that setup, also many companies including mine use proxy servers and sometimes this creates issues with the Eclipse web browsing.
SWTChart gives good results for line, scatter, bar, and area charts. The API is straight forward and there are numerous examples on the website. I went from finding it on google to viewing my data in less than an hour.
SWTChart
You might like this one too
It has the ability to plot real time data with your own data provider.
The one I've used are JChart2D and JFreeChart. I did a live plotter application over the summer and used JFreeChart for that. The guy who had started the project had used JChart2D but I found that it doesn't have enough options for tweaking the chart look and feel.
JChart2D is supposed to be very fast so if you need to do live plotting have a look at it, although JFreeChart didn't have any problems doing a plot a few times per second.
There also quite a list of charting libraries on java2s.com
I was also looking for a charting library for an Eclipse RCP app, stumbled on Caleb's post here and can definitely recommend SWTChart now myself. It is a lot faster than JFreeChart for me, plus easily extensible. If I would really have to complain about something, I'd say the javadoc could be a bit more verbose, but this is just to say everything else is great.
There’s also ILOG JViews Charts which looks pretty feature-complete… if you can afford it.
Here is some additional infos on using it with eclipse.
I suggest you try jzy3d, a simple java library for plotting 3d data. It's for java, on AWT, Swing or SWT.
After evaluationg several options I decided to use a JavaScript library for showing plots in my Eclipse Plugin. As zvikico already suggested it is possible to show a html page in a browser. In the html page you can utilize one of the JavaScript libraries to do the actual plotting. If you use Chartist you can save the image as SVG file from the context menu.
Some JavaScript charting libraries:
Chartist: http://gionkunz.github.io/chartist-js
D3js: http://d3js.org
Flot: http://www.flotcharts.org/
Further JavaScript charting frameworks: https://en.wikipedia.org/wiki/Comparison_of_JavaScript_charting_frameworks
Chartist Example image:
Example java code:
package org.treez.results.chartist;
import java.net.URL;
import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
public class WebViewSample extends Application {
private Scene scene;
#Override
public void start(Stage stage) {
// create the scene
stage.setTitle("Web View");
Browser browser = new Browser();
scene = new Scene(browser, 750, 500, Color.web("#666970"));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class Browser extends Region {
final WebView browser = new WebView();
final WebEngine webEngine = browser.getEngine();
public Browser() {
//add the web view to the scene
getChildren().add(browser);
//add finished listener
webEngine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
executeJavaScript();
}
});
// load the web page
URL url = WebViewSample.class.getResource("chartist.html");
String urlPath = url.toExternalForm();
webEngine.load(urlPath);
}
private void executeJavaScript() {
String script = "var chartist = new Chartist.Line(" + "'#chart'," + " " + "{"
+ " labels: [1, 2, 3, 4, 5, 6, 7, 8]," + "series: [" + " [5, 9, 7, 8, 5, 3, 5, 44]" + "]" + "}, " + ""
+ "{" + " low: 0," + " showArea: true" + "}" + "" + ");" + " var get = function(){return chartist};";
webEngine.executeScript(script);
Object resultJs = webEngine.executeScript("get()");
//get line
JSObject line = (JSObject) resultJs;
String getKeys = "{var keys = [];for (var key in this) {keys.push(key);} keys;}";
JSObject linekeys = (JSObject) line.eval(getKeys);
JSObject options = (JSObject) line.eval("this.options");
JSObject optionkeys = (JSObject) options.eval(getKeys);
options.eval("this.showLine=false");
}
#Override
protected void layoutChildren() {
double w = getWidth();
double h = getHeight();
layoutInArea(browser, 0, 0, w, h, 0, HPos.CENTER, VPos.CENTER);
}
#Override
protected double computePrefWidth(double height) {
return 750;
}
#Override
protected double computePrefHeight(double width) {
return 500;
}
}
Example html page:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="chartist.min.css">
</head>
<body>
<div class="ct-chart" id="chart"></div>
<script type="text/javascript" src="chartist.js"></script>
</body>
</html>
In order to get this working, chartist.js and chartist.min.css need to be downloaded and put at the same location as the html file. You could also include them from the web. See here for another example:
https://www.snip2code.com/Snippet/233633/Chartist-js-example
Edit
I created a java wrapper for D3.js, see
https://github.com/stefaneidelloth/javafx-d3
There's also JGraph, but I'm not sure if that's only for graphs (i.e. nodes and edges), or if it does charts also.
Here's something different: it's very to embed web pages in SWT views. I recently tried it and it works very well. You can see where this is going: there are plenty of beautiful charting components for HTML, it could be an option. Just make sure the component is client-side only (unless you want to start a server).
I haven't tested Flash, but I'm pretty sure you can get it to work (naturally, this means your software will require Flash plug-in installed).
JCharts is another option. It is similar to JFreeChart but the documentation is free. It does not have direct support for SWT but you can always generate an image and embed it in an SWT frame.

Categories

Resources