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

官网地址:[4]

6.WPS开放平台

官方地址:/[5]

brew换源_源换部首_源换个称呼

付费使用,价格如下:

源换个称呼_brew换源_源换部首

2前端处理方案1.pptx的预览方案

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

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

查询pptx的国际标准

解析pptx文件

渲染成html或者进行展示

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

先解释下什么是:

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

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

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

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

brew换源_源换个称呼_源换部首

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

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

那么js如何读取zip呢?

找到一个工具: …[9]

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

import JSZip from 'jszip'
// 加载pptx数据
const zip = await JSZip.loadAsync(pptxData)

每个pptx必然会有一个 [].xml。此文件包含包中部件的所有内容类型的列表。每个部件及其类型都必须列在 [].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目录下的.xml演示文稿的大小

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

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,
    }
  }

根据 的标准解释

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

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

其中主题的相关信息就在ppt/_rels/.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里面的其他内容,都可以这么去解析。根据标准,可能包含:

源换个称呼_brew换源_源换部首

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

完整源码:ranui[10]

使用文档:组件[11]

2.pdf的预览方案(1).和embed

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

<iframe src="viewFileUrl" />

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

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

(2)pdfjs

npm:…[12]

地址://pdf…[13]

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

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

源换部首_源换个称呼_brew换源

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

链接://pdf…[14]

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

具体使用情况如下:

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
}

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 = (numbernumber) => {
    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: [100-10, 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和,不过比较好的是,已经有人这么做了,还开源了

npm地址:…[17]

使用方法如下:

import { renderAsync } from 'docx-preview'

interface DocxOptions {
  bodyContainer?: HTMLElement | null
  styleContainer?: HTMLElement
  buffer: Blob
  docxOptions?: Partial<Record<stringstring | 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地址:@vu…[18]

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

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

5.前端预览方案总结

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

为什么是web 组件?

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

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

源码公开,MIT协议。

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

3服务端预览方案1.

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

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

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

官网如下:[22]

需要先下载,找到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.

地址://kk…[23]

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

brew换源_源换部首_源换个称呼

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

安装java:

brew install java

安装maven,java的包管理工具:

brew install mvn

检查是否安装成功

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

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

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

添加完后,执行

source .zshrc

安装下 :

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

brew install libreoffice

mvn安装依赖

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

mvn clean install -DskipTests

启动项目

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

访问页面

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

brew换源_源换个称呼_源换部首

最终结果

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

预览效果非常好

3.

官网地址:[24]

地址:/[25]

开发者版本和社区版免费,企业版付费:…[26]

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

4总结

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

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

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

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

5参考文档:

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

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

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

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

参考资料

[1]

/en-us/msoff…:

[2]

/…:

[3]

/view-…:

[4]

[5]

/:

[6]

//PPTX…:

[7]

:

[8]

-pptx:

[9]

…:

[10]

ranui:

[11]

组件:

[12]

…:

[13]

//pdf…:

[14]

//pdf…:

[15]

//ran/…:

[16]

..io/ran/src/ran…:

[17]

…:

[18]

@vu…: @vue-/excel

[19]

组件:

[20]

组件文档:

[21]

//ran/…:

[22]

[23]

//kk…:

[24]

[25]

/:

[26]

…:

[27]

在java中如何使用进行格式转换:

[28]

MAC搭建完整教程-保姆级:

[29]

纯js实现docx、xlsx、pdf文件预览库,使用超简单:

[30]

前端实现word、excel、pdf、ppt、mp4、图片、文本等文件的预览:

来源|/post/

资料免费共享群

1、4000G架构师全栈资料(点击查看)
2、99个实战项目点击查看
3、5000页互联网大厂面试题整理汇总(点击查看)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注