docx.js 前端生成word之 Image篇

1,357 阅读2分钟

目录

一. docx.js生成图片API;

二. docx.js 通过图片url生成遇到的问题:

  • 如何获取图片的原图大小
  • 在获取原图大小的过程中出现异步问题

三. 最终代码

一. docx.js生成图片API

    import * as fs from 'fs';
    import { Document, ImageRun, Paragraph } from 'docx.js';
    
    const doc = new Document([
        sections: [
            children: [
                new Paragraph([
                    children: [
                        new ImageRun({
                           data: fs.readFileSync('./demo/images/image1.png'),
                           transformation: {
                               width: 100,
                               height: 100
                           }
                        })
                    ]
                ])
            ]
        ]
    ])
    
    

二. docx.js 通过图片url生成遇到的问题:

  1. 如何获取图片的原图大小 解决方法: 通过生成img dom,来获取图片原始的大小;
  2. 在获取原图大小的过程中出现异步问题: 解决方法: 在循环图片的时候,出现了异步,解决方法用 async/await解决;
  3. 加载的顺序和之前的顺序一致问题: 解决方法: 用一个独一无二的占位符先先占children中的一个位置,加载成功后替换即可,在这里我使用的是src;当图片开始加载的时候, src占据图片原本应该占据的位置,等图片加载完成后,根据src的位置,替换加载成功后生成image的段落。 代码如下:
    import { Document, ImageRun, Paragraph } from 'docx.js';
    
    async createImage(src){
        const blob = await fetch(src).then(res => res.blob())
        return blob
    }
    
    async getImageFromUrl(src) {
        return new Promise((resolve, reject) => {
            let img = new Image()
            img.onload = function() {
                resolve(src)
            }
            img.onerror = function() {
                reject('加载失败')
            }
            
        })
    }
    
    async getImageSize(src) {
        const img = await getImageFromUrl(src).then(img => img).catch(err => console.log(err))
    }
    // 生成图片
    createParagraph(children) {
      return new Paragraph({
        children: [children]
      })
    }
    
    //当有个数组图片时,假设为 arrImage=['https://1.jpg', 'https://2.jpg',...]
    let arrImage = ['http://demo/1.jpg', 'http://demo/2.jpg','http://demo/3.jpg', 'http://demo/4.jpg', 'http://demo/5.jpg']
    
    children = []
    
    await Promise.all(arrImage.map(async function (src) {
        children.push(src) // 占位符,保持图片下载在文档中的顺序一致
        let blob = await createImage(src)
        let image = await getImageFromUrl(src)
        let childIndex = children.indexOf(src)
        if (childIndex > -1) {
              children[childIndex] = createParagraph(new ImageRun({
                  data: blob,
                  transformation: {
                    width: image.width,
                    height: image.height
                  }
              }))
            }
    }))
    
    const doc = new Document([
        sections: [
        {
            children: children
        }
        ]
    ])
    
总结: 这里涉及到一个map和async/await的问题, 上面代码 arrImage.map(async function (src) {....}), 这里面实际上是是 [promise1, promise2, promise3...], 必须使用Promise.all()