关于pptxgen.js在导出ppt时插入二进制图片与循环插入多张宽高不确定的图片,个人记录

一、插入二进制图片

这个二进制图片我使用html2canvas生成的,网上有关于这个插件的教程很多0.0就不详细说明了,简单贴一下代码

利用html2canvas生成二进制图片,返回一个异步

// html2canvas 截取图片
    convertToImage(container) {
      // 高度
      const arrDPI = this.js_getDPI() // 获取显示器DPI
      let dpiX = 96
      if (arrDPI.length > 0) {
        dpiX = arrDPI[0]
      }
      // html2canvas配置项
      const ops = {
        dpi: dpiX,
        useCORS: false,
        allowTaint: true,
        scale: 4 // 缩放比例越大,图片越清晰
      }

      return html2canvas(container, ops).then((canvas) => {
        // 返回图片的二进制数据
        // this.imgBlobData = canvas.toDataURL("image/png");
        return canvas.toDataURL('image/png', 1.0)
      })
    },
    // 获取屏幕dpi
    js_getDPI() {
      var arrDPI = []
      if (window.screen.deviceXDPI !== undefined) {
        arrDPI[0] = window.screen.deviceXDPI
        arrDPI[1] = window.screen.deviceYDPI
      } else {
        var tmpNode = document.createElement('DIV')
        tmpNode.style.cssText = 'width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden'
        document.body.appendChild(tmpNode)
        arrDPI[0] = parseInt(tmpNode.offsetWidth)
        arrDPI[1] = parseInt(tmpNode.offsetHeight)
        tmpNode.parentNode.removeChild(tmpNode)
      }
      return arrDPI
    },

利用pptxgen,导出ppt时候插入二进制图片,有关于pptxgen的使用我在另一篇文章中有说0.0
所以这里直接上代码了

		// 增加幻灯片
      const slide = pres.addSlide()
      // 截取二进制图片 记得用await,因为是异步的,否则会导致截图没截完,ppt就已经导出去了。
      this.imgBlobData = await this.convertToImage(this.$refs.keyword.$children[0].$children[1].$el) // 这里参数是要截取的元素
      // 插入图片
      slide.addImage({ x: '52%', y: this.subContentY, h: 3.38, w: '43%', sizing: { type: 'contain' }, data: this.imgBlobData })

二、宽高确定的情况下,循环插入多张图片

有个任务要求是导出文章截图,文章截图的宽高是确定的,而且每张图片都一样,所以这个需求其实不算太难,只要算好图片宽高,然后对应设置x值就好了,最多再加一个换页
上代码,走你

// 模块五 内容图片
    setModule5(pres, item, platform) {
      const slide = pres.addSlide()
      const list = this.contentImg.find(citem => citem.platform === platform) || {}
      // list.contentList就是包含图片的数组,里面是图片的url
      if (list.contentList) {
      	// 一页ppt放5张图片,超出换页
      	// 数组长度小于等于5的情况
        if (list.contentList.length <= 5) {
          list.contentList.forEach((litem, index) => {
          	// 循环,1.6是每张图片的实际宽度+左间距(1.5 + 0.1) 0.8是第一张图片的横坐标距离 
            slide.addImage({ x: index * 1.6 + 0.8, y: 1.3, w: 1.5, h: 3.3, path: litem, shadow: { type: 'outer' }})
          })
        } else {
          // 数组长度大于5的情况
          // 超出5张图片则换页,计算一下总页数 list.contentList.length - 1 是防止数组数量刚好为5的时候就换页了。。
          const count = Math.floor((list.contentList.length - 1) / 5)
          for (let i = 0; i <= count; i++) {
            let tempSlide = slide
            if (i > 0) {
              // 如果不是第一页,则需要新建一张PPT页
              tempSlide = pres.addSlide()
            }
            list.contentList.forEach((litem, index) => {
              if (index >= i * 5 && index < (i * 5 + 5)) {
                // 循环,1.6是每张图片的实际宽度+左间距(1.5 + 0.1) 0.8是第一张图片的横坐标距离 
                tempSlide.addImage({ x: (index % 5) * 1.6 + 0.8, y: 1.3, w: 1.5, h: 3.3, path: litem, shadow: { type: 'outer' }})
              }
            })
          }
        }
      }
    },

代码没什么好说的,了解一下思路就好了0.0循环确定图片位置,注意换行或者换页之后的位置就好了

三、宽高不确定的情况下,循环插入多张图片

工作中总是会遇到各种各样的需求,导出文章之后,又来了一个导出评论截图的功能。
由于评论截图是爬虫组与后端返回来的,在拿到图片之前,并不确定图片的宽高
但是在pptxgen.js中又必须确定了图片的宽高、位置等参数才能够插入图片,flex什么的以及图片自适应什么的我目前暂未发现。。
那怎么办呢?只好确定一个统一的高度或者宽度,自己硬着头皮,在图片加载完成之后获取图片本身宽高,再一张张地换算单位了
直接上代码吧。。。

// 模块六 评论图片 
    async setModule6(pres, item, platform) {
      const slide = pres.addSlide()
      const list = this.commentImg.find(citem => citem.platform === platform) || {}
      // list.commentList 就是包含图片的数组,里面是图片的url
      if (!list.commentList) {
        return false
      }
      const widthList = []
      const heightList = []
      // 图片实际宽度(在ppt上的宽度)限定 2.5 这里我是写死了图片宽度,然后去计算图片转换后的实际高度
      const w = 2.5
      // const hList = []
      // 循环获取图片宽高,装进数组中
      for (let index = 0; index < list.commentList.length; index++) {
        // const i = Math.floor(Math.random() * 3)
        const imgItem = list.commentList[index]
        imgList.push(imgItem)
        await this.loadImg(imgItem).then(obj => {
          // 实际高度 = 实际宽度 / 图片原本宽度 * 图片原本高度
          widthList.push(obj.width)
          heightList.push(obj.height)
          // hList.push(2.5 / obj.width * obj.height)
        })
      }

      // 纵向排布 这里应该是我某个逻辑出了问题,导致纵向排布失败了,但其实大概思路其实都差不多的
      // hList.forEach((item, index) => {
      //   // 计算数组0到当前索引实际总高度
      //   const totalH = this.getTotalH(hList.slice(0, index + 1))
      //    console.log(totalH);
      //   // 计算x的位置
      //   const x = Math.floor(totalH / 3.8) * 2.6 + 0.5
      //   console.log(x)
      //   let y = 1.3
      //   // 计算实际y距离,先判断0到上一个索引的高度
      //   if (index > 0) {
      //     const preTotalH = this.getTotalH(hList.slice(0, index))
      //     y = 1.3 + preTotalH % 3.8 + 0.1
      //     if (y > 3.8) {
      //       y = 1.3
      //     }
      //   }
      //   // 实际x距离,超出3个会换行,所以需要计算大于3的图片
      //   slide.addImage({ path: imgList[index], x, y, w, item })
      // })

      // 这是横向排布
      // 取所有图片的最高高度来换行,以免图片重叠(实际上用纵向排布会更好一点,就是flex-direction: column 这样的效果,这样不会导致行与行之间的间距太大)
      const maxH = Math.max.apply(null, heightList)
      const maxHIndex = heightList.findIndex(item => item === maxH)
      const maxImgH = w / widthList[maxHIndex] * maxH + 0.1
      // 循环设置图片
      widthList.forEach((item, index) => {
        // 计算实际高度
        const h = w / item * heightList[index]
        // 计算实际y距离 因为超出3个就换行
        const y = 1.3 + Math.floor(index / 3) * maxImgH
        // 实际x距离,超出3个会换行,所以需要计算大于3的图片
        let x = 0
        if (index > 2) {
          x = index % 3 * (w + 0.1) + 0.8
        } else {
          x = index * (w + 0.1) + 0.8
        }
        slide.addImage({ path: imgList[index], x, y, w, h })
      })
    },
    // 获取总高度
    // getTotalH(list) {
    //   const total = list.reduce((prev, cur) => {
    //     return prev + cur
    //   })
    //   return total
    // },
    // 在图片加载完成之后获取图片宽高
    loadImg(url) {
      return new Promise((resolve, reject) => {
        const img = new Image()
        img.src = url
        img.onload = () => {
          const obj = {
            width: img.width,
            height: img.height
          }
          resolve(obj)
        }
        img.onerror = reject
      })
    },

以上代码,重点是图片加载之后获取宽高,换算实际宽高比例,这样就知道了图片在ppt中的宽和高了。
然后注意循环时候图片换行之后的位置就好了

思路都是这样的,可以稍微参考,我当时写的还是比较乱的,假如有更好的选择可以交流一下,大家共同学习0.0

四、异步导出处理

由于导出ppt时候可能会涉及到异步操作(比如计算图片宽高、截图等操作),我在导出ppt的时候,就出现过“图片没算完,ppt就已经导出了”的现象,导致ppt一片空白,所以对导出ppt的方法我也做了一下处理

// 导出ppt
    async downloadPPT() {
      this.$notify.info('正在导出,请稍后')
      const pres = new Pptxgen()
      this.setModule1(pres)
      this.setModule2(pres)
      this.setModule3(pres)
      // 项目中是有很多个页面的,但从第五个页面开始, 5 6 7、 8 9 10 、11 12 13,页面样式都是这样重复的,所以我进行了一个for循环,顺便踩了一下forEach的坑。(forEach里面只能执行同步方法,在for循环里面使用async 和await 这样的异步操作是不起作用的。)
      for (let index = 0; index < this.settingList.length; index++) {
        const item = this.settingList[index]
        if (item.pageNo > 4 && item.disable) {
          if ((item.pageNo - 4) % 3 === 1) {
            this.setModule4(pres, item, index === 4 ? this.settingList[index - 1].title : '')
          } else if ((item.pageNo - 4) % 3 === 2) {
            this.setModule5(pres, item, this.settingList[index - 1].platform)
          } else {
          	// 其实其他代码忽视就好了,重点是这里 用await处理一下就好了
            await this.setModule6(pres, item, this.settingList[index - 2].platform)
          }
        }
      }
      console.log(pres)
      pres.writeFile({ fileName: '报告' }).then(() => {
        this.$notify.success('导出成功')
      })
    },
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值