脱机(无internet)将本地.html文件(使用javascript)从java转换为.png文件,而不将其呈现到屏幕

pgvzfuti  于 2021-07-03  发布在  Java
关注(0)|答案(0)|浏览(225)

我想创建并嵌入技术绘图的.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>

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题