整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

JAVA实现在线查看PDF和office文档,一个很

JAVA实现在线查看PDF和office文档,一个很多人都踩坑的问题

天我来说说这个不怎么被人提起,却又是很多人没搞定的问题!

一个项目中要做一个在线预览附件(和百度文库差不多)的小功能点,我在开发过程中踩了很多坑的同时也总结了一些方法,仅供广大猿友参考,那么要实现这个小功能,目前主要是有如下3种可行的实现方式,下面先说实现的思路设计与他们的优缺点:

第一种思路:先把附件office文档(doc,docx,ppt,pptx,xls,xlsx,txt)转为PDF格式,这里需要用一个OpenOffic这玩意来转换,有服务和端口的属性,所以它是一个服务类软件(像tomcat这类,区别是所提供的服务各不相同),然后把PDF转为SWF文件类型,最后在前台页面使用Flexpaper插件进行播放即可实现。

第一种方式的好处在于:可以兼容IE低版本的浏览器。

第一种方式的!好在于:

首先是把一个附件进行了2次的转换,这里的转换是指另外保存了.pdf和.swf这两种格式的文件,这无疑的加大了存储空间的使用。

其次是.swf格式的文件需要放到项目的WebRoot文件夹的下层才能被Flexpaper插件所读取,当然了你也可以使用Nginx做一个地址映射,把.swf文件放到别的地方也能被Flexpaper所读取。

最后这种方式最大的缺点是Flexpaper插件主要是依赖于一个文件FlexPaperViewer.swf,而这个文件是无法编辑的,如果要编辑,则要找到Flexpaper的源码,然后修改源码,在重新构建生成FlexPaperViewer.swf,来着这里,大家肯定会问,为什么要编辑这个文件,那是因为这个文件是控制Flexpaper插件的各种按钮的,比如打印按钮的显示和隐藏,更重要的是Flexpaper插件是有它自带的LOGO水印,不去掉会显得很难看且尴尬,而编辑这个文件可以解决这些问题,另外如果你的功能中要对附件加自定义的水印的话,就不要采取这种方式了,因为是不可能实现的,原因很简单,因为PDF转SWF中这一步是很坑的,即使你的PDF中已经添加了水印,但是转换后得到的SWF是无水印的,不知道为什么会帮你自动去掉,所以前台读取的是.swf就自然就显示不出来水印了。

谷歌浏览器需要安装flash插件才能正常显示。

第二种思路:第一步还是和第一种一样的,都是先把附件为office文档转换为PDF格式,但是不同于第一种的是得到PDF之后呢,是使用pdf2htmlex插件把PDF直接转化为HTML文本输出到页面来。

第一种方式的好处在于:就是不用生成.swf文件,节省空间,提升效率。

第一种方式的!好在于:

首先只能达到附件预览的效果,如果你要实现打印,文本搜索等功能是是要自己另外写代码的。

其次,如果你的PDF中加了水印的话,输出的HTML也是没有水印的。

第三种思路:最靠谱的一种方式,第一步和前两种方法是一样的,都是先把附件Office文档转换了PDF格式,然后不同的是,得到PDF之后,使用PDF.JS这个框架来显示附件,但是这个框架是基于HTML5的新特性才能实现的,IE的话需要9以上版本才能兼容,这是最大的缺点了,优点太多了,即可看到水印,而且打印等这些功能点都已经实现好了,并且可以改变一些参数就可以实现这些按钮的权限的控制,良心之作。

写完思路之后当然要写具体要怎么写代码,先说第一种:

这是JAVA后台代码结构

  • 一个是测试类,是用来测试offiec文档转换换为PDF和SWF的
  • 一个工具类,是用来实现转换的代码
  • 一个配置文件是是配置你的OpenOffic服务的端口和地址

这是Web前台代码结构

主要是一些CSS和JS的控件和样式,前台的页面主要是这个FlexPaperViewer.html 或者index.html把页面嵌进一个DIV层就能自定义展示,要显示的文档要转换为SWF格式放到WEBROOT下层任意路径,比如我的docs文件夹里的Paper.pdf.swf文件

效果如下

项目Demo代码百度云地址:这个项目的打印功能和水印是被我去掉的,具体的怎么去掉自己去百度吧很多教程很麻烦这里就不演示

需要我总结的网盘链接的可以转发+私信【源码】获取!

保留了打印功能的是这个地址:里面有个FlexPaperViewer.swf的配置文件把它替换了原来的就行了

需要我总结的网盘链接的可以私信【源码】获取!

然后说第二种:

通过调用工具类里边的一个方法,把一个PDF文件内容变为静态的HTML,然后浏览器直接显示HTML就可以实现预览效果了。

效果如下

Demo链接:需要我总结的网盘链接的可以转发+私信【源码】获取!

最后说第三种:

首先呢要在TOMCAT服务器搭建一个PDF.JS框架,说白了就是在webapp文件夹放入一个已经搭建好的小项目,如图

然后如何调用呢?在你的项目中DIV的SRC或者弹框中用

src=http://localhost:8080/generic/web/viewer.html?file=http://localhost:8080/resources/PDF文件名 其中resources是个文件夹这个是自己建的就可以了,?后边PDF文件的路径

效果如下

百度云:需要链接的可以转发+私信【源码】获取! 这个是PDF.JS框架代码

最后附上PDF加水印的代码,也用到一些第三方jar包,直接调用,比较简单。

链接:需要我总结的网盘链接的可以转发+私信【源码】获取!

最后补充说明一下:

关于把offer文档转换为PDF的时候首先在本机安装OpenOffice,然后就开启服务,在安装目录下的program文件夹(里边是存命令的),进入后 通过cmd控制台输入以下命令:

soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard

注本头条号,专注做前端

今天要分享的是基于html5,通过强大的JS实现的在线pdf阅读器,大部分浏览器支持pdf阅读,但是有的浏览器不支持,可以通过pdf.js来解决

//

DFium[1] 是 Chromium 的 PDF 渲染引擎,许可协议为 BSD 3-Clause。不同于 Mozilla 基于 HTML5 的 PDF.js[2],PDFium 是基于 Foxit Software (福昕软件)的渲染代码,Google 与其合作开源出的。

此外,Qt PDF 模块也选用了 PDFium ,可见 QtWebEngine / QtPdf[3]

本文将介绍如何用 PDFium 实现一个简单的 PDF 阅读器,代码见:https://github.com/ikuokuo/pdfium-reader 。

编译 PDFium

使用预编译库:https://github.com/bblanchon/pdfium-binaries

不然,参考 PDFium / README[4] 自己编译,实践步骤如下:

# get depot_tools, contains: gclient, ninja, gn, ...
git clone --depth 1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH="$PATH:$HOME/Codes/Star/depot_tools"

# get pdfium
cd pdfium-reader/
mkdir -p third_party/chromium
cd third_party/chromium
gclient config --unmanaged https://pdfium.googlesource.com/pdfium.git
gclient sync
cd pdfium

# get deps
#  on linux, install additional build dependencies
./build/install-build-deps.sh

# gn config
#  args see the following `out/Release/args.gn`
gn args out/Release

# ninja build
#  pdfium
ninja -C out/Release pdfium
#  pdfium_test
ninja -C out/Release pdfium_test

# run sample: pdf > ppm
./out/Release/pdfium_test --ppm path/to/myfile.pdf

期间 out/Release/args.gn 内容如下:

use_goma=false  # Googlers only. Make sure goma is installed and running first.
is_debug=false  # Enable debugging features.

# Set true to enable experimental Skia backend.
pdf_use_skia=false
# Set true to enable experimental Skia backend (paths only).
pdf_use_skia_paths=false

pdf_enable_xfa=false  # Set false to remove XFA support (implies JS support).
pdf_enable_v8=false  # Set false to remove Javascript support.
pdf_is_standalone=true  # Set for a non-embedded build.
pdf_is_complete_lib=true  # Set for a static library build.
is_component_build=false  # Disable component build (Though it should work)

使用 PDFium

阅读 PDFium / Getting Started[5],了解如何初始化 PDFium 及载入文档。步骤如下,或见 pdfium_start.c[6]:

#include <fpdfview.h>
#include <stdio.h>

int main(int argc, char const *argv[]) {
  FPDF_STRING test_doc="test_doc.pdf";
  if (argc >=2) {
    test_doc=argv[1];
  }
  printf("test_doc: %s\n", test_doc);

  FPDF_InitLibrary();

  FPDF_DOCUMENT doc=FPDF_LoadDocument(test_doc, NULL);
  if (!doc) {
    unsigned long err=FPDF_GetLastError();
    // Load pdf docs unsuccessful: ...
    goto EXIT;
  }

  FPDF_CloseDocument(doc);
EXIT:
  FPDF_DestroyLibrary();
  return 0;
}

获取信息

样例见 pdf_info.cc[7],可打印 PDF 元数据、页面信息等。

FPDF_GetMetaText 获取元数据(UTF-16LE 编码):

void PrintPdfMetaData(FPDF_DOCUMENT doc) {
  static constexpr const char *kMetaTags[]={
      "Title",   "Author",   "Subject",      "Keywords",
      "Creator", "Producer", "CreationDate", "ModDate"};
  for (const char *meta_tag : kMetaTags) {
    const unsigned long len=FPDF_GetMetaText(doc, meta_tag, nullptr, 0);
    if (!len)
      continue;

    std::vector<char16_t> buf(len);
    FPDF_GetMetaText(doc, meta_tag, buf.data(), buf.size());
    auto text=strings::FromUtf16(std::u16string(buf.data()));
    if (strcmp(meta_tag, "CreationDate")==0 ||
        strcmp(meta_tag, "ModDate")==0) {
      text=fpdf::DateToRFC3399(text);
    }
    std::cout << " " << meta_tag << ": " << text << std::endl;
  }
}

渲染页面

样例见 pdf_render.cc[8],可渲染 PDF 页面并保存为 PNG。

FPDF_RenderPageBitmap 渲染某一页:

void PdfRenderPage(const std::string &pdf_name, FPDF_DOCUMENT doc, int index) {
  Timer t;

  FPDF_PAGE page=FPDF_LoadPage(doc, index);

  double scale=1.0;
  // double scale=2.0;
  int width=static_cast<int>(FPDF_GetPageWidth(page) * scale);
  int height=static_cast<int>(FPDF_GetPageHeight(page) * scale);
  int alpha=FPDFPage_HasTransparency(page) ? 1 : 0;
  ScopedFPDFBitmap bitmap(FPDFBitmap_Create(width, height, alpha));  // BGRx

  if (bitmap) {
    FPDF_DWORD fill_color=alpha ? 0x00000000 : 0xFFFFFFFF;
    FPDFBitmap_FillRect(bitmap.get(), 0, 0, width, height, fill_color);

    int rotation=0;
    int flags=FPDF_ANNOT;
    FPDF_RenderPageBitmap(bitmap.get(), page, 0, 0, width, height,
        rotation, flags);
    auto t_render=t.Elapsed();

    int stride=FPDFBitmap_GetStride(bitmap.get());
    void *buffer=FPDFBitmap_GetBuffer(bitmap.get());

    char img_name[256];
    int chars_formatted=snprintf(
        img_name, sizeof(img_name), "%s.%d.png", pdf_name.c_str(), index);
    if (chars_formatted < 0 ||
        static_cast<size_t>(chars_formatted) >=sizeof(img_name)) {
      fprintf(stderr, "Filename is too long: %s\n", img_name);
      exit(EXIT_FAILURE);
    }

    auto ok=PdfWritePng(img_name, buffer, width, height, stride);
    if (!ok) {
      fprintf(stderr, "Write png failed: %s\n", img_name);
      exit(EXIT_FAILURE);
    }
    auto t_write=t.Elapsed();

    fprintf(stdout, "%s\n", img_name);
    fprintf(stdout, " %02d: %dx%d, render=%lldms, write=%lldms\n",
        index, width, height, t_render, t_write);
  } else {
    fprintf(stderr, "Page was too large to be rendered.\n");
    exit(EXIT_FAILURE);
  }

  FPDF_ClosePage(page);
}

stb_image_write.h[9] 存为 PNG:

bool PdfWritePng(const std::string &img_name, void *buffer,
                 int width, int height, int stride) {
  // BGRA > RGBA
  auto buf=reinterpret_cast<uint8_t *>(buffer);
  for (int r=0; r < height; ++r) {
    for (int c=0; c < width; ++c) {
      auto pixel=buf + (r*stride) + (c*4);
      auto b=pixel[0];
      pixel[0]=pixel[2];  // b=r
      pixel[2]=b;         // r=b
    }
  }
  return stbi_write_png(img_name.c_str(), width, height, 4, buf, stride) !=0;
}

实现 UI

本文给出的 PDFium Reader[10] 代码,用的 ImGui[11]+GLFW[12]+OpenGL3[13] 实现的 UI,可跨三大桌面系统。

想进一步了解的,可以直接看代码,编译运行依照 README。

脚注

[1] PDFium: https://pdfium.googlesource.com/pdfium/

[2] PDF.js: https://github.com/mozilla/pdf.js

[3] QtWebEngine / QtPdf: https://code.qt.io/cgit/qt/qtwebengine.git/tree/src

[4] PDFium / README: https://pdfium.googlesource.com/pdfium/

[5] PDFium / Getting Started: https://pdfium.googlesource.com/pdfium/+/refs/heads/main/docs/getting-started.md

[6] pdfium_start.c: https://github.com/ikuokuo/pdfium-reader/blob/main/samples/pdfium_start.c

[7] pdf_info.cc: https://github.com/ikuokuo/pdfium-reader/blob/main/samples/pdf/pdf_info.cc

[8] pdf_render.cc: https://github.com/ikuokuo/pdfium-reader/blob/main/samples/pdf/pdf_render.cc

[9] stb_image_write.h: https://github.com/nothings/stb/blob/master/stb_image_write.h

[10] PDFium Reader: https://github.com/ikuokuo/pdfium-reader

[11] ImGui: https://github.com/ocornut/imgui

[12] GLFW: https://github.com/glfw/glfw

[13] OpenGL3: https://www.opengl.org/