我想创建并嵌入技术绘图的.pngs(基于javascript和plotly)到powerpoint演示文稿中。我在过去使用过jfreechart和jafafx绘图(然后创建了.pngs),但现在我正在尝试用plotly替换这些绘图技术。下面的链接说,不可能直接将.html嵌入到ppt幻灯片中,这样就可以在没有第三方加载项(我不能使用)的情况下不单击它就可以查看它,这就是为什么我尝试将我的.html(使用javascript)打印文件改为.png打印文件的原因。https://superuser.com/questions/1221880/how-to-embed-an-html-file-into-a-powerpoint-presentation
我经常从java(下面的示例)创建100个ploty.html文件,保存到本地硬盘上。我的开发/执行环境是离线的,所以我需要一个可以从java调用的解决方案(即我可以下载和使用的本机或开源第三方.jar),这样我就可以将这些.html文件(使用plotly javascript)转换成.png。
swing-jeditorpane解决方案无法处理我的.html文件。
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class HTML2PNG_SWING {
public static void main(String[] args) {
URL htmlFile = null;
try {htmlFile = new File("D://myPlot.html").toURI().toURL();} catch (MalformedURLException e2) {e2.printStackTrace();}
File pngFile = new File("D://myPlot.png"); // png file I want to create
JEditorPane ed = null;
//load the webpage into the editor
try {ed = new JEditorPane(htmlFile);} catch (IOException e) {e.printStackTrace();}
try { // Likely there is some callback I can use instead which can tell me when the .html file is loaded
Thread.sleep(10000);} catch (InterruptedException e1) {e1.printStackTrace();
}
// I have to put some window size here... it would be nice if the size were auto-generated based on the .html plot
ed.setSize(1000,1000);
//create a new image
BufferedImage image = new BufferedImage(ed.getWidth(), ed.getHeight(),BufferedImage.TYPE_INT_ARGB);
//paint the editor onto the image
SwingUtilities.paintComponent(image.createGraphics(), ed, new JPanel(), 0, 0, image.getWidth(), image.getHeight());
//save the image to file
try {ImageIO.write((RenderedImage)image, "png", pngFile);} catch (IOException e) {e.printStackTrace();
}
}
}
说明:swing窗格可以处理简单的.html文件,而无需将html文件呈现到屏幕上。当我在下面的sample.html文件上尝试swing解决方案时,会显示两个文本div(参见下面的示例),但不会显示plotly div plot本身,因此jeditorpane可能遇到的问题是plotly.js javascript:https://www.tutorialspoint.com/swingexamples/using_jeditorpane_to_show_html.htm
javafx snapshot/webview/webengine解决方案不能用于my.html文件。
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import javax.imageio.ImageIO;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class HTML2PNG_JAVAFX2 extends Application {
public void start(Stage primaryStage) throws Exception {
URL htmlFile = null;
try {htmlFile = new File("D://myPlot.html").toURI().toURL();} catch (MalformedURLException e2) {e2.printStackTrace();}
File pngFile = new File("D://myPlot.png"); // png file I want to create
System.out.println("Before loading web page- "+new Date().toString());
WebView webView = new WebView();
webView.getEngine().load(htmlFile.toExternalForm()); // comment this out and uncomment out the next line to show that 'simple' pages can be rendered' successfully
// webView.getEngine().load( "http://www.stackoverflow.com/" );
WebEngine webEngine = webView.getEngine();
VBox vBox = new VBox();
vBox.getChildren().add(new Text("Hello World")); // used so I can see something if the webView has not loaded
vBox.getChildren().add(webView);
// I am only using this to show that the page is loaded (successfully or not) and when
webEngine.getLoadWorker().stateProperty().addListener(new BrowserStatusChangeListener(vBox));
Stage tempStage = new Stage();
// Please excuse this weird threading code and the .sleeps.
// I was trying to methodically separate the different activities into isolated code pockets to better understand what was going on
// Put this in a new Thread so it is off the JavaFX Thread
new Thread(() -> {
// Delay to allow the web page to load
try {
Thread.sleep(10000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// This goes back on the JavaFX Thread
Platform.runLater(() ->{
Scene scene = new Scene(vBox);
tempStage.setScene(scene);
vBox.layout();
vBox.requestLayout();
tempStage.show(); // if this line is commented out the html will not be captured
});
// Delay to allow the above scene/stage code to be executed (may not be needed)
try {
Thread.sleep(10000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// This also goes back on the JavaFX Thread but after a 2nd delay
Platform.runLater(() ->{
System.out.println("Writing... after the delay- "+new Date().toString());
WritableImage image = vBox.snapshot(new SnapshotParameters(), null);
try {
ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", pngFile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (pngFile.length() > 50000) {
System.out.println("Success, file size: "+pngFile.length()+"- "+new Date().toString());
}
else {
System.out.println("Failure, file size: "+pngFile.length()+"- "+new Date().toString());
}
});
})
.start();
}
//
class BrowserStatusChangeListener implements ChangeListener<Worker.State> {
VBox vBox;
public BrowserStatusChangeListener(VBox vBox) {
this.vBox = vBox;
}
@Override
public void changed(ObservableValue<? extends Worker.State> observable, Worker.State oldValue, Worker.State newValue) {
if (newValue.equals(Worker.State.SUCCEEDED)) {
System.out.println("Succeeded loading- "+new Date().toString());
}
else if(newValue.equals(Worker.State.FAILED)){
System.out.println("Failed loading- "+new Date().toString());
}
}
}
public static void main(String[] args) {
Application.launch(args);
}
}
说明:javafx snapshot/webview/webengine解决方案只有在webview可见时才有效(附加到javafx scene和stage以及'show()'ed)。如果 tempStage.show();
没有什么可以捕捉的。以下未回答的问题是针对javafx的,但在其他方面与我的相同。javafx-如何创建(不可见)webview的快照/屏幕快照。最后,我无法让Web引擎正确加载myplot.html。引擎报告它在加载myplot.html时成功了,但是java脚本似乎没有执行。这个链接意味着您可以强制javascript执行,但我没有尝试,因为 tempStage.show();
上述问题。http://tutorials.jenkov.com/javafx/webview.html#executing-java中的javascript
我认为一个swing、javafx或第三方html呈现引擎可以处理java脚本,并且可以返回rendered.html的图形图像而不显示在屏幕上,这就是我想要的。我不相信我的问题是ploty.js特定的。
我的理想解决方案如下:
// Sample ideal pseudo code (ignoring error handling code)
URL htmlFile = new File("D://myPlot.html").toURI().toURL(); // local .html file (that contains JavaScript)
File pngFile = new File("D://myPlot.png"); // png file I want to create
SomeWebEngine we = new SomeWebEngine(htmlFile); // loads the .html file (but does not display it to the screen)
we.whenLoaded(()->we.saveTo(pngFile)); // Spawns task which executes AFTER the html file is loaded, which saves the html to the png file
额外功能:渲染图像是包含html绘图所需的最小图像大小(参见下面的示例),您不必自己设置该大小。
基于plotly的“plot.html”文件示例(带有html'div' Package 器,用于在拐角处添加文本元素,我无法单独在plotly中执行这些元素):
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>My Plot</title>
<script src='D://plotly.js'></script>
<!-- <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> won't work becuase I am offline -->
</head>
<body>
<div style="position:relative;" id='plotDiv'>
<div id="topLeft">
<p style="position:absolute;top:0;left:0;"><Strong>Stuff plotly won't let me put inside the plot</Strong></p>
</div>
<div id="bottomRight">
<p style="position:absolute;bottom:0;right:0;"><Strong>More Stuff, different corner</Strong></p>
</div>
</div>
</body>
<script>
var trace0 = {
x: ["1.0", "2.0", "3.0", "4.0"],
y: ["1.0", "4.0", "2.0", "3.0"],
mode: 'lines+markers',
type: 'scatter',
name: 'My Data'
};
var data = [trace0];
Plotly.newPlot('plotDiv', data);
</script>
</html>
暂无答案!
目前还没有任何答案,快来回答吧!