全网最全的docx、pptx、xlsx、pdf文件预览方案(典藏版)

Vue实现文档在线预览功能,上传预览PDF、Word等office文件 阅读详情

👉 这是一个或许对你有用的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料: 

c90802d15eedd8faa19892b905bf319f.gif

👉这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号等等功能:

  • Boot 地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro

  • Cloud 地址:https://gitee.com/zhijiantianya/yudao-cloud

  • 视频教程:https://doc.iocoder.cn

来源:juejin.cn/post/
7268530145208451124

14f216b1b97e6c9cbf1dd95043bf92cc.jpeg


最近遇到了文件预览的需求,但一搜索发现,这还不是一个简单的功能。于是又去查询了很多资料,调研了一些方案,也踩了好多坑。最后总结方案如下

花钱解决(使用市面上现有的文件预览服务)

  1. 微软

  2. google

  3. 阿里云 IMM

  4. XDOC

  5. Office Web 365

  6. wps开放平台

前端方案

  1. pptx的预览方案

  2. pdf的预览方案

  3. docx的预览方案

  4. xlsx(excel)的预览方案

  5. 前端预览方案总结

服务端方案

  1. openOffice

  2. kkFileView

  3. onlyOffice

如果有其他人也遇到了同样的问题,有了这篇文章,希望能更方便的解决。

基本涵盖了所有解决方案。因此,标题写上 最全 的文件预览方案调研总结,应该不为过吧。

1 市面上现有的文件预览服务

1.微软

docx,pptx,xlsx可以说是office三件套,那自然得看一下 微软官方 提供的文件预览服务。使用方法特别简单,只需要将文件链接,拼接到参数后面即可。

记得encodeURL

https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(url)}
(1).PPTX预览效果:
5ce3a369cf29f47ec3f225d9eea0a094.jpeg
  • 优点:还原度很高,功能很丰富,可以选择翻页,甚至支持点击播放动画。

  • 缺点:不知道是不是墙的原因,加载稍慢。

(2).Excel预览效果:
c248caa8a7df901f5cc397508ba8ddf2.jpeg
(3).Doxc预览效果
5ef7d244a36df149336a8aff390a90c9.jpeg
(4).PDF预览效果

这个我测试没有成功,返回了一个错误,其他人可以试试。

f3477993573505a3f7c1aa162b08f2e3.jpeg
(5).总的来说

对于docx,pptx,xlsx都有较好的支持,pdf不行。

还有一个坑点是:这个服务是否稳定,有什么限制,是否收费,都查不到一个定论。在office官方网站上甚至找不到介绍这个东西的地方。

目前只能找到一个Q&A:answers.microsoft.com/en-us/msoff… [1]

微软官方人员回答表示:

ac7e6ad3cb42c0bf5129c9d58f85db17.jpeg

翻译翻译,就是:几乎永久使用,没有收费计划,不会存储预览的文件数据,限制文件10MB,建议用于 查看互联网上公开的文件 。

但经过某些用户测试发现:

560e8625fc630ac494330aa274edd4d0.jpeg

使用了微软的文件预览服务,然后删除了文件地址,仍然可访问,但过一段时间会失效。

2.Google Drive 查看器

接入简单,同 Office Web Viewer,只需要把 src 改为https://drive.google.com/viewer?url=${encodeURIComponent(url)}即可。

限制25MB,支持以下格式:

1c86dac7552c40d045f786f1b8ee6564.jpeg

测试效果,支持docx,pptx,xlsx,pdf预览,但pptx预览的效果不如微软,没有动画效果,样式有小部分会错乱。

由于某些众所周知的原因,不可用

3.阿里云 IMM

官方文档如下:help.aliyun.com/document_de… [2]

4355d140ed75c8384a39e566dd5c86a4.jpeg

付费使用

4.XDOC 文档预览

说了一些大厂的,在介绍一些其他的,需要自行分辨

官网地址:view.xdocin.com/view-xdocin… [3]

2450355cd34648d7311fe47d6c59ee77.jpeg

5.Office Web 365

需要注意的是,虽然名字很像office,但我们看网页的Copyright可以发现,其实是一个西安的公司,不是微软 。

但毕竟也提供了文件预览的服务

官网地址:www.officeweb365.com/ [4]

1563e11a44e9fc1e98fc0a7b3522274d.jpeg

6.WPS开放平台

官方地址:solution.wps.cn/ [5]

dbd4ef8a24e61ccbe731fcaac390cc2c.jpeg

付费使用,价格如下:

7e94746488b851dc872fab8619fbe873.jpeg

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

2 前端处理方案

1.pptx的预览方案

先查一下有没有现成的轮子,目前pptx的开源预览方案能找到的只有这个:github.com/g21589/PPTX… [6] 。但已经六七年没有更新,也没有维护,笔者使用的时候发现有很多兼容性问题。

简单来说就是,没有。对于这种情况,我们可以自行解析,主要步骤如下:

  1. 查询pptx的国际标准

  2. 解析pptx文件

  3. 渲染成html或者canvas进行展示

我们先去找一下pptx的国际标准,官方地址:officeopenxml [7]

先解释下什么是officeopenxml:

Office OpenXML,也称为OpenXML或OOXML,是一种基于XML的办公文档格式,包括文字处理文档、电子表格、演示文稿以及图表、图表、形状和其他图形材料。该规范由微软开发,并于2006年被ECMA国际采用为ECMA-376。第二个版本于2008年12月发布,第三个版本于2011年6月发布。该规范已被ISO和IEC采用为ISO/IEC 29500。

虽然Microsoft继续支持较旧的二进制格式(.doc、.xls和.ppt),但OOXML现在是所有Microsoft Office文档(.docx、.xlsx和.pptx)的默认格式。

由此可见,Office OpenXML由微软开发,目前已经是国际标准。接下来我们看一下pptx里面有哪些内容,具体可以看pptx的官方标准:officeopenxml-pptx [8]

PresentationML或.pptx文件是一个zip文件 ,其中包含许多“部分”(通常是UTF-8或UTF-16编码)或XML文件。该包还可能包含其他媒体文件,例如图像。该结构根据 OOXML 标准 ECMA-376 第 2 部分中概述的开放打包约定进行组织。

7de3463d5841f4889c7c877f514b4545.jpeg

根据国际标准,我们知道,pptx文件本质就是一个zip文件,其中包含许多部分:

部件的数量和类型将根据演示文稿中的内容而有所不同,但始终会有一个 [Content_Types].xml、一个或多个关系 (.rels) 部件和一个演示文稿部件(演示文稿.xml),它位于 ppt 文件夹中,用于Microsoft Powerpoint 文件。通常,还将至少有一个幻灯片部件,以及一张母版幻灯片和一张版式幻灯片,从中形成幻灯片。

那么js如何读取zip呢?

找到一个工具: www.npmjs.com/package/jsz… [9]

于是我们可以开始尝试解析pptx了。

import JSZip from 'jszip'
// 加载pptx数据
const zip = await JSZip.loadAsync(pptxData)
  • 解析[Content_Types].xml

每个pptx必然会有一个 [Content_Types].xml。此文件包含包中部件的所有内容类型的列表。每个部件及其类型都必须列在 [Content_Types].xml 中。通过它里面的内容,可以解析其他的文件数据

const filesInfo = await getContentTypes(zip)

async function getContentTypes(zip: JSZip) {
    const ContentTypesJson = await readXmlFile(zip, '[Content_Types].xml')
    const subObj = ContentTypesJson['Types']['Override']
    const slidesLocArray = []
    const slideLayoutsLocArray = []
    for (let i = 0; i < subObj.length; i++) {
      switch (subObj[i]['attrs']['ContentType']) {
        case 'application/vnd.openxmlformats-officedocument.presentationml.slide+xml':
          slidesLocArray.push(subObj[i]['attrs']['PartName'].substr(1))
          break
        case 'application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml':
          slideLayoutsLocArray.push(subObj[i]['attrs']['PartName'].substr(1))
          break
        default:
      }
    }
    return {
      slides: slidesLocArray,
      slideLayouts: slideLayoutsLocArray,
    }
  }
  • 解析演示文稿

先获取ppt目录下的presentation.xml演示文稿的大小

由于演示文稿是xml格式,要真正的读取内容需要执行 readXmlFile

const slideSize = await getSlideSize(zip)
 async function getSlideSize(zip: JSZip) {
    const content = await readXmlFile(zip, 'ppt/presentation.xml')
    const sldSzAttrs = content['p:presentation']['p:sldSz']['attrs']
    return {
      width: (parseInt(sldSzAttrs['cx']) * 96) / 914400,
      height: (parseInt(sldSzAttrs['cy']) * 96) / 914400,
    }
  }
  • 加载主题

根据 officeopenxml的标准解释

每个包都包含一个关系部件,用于定义其他部件之间的关系以及与包外部资源的关系。这样可以将关系与内容分开,并且可以轻松地更改关系,而无需更改引用目标的源。

除了包的关系部分之外,作为一个或多个关系源的每个部件都有自己的关系部分。每个这样的关系部件都可以在部件的_rels子文件夹中找到,并通过在部件名称后附加“.rels”来命名。

其中主题的相关信息就在ppt/_rels/presentation.xml.rels中

async function loadTheme(zip: JSZip) {
    const preResContent = await readXmlFile(
      zip,
      'ppt/_rels/presentation.xml.rels',
    )
    const relationshipArray = preResContent['Relationships']['Relationship']
    let themeURI
    if (relationshipArray.constructor === Array) {
      for (let i = 0; i < relationshipArray.length; i++) {
        if (
          relationshipArray[i]['attrs']['Type'] ===
          'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme'
        ) {
          themeURI = relationshipArray[i]['attrs']['Target']
          break
        }
      }
    } else if (
      relationshipArray['attrs']['Type'] ===
      'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme'
    ) {
      themeURI = relationshipArray['attrs']['Target']
    }

    if (themeURI === undefined) {
      throw Error("Can't open theme file.")
    }

    return readXmlFile(zip, 'ppt/' + themeURI)
  }

后续ppt里面的其他内容,都可以这么去解析。根据officeopenxml标准,可能包含:

PartDescription
Comments AuthorsContains information about each author who has added a comment to the presentation.
CommentsContains comments for a single slide.
Handout MasterContains the look, position, and size of the slides, notes, header and footer text, date, or page number on the presentation's handout. There can be only one such part.
Notes MasterContains information about the content and formatting of all notes pages. There can be only one such part.
Notes SlideContains the notes for a single slide.
PresentationContains the definition of a slide presentation. There must be one and only one such part. See Presentation.
Presentation PropertiesContains all of the presentation's properties. There must be one and only one such part.
SlideContains the content of a single slide.
Slide LayoutContains the definition for a slide template. It defines the default appearance and positioning of drawing objects on the slide. There must be one or more such parts.
Slide MasterContains the master definition of formatting, text, and objects that appear on each slide in the presentation that is derived from the slide master. There must be one or more such parts.
Slide Synchronization DataContains properties specifying the current state of a slide that is being synchronized with a version of the slide stored on a central server.
User-Defined TagsContains a set of user-defined properties for an object in a presentation. There can be zero or more such parts.
View PropertiesContains display properties for the presentation.

等等内容,我们根据标准一点点解析并渲染就好了。

完整源码:ranui [10]

使用文档:preview组件 [11]

2.pdf的预览方案

(1).iframe和embed

pdf比较特别,一般的浏览器默认支持预览pdf。因此,我们可以使用浏览器的能力:

<iframe src="viewFileUrl" />

但这样就完全依赖浏览器,对PDF的展示,交互,是否支持全看浏览器的能力,且不同的浏览器展示和交互往往不同,如果需要统一的话,最好还是尝试其他方案。

embed的解析方式也是一样,这里不举例子了

(2)pdfjs

npm: www.npmjs.com/package/pdf… [12]

github地址:github.com/mozilla/pdf… [13]

由mozilla出品,就是我们常见的MDN的老大。

而且目前 火狐浏览器 使用的 PDF 预览就是采用这个,我们可以用火狐浏览器打开pdf文件,查看浏览器使用的js就能发现

29184156253418c4f1293ac1e77ee18b.jpeg

需要注意的是,最新版pdf.js限制了node版本,需要大于等于18

github链接:github.com/mozilla/pdf… [14]

263c4c780a826411d6e67162a5106a6b.jpeg

如果你项目node版本小于这个情况,可能会无法使用。

具体使用情况如下:

  • 完整源码:github.com/chaxus/ran/… [15]

  • 使用文档:chaxus.github.io/ran/src/ran… [16]

import * as pdfjs from 'pdfjs-dist'
import * as pdfjsWorker from 'pdfjs-dist/build/pdf.work.entry'

interface Viewport {
  width: number
  height: number
  viewBox: Array<number>
}

interface RenderContext {
  canvasContext: CanvasRenderingContext2D | null
  transform: Array<number>
  viewport: Viewport
}

interface PDFPageProxy {
  pageNumber: number
  getViewport: () => Viewport
  render: (options: RenderContext) => void
}

interface PDFDocumentProxy {
  numPages: number
  getPage: (x: number) => Promise<PDFPageProxy>
}

class PdfPreview {
  private pdfDoc: PDFDocumentProxy | undefined
  pageNumber: number
  total: number
  dom: HTMLElement
  pdf: string | ArrayBuffer
  constructor(pdf: string | ArrayBuffer, dom: HTMLElement | undefined) {
    this.pageNumber = 1
    this.total = 0
    this.pdfDoc = undefined
    this.pdf = pdf
    this.dom = dom ? dom : document.body
  }
  private getPdfPage = (number: number) => {
    return new Promise((resolve, reject) => {
      if (this.pdfDoc) {
        this.pdfDoc.getPage(number).then((page: PDFPageProxy) => {
          const viewport = page.getViewport()
          const canvas = document.createElement('canvas')
          this.dom.appendChild(canvas)
          const context = canvas.getContext('2d')
          const [_, __, width, height] = viewport.viewBox
          canvas.width = width
          canvas.height = height
          viewport.width = width
          viewport.height = height
          canvas.style.width = Math.floor(viewport.width) + 'px'
          canvas.style.height = Math.floor(viewport.height) + 'px'
          const renderContext = {
            canvasContext: context,
            viewport: viewport,
            transform: [1, 0, 0, -1, 0, viewport.height],
          }
          page.render(renderContext)
          resolve({ success: true, data: page })
        })
      } else {
        reject({ success: false, data: null, message: 'pdfDoc is undefined' })
      }
    })
  }
  pdfPreview = () => {
      window.pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker
      window.pdfjsLib
        .getDocument(this.pdf)
        .promise.then(async (doc: PDFDocumentProxy) => {
          this.pdfDoc = doc
          this.total = doc.numPages
          for (let i = 1; i <= this.total; i++) {
            await this.getPdfPage(i)
          }
    })
  }
  prevPage = () => {
    if (this.pageNumber > 1) {
      this.pageNumber -= 1
    } else {
      this.pageNumber = 1
    }
    this.getPdfPage(this.pageNumber)
  }
  nextPage = () => {
    if (this.pageNumber < this.total) {
      this.pageNumber += 1
    } else {
      this.pageNumber = this.total
    }
    this.getPdfPage(this.pageNumber)
  }
}

const createReader = (file: File): Promise<string | ArrayBuffer | null> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = () => {
      resolve(reader.result)
    }
    reader.onerror = (error) => {
      reject(error)
    }
    reader.onabort = (abort) => {
      reject(abort)
    }
  })
}

export const renderPdf = async (
  file: File,
  dom?: HTMLElement,
): Promise<void> => {
  try {
    if (typeof window !== 'undefined') {
      const pdf = await createReader(file)
      if (pdf) {
        const PDF = new PdfPreview(pdf, dom)
        PDF.pdfPreview()
      }
    }
  } catch (error) {
    console.log('renderPdf', error)
  }
}

3.docx的预览方案

我们可以去查看docx的国际标准,去解析文件格式,渲染成html和canvas,不过比较好的是,已经有人这么做了,还开源了

npm地址:www.npmjs.com/package/doc… [17]

使用方法如下:

import { renderAsync } from 'docx-preview'

interface DocxOptions {
  bodyContainer?: HTMLElement | null
  styleContainer?: HTMLElement
  buffer: Blob
  docxOptions?: Partial<Record<string, string | boolean>>
}

export const renderDocx = (options: DocxOptions): Promise<void> | undefined => {
  if (typeof window !== 'undefined') {
    const { bodyContainer, styleContainer, buffer, docxOptions = {} } = options
    const defaultOptions = {
      className: 'docx',
      ignoreLastRenderedPageBreak: false,
    }
    const configuration = Object.assign({}, defaultOptions, docxOptions)
    if (bodyContainer) {
      return renderAsync(buffer, bodyContainer, styleContainer, configuration)
    } else {
      const contain = document.createElement('div')
      document.body.appendChild(contain)
      return renderAsync(buffer, contain, styleContainer, configuration)
    }
  }
}

4.xlsx的预览方案

我们可以使用这个:

npm地址:www.npmjs.com/package/@vu… [18]

支持vue2和vue3,也有js的版本

对于xlsx的预览方案,这个是找到最好用的了。

5.前端预览方案总结

我们对以上找到的优秀的解决方案,进行改进和总结,并封装成一个web components组件:preview组件 [19]

为什么是web components组件?

因为它跟框架无关,可以在任何框架中使用,且使用起来跟原生的div标签一样方便。

并编写使用文档: preview组件文档 [20], 文档支持交互体验。

源码公开,MIT协议。

目前docx,pdf,xlsx预览基本可以了,都是最好的方案。pptx预览效果不太好,因为需要自行解析。不过源码完全公开 ,需要的可以提issue,pr或者干脆自取或修改,源码地址:github.com/chaxus/ran/… [21]

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

3 服务端预览方案

1.openOffice

由于浏览器不能直接打开docx,pptx,xlsx等格式文件,但可以直接打开pdf和图片.因此,我们可以换一个思路,用服务端去转换下文件的格式,转换成浏览器能识别的格式,然后再让浏览器打开,这不就OK了吗,甚至不需要前端处理了。

我们可以借助openOffice的能力,先介绍一下openOffice:

Apache OpenOffice是领先的开源办公软件套件,用于文字处理,电子表格,演示文稿,图形,数据库等。它有多种语言版本,适用于所有常用计算机。它以国际开放标准格式存储您的所有数据,还可以从其他常见的办公软件包中读取和写入文件。它可以出于任何目的完全免费下载和使用。

官网如下:www.openoffice.org/ [22]

需要先下载opneOffice,找到bin目录,进行设置

configuration.setOfficeHome("这里的路径一般为C:\\Program Files (x86)\\OpenOffice 4");

测试下转换的文件路径

public static void main(String[] args) {
    convertToPDF("/Users/Desktop/asdf.docx", "/Users/Desktop/adsf.pdf");
}

完整如下:

package org.example;

import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
import org.artofsolving.jodconverter.office.OfficeManager;

import java.io.File;

public class OfficeUtil {

    private static OfficeManager officeManager;
    private static int port[] = {8100};

    /**
     * start openOffice service.
     */
    public static void startService() {
        DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();
        try {
            System.out.println("准备启动office转换服务....");
            configuration.setOfficeHome("这里的路径一般为C:\\Program Files (x86)\\OpenOffice 4");
            configuration.setPortNumbers(port); // 设置转换端口,默认为8100
            configuration.setTaskExecutionTimeout(1000 * 60 * 30L);// 设置任务执行超时为30分钟
            configuration.setTaskQueueTimeout(1000 * 60 * 60 * 24L);// 设置任务队列超时为24小时
            officeManager = configuration.buildOfficeManager();
            officeManager.start(); // 启动服务
            System.out.println("office转换服务启动成功!");
        } catch (Exception e) {
            System.out.println("office转换服务启动失败!详细信息:" + e);
        }
    }

    /**
     * stop openOffice service.
     */
    public static void stopService() {
        System.out.println("准备关闭office转换服务....");
        if (officeManager != null) {
            officeManager.stop();
        }
        System.out.println("office转换服务关闭成功!");
    }

    public static void convertToPDF(String inputFile, String outputFile) {
        startService();
        System.out.println("进行文档转换转换:" + inputFile + " --> " + outputFile);
        OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager);
        converter.convert(new File(inputFile), new File(outputFile));
        stopService();
    }

    public static void main(String[] args) {
        convertToPDF("/Users/koolearn/Desktop/asdf.docx", "/Users/koolearn/Desktop/adsf.pdf");
    }
}

2.kkFileView

github地址:github.com/kekingcn/kk… [23]

支持的文件预览格式非常丰富

4854a6300462a04c8ea54d5e9cec2586.jpeg

接下来是 从零到一 的启动步骤,按着步骤来,任何人都能搞定

  1. 安装java:

brew install java
  1. 安装maven,java的包管理工具:

brew install mvn
  1. 检查是否安装成功

执行java --version和mvn -v。我这里遇到mvn找不到java home的报错。解决方式如下:

我用的是zsh,所以需要去.zshrc添加路径:

export JAVA_HOME=$(/usr/libexec/java_home)

添加完后,执行

source .zshrc
  1. 安装下libreoffice :

kkFileView明确要求的额外依赖,否则无法启动

brew install libreoffice
  1. mvn安装依赖

进入项目,在根目录执行依赖安装,同时清理缓存,跳过单测(遇到了单测报错的问题)

mvn clean install -DskipTests
  1. 启动项目

找到主文件,主函数mian,点击vscode上面的Run即可执行,路径如下图

03ab7c558e632dcde8445bbd5f8c0218.jpeg
  1. 访问页面

启动完成后,点击终端输出的地址

ee7298d0e73323be7d90894f8a4a61cf.jpeg
  1. 最终结果

最终展示如下,可以添加链接进行预览,也可以选择本地文件进行预览

db9683b3b5d350bf75f35de495af8d0c.jpeg

预览效果非常好

3.onlyOffice

官网地址:www.onlyoffice.com/zh [24]

github地址:github.com/ONLYOFFICE [25]

开发者版本和社区版免费,企业版付费:www.onlyoffice.com/zh/docs-ent… [26]

预览的文件种类没有kkFileView多,但对office三件套有很好的支持,甚至支持多人编辑。

4 总结

  1. 外部服务,推荐微软的view.officeapps.live.com/op/view.aspx,但只建议预览一些互联网公开的文件,不建议使用在要求保密性和稳定性的文件。

  2. 对保密性和稳定性有要求,且不差钱的,可以试试大厂服务,阿里云解决方案。

  3. 服务端技术比较给力的,使用服务端预览方案。目前最好最全的效果是服务端预览方案。

  4. 不想花钱,没有服务器的,使用前端预览方案,客户端渲染零成本。

5 参考文档

  1. 在java中如何使用openOffice进行格式转换 [27]

  2. MAC搭建OpenOffice完整教程-保姆级 [28]

  3. 纯js实现docx、xlsx、pdf文件预览库,使用超简单 [29]

  4. 前端实现word、excel、pdf、ppt、mp4、图片、文本等文件的预览 [30]


欢迎加入我的知识星球,全面提升技术能力。

👉 加入方式,“长按”或“扫描”下方二维码噢:

feb92c784f987445d2c452651a00b2dc.png

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。

0fd7efe6719dff2769cd90581c5c42a7.png

d563604a6c5b56f037ada5611b356bef.png4353b8ef12d09d273d978846de674649.pngd1fa2b79ec0dec957aa09e6e743c2fbd.png92cfb11bdb06096945cc372d8be185cc.png

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
使用Openoffice或LibreOffice实现World、Excel、PPTX在线预览 jodconverter是一个开源项目,用于将Office文档(如Word、Excel、PowerPoint等)转换为其他格式,例如PDF、HTML、图像等。它基于Java平台,并使用LibreOffice/OpenOffice作为转换引擎。 阅读详情

相关推荐

前端预览pdf文件

前端预览pdf

brilliantSt的博客 9396

前端实现 PDF 预览的常见方案

前端实现 PDF 预览常见的5 种方案 :iframe 标签、embed 标签、object 标签、PDF.js、PDFObject。

forward_xx的博客 2万+

xdoc文件预览.zip

文件预览

全网最全的docx、pptx、xlsx、pdf文件预览方案

最近遇到了文件预览的需求,但一搜索发现,这还不是一个简单的功能。于是又去查询了很多资料,调研了一些方案,也踩了好多坑。最后总结方案如下花钱解决(使用市面上现有的文件预览服务)微软google阿里云 IMMXDOCOffice Web 365wps开放平台前端方案pptx的预览方案pdf的预览方案docx的预览方案xlsx(excel)的预览方案前端预览方案总结服务端方案openOfficekkFi...

公众号-老炮说Java 1664

Framelet Transform

需要定义 Framelet 的基函数。Framelet 基函数可以是通过组合不同的小波函数生成的。# 这里可以定义 Framelet 基函数,例如一些小波基函数的线性组合# 这是一个示例函数,具体实现需要根据具体的 Framelet 设计# 示例:正弦函数。

qq_33009429的博客 1212

Unity程序化河流生成工具Waterways:从算法到实践的全流程解析

程序化内容生成(PCG)是游戏开发与三维建模领域的关键技术,它通过算法自动创建游戏内容,显著提升开发效率。其核心原理是将设计规则转化为可执行的代码逻辑,从而生成复杂、多样且符合自然规律的环境资产。在开放世界游戏和模拟经营类项目中,程序化生成技术能够快速构建大规模、高一致性的自然场景,如山川、森林与水体网络。Unity引擎作为广泛使用的开发平台,其地形系统与着色器管线为程序化工具的集成提供了强大基础。本文聚焦于利用Waterways这一Unity工具集,深入探讨如何通过模拟重力驱动、流量累积等自然水力原理,在

weixin_33690963的博客 684

终极文档下载解决方案kill-doc:如何免费获取全网文档资源

你是否经常需要从各种文档网站下载学习资料、技术文档或学术论文,却总是被广告弹窗、登录验证和繁琐的下载步骤困扰?kill-doc正是为解决这些痛点而生的免费用户脚本工具,它让你能够看到多少内容就能下载多少内容,真正实现文档下载的自由化。这款强大的浏览器扩展脚本支持百度文库、原创力文档、豆丁网等数十个主流文档平台,让文档获取变得简单高效。 ## 为什么传统文档下载方式已经过时? 传统的文档下载方式

gitblog_00908的博客 116

告别理论!手把手教你用Patran/Nastran搞定悬臂翼的颤振分析(附完整模型文件)

本文提供了一份详细的Patran/Nastran悬臂翼颤振分析实战指南,涵盖从几何建模到结果解读的全过程。通过手把手教学和完整模型文件,帮助工程师和学生快速掌握气动弹性分析技术,特别适合需要实际操作的初学者。文章重点介绍了模态分析、气动建模和颤振求解等关键步骤,并提供了常见问题排查和优化建议。

weixin_30879169的博客 493

如何用kill-doc一站式免费下载全网文档:突破性文档获取方案

在数字化学习与工作中,我们经常面临这样的困境:急需一份技术文档、学术论文或行业标准,却被网站的广告弹窗、强制登录、繁琐验证和付费门槛层层阻挠。kill-doc作为一款突破性的浏览器脚本工具,正是为解决这一痛点而生。这款高效智能的文档下载工具基于"所见即所得"理念,让你能够看到多少内容就能下载多少内容,真正实现文档获取自由。 ## 传统文档获取的痛点与kill-doc的智能解决方案 | 传统方式

gitblog_00141的博客 65

揭秘AI人工智能中Stable Diffusion的模型微调技巧

Stable Diffusion作为一种强大的文本到图像生成模型,在艺术创作、设计、娱乐等多个领域展现出了巨大的应用潜力。然而,其默认的模型输出可能无法满足特定用户或特定场景的个性化需求。本文章的目的在于深入揭秘Stable Diffusion的模型微调技巧,让读者能够根据自己的需求对模型进行定制化调整,生成符合特定风格、主题或要求的图像。范围涵盖了从基础概念到实际操作,从理论原理到项目实战的全方位内容,旨在为读者提供一个系统且深入的学习指南。

大模型应用工坊 950

为YOLOv11引入加权双向特征金字塔(BiFPN)

本文介绍了将BiFPN应用于YOLOv11模型以提升边缘设备上小目标检测精度的实践。针对传统FPN在特征融合时的信息丢失问题,采用带可学习权重的BiFPN结构进行改造,实现了不同层级特征的动态融合。重点阐述了WeightedFeatureFusion模块的实现细节、neck结构改造方法及训练部署注意事项。实验表明,该改进使小目标AP提升3.1%,参数量仅增加5%,在精度和效率间取得良好平衡。文章还分享了权重初始化、归一化处理等实用技巧,并强调需根据数据特性评估改进效果,重新计算anchor等关键点。

as1225120794的博客 352

终极文档下载指南:如何免费获取全网文档资源

你是否经常遇到这样的困扰:需要从百度文库、豆丁网等平台下载学习资料或技术文档,却总是被登录验证、广告弹窗和繁琐的下载流程所阻碍?今天,我要向你介绍一款革命性的免费文档下载工具——kill-doc,它能让你看到多少内容就能下载多少内容,真正实现文档下载的自由化。这款强大的浏览器脚本工具支持超过30个主流文档平台,让文档获取变得前所未有的简单高效。 ## 为什么传统下载方式让你头疼? 在开始介绍k

gitblog_01097的博客 217

学Simulink——基于Simulink的PMSM矢量控制(FOC)从零搭建

《Simulink下PMSM矢量控制(FOC)全流程开发指南》 本教程系统讲解了基于Simulink的永磁同步电机(PMSM)磁场定向控制(FOC)实现方法。主要内容包括:FOC控制原理与双闭环架构设计、Simulink建模全流程(含PMSM本体建模、坐标变换、PI控制器设计等)、关键调试技巧以及工程扩展方向。教程以48V伺服电机为例,详细演示了从Clarke/Park变换到SVPWM生成的完整实现过程,并提供了参数配置建议和常见问题解决方案。通过本教程,读者可掌握FOC系统的核心实现技术,为开发高性能电机

xiaoheshang_123的博客 273

终极文档下载工具kill-doc:如何免费获取全网文档资源

你是否经常需要从各种文档网站下载学习资料、技术文档或学术论文,却总是被广告弹窗、登录验证和繁琐的下载步骤困扰?kill-doc正是为解决这些痛点而生的免费用户脚本工具,它让你能够看到多少内容就能下载多少内容,真正实现文档下载的自由化。这款强大的浏览器扩展脚本支持百度文库、原创力文档、豆丁网等数十个主流文档平台,让文档获取变得简单高效。 ## 为什么你需要kill-doc?传统下载方式的痛点对比

gitblog_00082的博客 93

高并发网络爬虫实践(欧赔、亚盘、大小指数数据爬取)

本文通过对一个实战化的高并发网络爬虫脚本进行深度模块化剖析,展示了如何构建一个兼具性能、健壮性和易用性的数据采集工具。核心设计思想总结模块化与单一职责: 每个函数都专注于解决一个特定问题,无论是网络请求、数据解析还是文件操作。并发与效率: 通过ThreadPoolExecutor实现了高效的并发抓取,极大缩短了总耗时。健壮性与容错: 强大的重试机制、细致的异常处理和线程安全的文件写入,保证了程序在复杂网络环境下的稳定运行。断点续传: 精心设计了进度记录与恢复机制,使得大规模抓取任务变得轻松可控。

猫敷雪 486

出现 Tomcat:HTTP状态 404 - 未找到解决方法(图文分析)

出现如下问题 HTTP状态 404 - 未找到 类型 状态报告 消息 请求的资源[/ajax_war_exploded/]不可用 描述 源服务器未能找到目标资源的表示或者是不愿公开一个已经存在的资源表示。 Apache Tomcat/8.5.69 解决方法如下: 网上中的操作有步操作多数都误导 这个部署的环境目录上面是web.xml 下面的目录路径是web即可不用到webapp 保存重启服务器即可使用 其他配置中启动tomcat的操作具体 JRE 1.8 ...

码农研究僧的博客 13万+

3步免费解锁全网文档:kill-doc终极下载工具完全指南

你是否厌倦了在各种文档网站上反复点击广告、强制登录验证、以及繁琐的下载步骤?kill-doc 作为一款免费的浏览器脚本工具,彻底改变了文档下载的游戏规则。这个强大的工具基于"看到多少,下载多少"的核心理念,让你能够轻松获取百度文库、原创力文档、豆丁网等30多个主流平台的文档资源。无论是学术研究、职场办公还是个人学习,kill-doc 都能让你的文档获取效率提升数倍。 ## 🔍 为什么你需要ki

gitblog_00521的博客 212

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

一条命令查遍全网:Sherlock 跨平台用户名搜索完整指南

Sherlock 是一款开源 OSINT 工具:输入一个用户名,它会自动在 100+ 个社交网络和在线服务中逐一核查注册情况,并把找到的主页链接列出来。无论是做安全侦察、品牌舆情监测,还是清理自己早年留下的旧账号,它都能替代"挨个网站手动点开"这种费时的流程。 ## 解决什么问题 一次调查里,你最想知道的答案往往是:这个用户名在各平台上被谁占用了?手动做法是逐站访问、站内搜索、翻主页,上百个平

gitblog_00517的博客 87

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

免费文档下载神器:kill-doc浏览器脚本一键获取全网文档

还在为文档网站的各种限制而烦恼吗?广告弹窗、强制登录、验证码识别……这些层层障碍让获取一份简单的技术文档都变得异常困难。kill-doc文档下载工具正是为解决这些问题而生,这款基于Tampermonkey脚本技术的开源工具能够智能绕过各类文档平台的下载限制,让你真正做到"看到多少,就能下载多少"。无论你是学生、研究人员还是开发者,这款文档下载工具都能为你节省大量时间和精力,实现真正的一键下载体验。

gitblog_00483的博客 195

3步解锁文档自由:kill-doc如何帮你轻松获取全网免费资料

你是否曾为下载文档而烦恼?面对百度文库的登录弹窗、豆丁网的预览限制、原创力文档的繁琐步骤,kill-doc文档下载脚本为你提供了一键解决方案。这个基于Tampermonkey的用户脚本,让免费文档获取变得简单高效,真正实现"所见即所得"的下载体验。 ## 📊 文档下载痛点诊断:为什么我们需要kill-doc? 在线文档平台虽然提供了丰富的资源,但用户体验却常常令人沮丧。让我们先来看看传统下载

gitblog_00903的博客 194

如何用kill-doc三步搞定全网30+文库免费下载:你的终极文档获取秘籍

还在为下载文档而烦恼吗?面对百度文库、原创力文档、人人文库等平台的繁琐验证、强制登录和恼人广告,你是否感到束手无策?今天我要为你介绍一个革命性的解决方案——kill-doc,这个免费的浏览器脚本能让你轻松下载30多个主流文档平台的免费资源,真正实现"所见即所得"的下载体验。 **核心关键词**:kill-doc文档下载、百度文库免费下载、文档获取神器 **长尾关键词**:如何免费下载文库文档

gitblog_00122的博客 160
上一篇: 又一款更快、更好、更稳定的 Redis 可视化工具开源了!!!
下一篇: 分布式定时调度:xxl-job 最佳实践
公众号-芋道源码
博客等级 码龄10年 1634粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值