整页截图,Java

时间:2015-09-02 09:12:31

标签: webview javafx fullscreen snapshot webpage-screenshot

这是我的问题 - 我有一个用JavaFX编写的桌面应用程序。我需要向用户显示全屏网页,并将呈现的页面保存为PNG。我需要保存整页(例如分辨率1920×3500)。

现在我正在使用Selenium和Firefox来做到这一点。它工作正常,但有一个很大的缺点 - 用户必须在他的机器上安装Firefox。

我尝试使用JavaFX使用WebView呈现网页并使用.snapshot()。这将是伟大的,但这种方法不会给我整个页面,只有WebView的可见部分。有没有办法如何使用WebView获取整个页面快照?或任何其他想法如何做到这一点?感谢。

2 个答案:

答案 0 :(得分:0)

您可能需要查看this post。我不知道它是否有效,但它似乎是一个合理的解决方案。

答案 1 :(得分:0)

经过大量搜索和拼凑后,我发现我在oracle论坛上张贴的一些SO-post示例的唯一问题是固定的Webview大小和我的 css 中。

overflow-x: hidden;
overflow-y: hidden;

隐藏最后一个滚动条。

因此,我想出了以下快照方法(带有动画的应用程序仅作为您的应用程序示例),看看它是否适合您的尺寸,否则您可以将javafx.scene.web.WebView.setZoom(double value)的Webview缩小到可以使用的大小,失去一些分辨率,但至少具有整体效果:

package application;

import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import javafx.animation.Animation;
import javafx.animation.PauseTransition;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.web.WebView;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;

public class WebViewSnapshot extends Application {

    BorderPane rootPane;
    TranslateTransition animation;

    @Override
    public void start(Stage primaryStage) {

        Rectangle rect = new Rectangle(50, 50, 50, 50);
        rect.setFill(Color.CORAL);

        animation = createAnimation(rect);

        Button snapshotButton = new Button("Take snapshot");

        Pane pane = new Pane(rect);
        pane.setMinSize(600, 150);

        rootPane = new BorderPane(pane, null, null, snapshotButton, new Label("This is the main scene"));

        snapshotButton.setOnAction(e -> {
            // html file being shown in webview
            File htmlFile = new File ("generated/template.html");
            // the resulting snapshot png file
            File aboutFile = new File ("generated/about.png");
            generate(htmlFile, aboutFile, 1280, 720);
        });

        BorderPane.setAlignment(snapshotButton, Pos.CENTER);
        BorderPane.setMargin(snapshotButton, new Insets(5));
        Scene scene = new Scene(rootPane);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private TranslateTransition createAnimation(Rectangle rect) {
        TranslateTransition animation = new TranslateTransition(Duration.seconds(1), rect);
        animation.setByX(400);
        animation.setCycleCount(Animation.INDEFINITE);
        animation.setAutoReverse(true);
        animation.play();
        return animation;
    }

    public void generate(File htmlFile, File outputFile, double width, double height) {
        animation.pause();
        // rootPane is the root of original scene in an FXML controller you get this when you assign it an id
        rootPane.setEffect(new GaussianBlur());
        Stage primaryStage = (Stage)rootPane.getScene().getWindow();
        // creating separate webview holding same html content as in original scene
        WebView webView = new WebView();
        // with the size I want the snapshot
        webView.setPrefSize(width, height);
        AnchorPane snapshotRoot = new AnchorPane(webView);
        webView.getEngine().load(htmlFile.toURI().toString());
        Stage popupStage = new Stage(StageStyle.TRANSPARENT);
        popupStage.initOwner(primaryStage);
        popupStage.initModality(Modality.APPLICATION_MODAL);
        // this popup doesn't really show anything size = 1x1, it just holds the snapshot-webview
        popupStage.setScene(new Scene(snapshotRoot, 1, 1));
        // pausing to make sure the webview/picture is completely rendered
        PauseTransition pt = new PauseTransition(Duration.seconds(2));
        pt.setOnFinished(new EventHandler<ActionEvent>() {
            @Override public void handle(ActionEvent event) {
                WritableImage image = webView.snapshot(null, null);
                // writing a png to outputFile
                // writing a JPG like this will result in a pink JPG, see other posts
                // if somebody can scrape me simple code to convert it ARGB to RGB or something
                String format = "png";
                try {
                    ImageIO.write(SwingFXUtils.fromFXImage(image, null), format, outputFile);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {
                    rootPane.setEffect(null);
                    popupStage.hide();
                    animation.play();
                }
            }
        });
        // pausing, after pause onFinished event will take + write snapshot
        pt.play();
        // GO!
        popupStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}