在JavaFX中显示pdf

时间:2013-08-13 10:49:27

标签: java javafx

JavaFX中开发需要显示pdf的桌面应用程序。我读到JavaFX(当前版本)中不支持pdf查看/显示,我也读到了JPedal

现在,问题:

  1. 是否有任何外部组件或库可以在JavaFX中查看pdf?它应该是一个免费软件。
  2. (如果我必须使用JPedal)如何将其嵌入我的应用程序中。

9 个答案:

答案 0 :(得分:12)

JPedalFX示例代码和用法

使用JPedalFX的示例代码随JPedalFX download提供。

对我来说有点蹩脚,但我只是在这里粘贴从JPedalFX库提供的示例查看器中复制的代码片段示例代码。代码依赖于JPedalFX发行版中包含的jpedal_lgpl.jar文件,该文件位于类路径(或应用程序jar清单中引用的库路径)上。

如果您对JPedalFX的使用有任何疑问,我建议您contact IDR solutions directly(他们过去一直对我做出回应)。

// get file path.
FileChooser fc = new FileChooser();
fc.setTitle("Open PDF file...");
fc.getExtensionFilters().add(new FileChooser.ExtensionFilter("PDF Files", "*.pdf"));     
File f = fc.showOpenDialog(stage.getOwner());
String filename = file.getAbsolutePath();

// open file.
PdfDecoder pdf = new PdfDecoder();
pdf.openPdfFile(filename);
showPage(1);
pdf.closePdfFile();

. . . 

/**
 * Update the GUI to show a specified page.
 * @param page 
 */
private void showPage(int page) {

    //Check in range
    if (page > pdf.getPageCount())
        return;
    if (page < 1)
        return;

    //Store
    pageNumber = page;


    //Show/hide buttons as neccessary
    if (page == pdf.getPageCount())
        next.setVisible(false);
    else
        next.setVisible(true);

    if (page == 1)
        back.setVisible(false);
    else
        back.setVisible(true);


    //Calculate scale
    int pW = pdf.getPdfPageData().getCropBoxWidth(page);
    int pH = pdf.getPdfPageData().getCropBoxHeight(page);

    Dimension s = Toolkit.getDefaultToolkit().getScreenSize();

    s.width -= 100;
    s.height -= 100;

    double xScale = (double)s.width / pW;
    double yScale = (double)s.height / pH;
    double scale = xScale < yScale ? xScale : yScale;

    //Work out target size
    pW *= scale;
    pH *= scale;

    //Get image and set
    Image i = getPageAsImage(page,pW,pH);
    imageView.setImage(i);

    //Set size of components
    imageView.setFitWidth(pW);
    imageView.setFitHeight(pH);
    stage.setWidth(imageView.getFitWidth()+2);
    stage.setHeight(imageView.getFitHeight()+2);
    stage.centerOnScreen();
}

/**
 * Wrapper for usual method since JFX has no BufferedImage support.
 * @param page
 * @param width
 * @param height
 * @return 
 */
private Image getPageAsImage(int page, int width, int height) {

    BufferedImage img;
    try {
        img = pdf.getPageAsImage(page);

        //Use deprecated method since there's no real alternative 
        //(for JavaFX 2.2+ can use SwingFXUtils instead).
        if (Image.impl_isExternalFormatSupported(BufferedImage.class))
            return javafx.scene.image.Image.impl_fromExternalImage(img);

    } catch(Exception e) {
        e.printStackTrace();
    }

    return null;
}

/**
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.jpedal.org
 * (C) Copyright 1997-2008, IDRsolutions and Contributors.
 *
 *  This file is part of JPedal
 *
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


 *
 * ---------------
 * JPedalFX.java
 * ---------------
 */

SwingLabs PDF渲染器

另外,我过去使用旧的基于SwingLabs Swing的pdf渲染器和JavaFX来渲染我的JavaFX web browser的pdf。虽然Swing / JavaFX集成在我开发浏览器时并不是JavaFX的支持功能,但它仍然适用于我。集成代码位于PDFViewer.javaBrowserWindow.java

请注意,Java 2.2支持embedding JavaFX in a Swing app,Java 8支持embedding a Swing app in JavaFX

答案 1 :(得分:11)

我建议使用PDF JS javascript库。

创建一个WebView并静态加载此javascript pdf viewer example project的html / javascript内容。在javascript中创建一个函数,您可以向其发送要显示的pdf字节数组。

这样,pdf查看器的所有逻辑都已存在。您甚至可以修改查看器html以删除其中的某些功能。

还要注意 JPedalFX ,因为我发现它必须渲染添加到pdf文件中的图像时不可靠。在我的情况下,JPedalFX无法渲染使用jfreechart

生成的图表图像

答案 2 :(得分:9)

好的,这是我的50美分。除了@ALabrosik和@ReneEnriquez答案。

下载pdf.js dist并将其放在src/main/resources

├── pom.xml
├── src
│   └── main
│       ├── java
│       │   └── me
│       │       └── example
│       │           ├── JSLogListener.java
│       │           ├── Launcher.java
│       │           └── WebController.java
│       └── resources
│           ├── build
│           │   ├── pdf.js
│           │   └── pdf.worker.js
│           ├── main.fxml
│           ├── web
│           │   ├── cmaps
│           │   ├── compatibility.js
│           │   ├── debugger.js
│           │   ├── images
│           │   ├── l10n.js
│           │   ├── locale
│           │   ├── viewer.css
│           │   ├── viewer.html
│           │   └── viewer.js

创建以下fxml文件(您应该在 TabPane 或类似的容器中包装 WebView 以避免滚动支持的问题)

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.web.WebView?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="576.0" prefWidth="1024.0" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="me.example.WebController">
    <center>
      <TabPane>
         <tabs>
            <Tab text="PDF test">
               <content>
                    <WebView fx:id="web" minHeight="-1.0" minWidth="-1.0" />
               </content>
            </Tab>
         </tabs>
      </TabPane>
    </center>
   <bottom>
      <Button fx:id="btn" mnemonicParsing="false" text="Open another file" BorderPane.alignment="CENTER" />
   </bottom>
</BorderPane>

要阻止pdf.js在启动时打开演示pdf文件,请打开web/viewer.js并清除DEFAULT_URL值。

var DEFAULT_URL = '';

打开web/viewer.html并添加脚本块:

<head>

<!-- ... -->
<script src="viewer.js"></script>

<!-- CUSTOM BLOCK -->
<script>
    var openFileFromBase64 = function(data) {
        var arr = base64ToArrayBuffer(data);
        console.log(arr);
        PDFViewerApplication.open(arr);
    }

    function base64ToArrayBuffer(base64) {
      var binary_string = window.atob(base64);
      var len = binary_string.length;
      var bytes = new Uint8Array( len );
      for (var i = 0; i < len; i++)        {
          bytes[i] = binary_string.charCodeAt(i);
      }
      return bytes.buffer;
    }
</script>
<!-- end of CUSTOM BLOCK -->

</head>

现在是控制器(请参阅代码注释以获得解释)。

 public class WebController implements Initializable {

    @FXML
    private WebView web;

    @FXML
    private Button btn;

    public void initialize(URL location, ResourceBundle resources) {
        WebEngine engine = web.getEngine();
        String url = getClass().getResource("/web/viewer.html").toExternalForm();

        // connect CSS styles to customize pdf.js appearance
        engine.setUserStyleSheetLocation(getClass().getResource("/web.css").toExternalForm());

        engine.setJavaScriptEnabled(true);
        engine.load(url);

        engine.getLoadWorker()
                .stateProperty()
                .addListener((observable, oldValue, newValue) -> {
                    // to debug JS code by showing console.log() calls in IDE console
                    JSObject window = (JSObject) engine.executeScript("window");
                    window.setMember("java", new JSLogListener());
                    engine.executeScript("console.log = function(message){ java.log(message); };");

                    // this pdf file will be opened on application startup
                    if (newValue == Worker.State.SUCCEEDED) {
                        try {
                            // readFileToByteArray() comes from commons-io library
                            byte[] data = FileUtils.readFileToByteArray(new File("/path/to/file"));
                            String base64 = Base64.getEncoder().encodeToString(data);
                            // call JS function from Java code
                            engine.executeScript("openFileFromBase64('" + base64 + "')");
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });

        // this file will be opened on button click
        btn.setOnAction(actionEvent -> {
            try {
                byte[] data = FileUtils.readFileToByteArray(new File("/path/to/another/file"));
                String base64 = Base64.getEncoder().encodeToString(data);
                engine.executeScript("openFileFromBase64('" + base64 + "')");
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}

某些pdf.js函数不起作用:打开文件(因为pdf.js无法访问JAR之外的URL),打印等。要隐藏相应的工具栏按钮,可以将以下行添加到web.css:

#toolbarViewerRight {
    display:none;
}

这就是全部。其余的代码是微不足道的。

public class JSLogListener {

    public void log(String text) {
        System.out.println(text);
    }
}

public class Launcher extends Application {

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

    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("/main.fxml"));
        primaryStage.setTitle("PDF test app");
        primaryStage.setScene(new Scene(root, 1280, 576));
        primaryStage.show();
    }
}

希望这对某人有帮助。

答案 3 :(得分:2)

尝试JPedalFX在他们的网站上声明“JPedalFX是一个基于JavaFX 2的轻量级PDF查看器和JPedal的LGPL版本。它具有简单的界面,旨在快速方便地查看PDF文档。”< / p>

http://www.idrsolutions.com/jpedalfx-viewer/

尚未尝试但希望有所帮助

答案 4 :(得分:1)

您也可以尝试使用iText,我在java中使用它 A tutorial about how to use it

答案 5 :(得分:1)

对于某些人来说,将PDF文档转换为HTML并使用WebView显示它可能是一种解决方法。

开源命令行工具pdf2htmlEx生成非常漂亮的独立HTML文件,其中嵌入了图像和JavaScript。

答案 6 :(得分:0)

ICEPDF非常易于使用,免费且轻量级。我最近用它为我的公司制作了一个小的PDF索引应用程序;)

答案 7 :(得分:0)

我用Web视图和pdf.js写了一个非常简单的例子,这是GitHub上提供的源代码:

https://github.com/enriquezrene/curso-javafx-udemy/tree/master/clase-17/curso-javafx

享受它!!!

答案 8 :(得分:-1)

import android.support.v4.app.Fragment;
...
public class BottomPictureFragment extends Fragment { ... }