html2pdf no puede exportar la solución de imágenes (versión 2020)

Fondo de investigación: el elemento de función en el proyecto reciente es exportar informes en PDF. Dado que el contenido de la página contiene una variedad de gráficos estadísticos, es difícil para el personal de fondo implementarlo, así que pasemos al frente ~ Ya que es un proyecto de intranet, todas las imágenes se leen desde el servidor, lo que resulta en Las imágenes en el pdf descargado no pueden salir, estoy demasiado al sur.

-------------------------------------------------- -------------------------Línea divisoria----------------------- -------------------------------------------------- -----

Todos deben conocer el método de importación de PDF, primero convertir html a lienzo y luego convertirlo a pdf.

Debido al marco Vue + desarrollo del lenguaje mecanografiado utilizado en el proyecto, declare aquí con anticipación, para que los amigos puedan entender la gramática primero.

Se utilizan las bibliotecas de terceros html2canvas y jspdf, y las direcciones no se publican aquí (o se publican cuando no hay nada que hacer).

 

Permítanme hablar sobre la idea de encontrar el problema primero:

1. Al principio no hubo ningún mensaje, pensé que estaba cubierto, pero eliminé el color de fondo del pdf, pero aún así nada, lo que significa que la imagen realmente no se exporta.

2. Prueba a usar una imagen de proyecto local y funciona (esto es muy importante, hablaré de eso más adelante), prueba a usar una imagen de red y también se exporta. ¿Será un problema entre dominios?

3. Al buscar información en Internet, se dice que modifique useCORS a verdadero para permitir el cruce de dominios, allowTaint a verdadero, ahora corrija la ruta de la imagen y escriba una imagen de servidor hasta el final, realmente solicita

El caso fue resuelto y el sospechoso finalmente confesó. Oye~ No entres en pánico, qué está pasando, ve al segundo artículo

html2canvas no obtuvo el recurso de imagen.

A partir de esto, generalmente se conoce el quid del problema:

Los enlaces del atributo src de la etiqueta img ordinaria a las imágenes del servidor no causarán problemas entre dominios. Esta es también la razón por la que no lo esperaba al principio, entonces, ¿por qué informará entre dominios? Solo eche un vistazo (en caso de que no haya entendido y haya cometido un error ), puede ver que al convertir html a lienzo, las imágenes en html y echartscanvas se procesan por separado. Las imágenes que citó en modo js causaron problemas entre dominios. . .

 

Pero qué hacer, recomiendo un sitio web mágico llamado [Baidu, lo sabrás] (tos, hermano Yanhong, recuerda pagar)

Busqué el siguiente contenido en Internet

HTML a PDF, la solución definitiva al fallo de exportación de imágenes

El autor usa el método de descargar al local y luego citar. Aquí, rindo homenaje al autor y cambio la solicitud de dominio cruzado a un archivo local. ¿No está esto resuelto? Pero no quiero ser tan problemático, ¿hay una mejor manera?

Los amigos que han usado el desarrollo de vue saben que la forma en que vue se refiere a las imágenes locales es require('ruta relativa del proyecto'), y cuando llega a la página, en realidad se convierte en código base64

¿Puedo colocar directamente el código base64 en el atributo src de la imagen, de modo que sea equivalente a almacenarlo dinámicamente de forma local y no haya dominios cruzados? Eche un vistazo a la exportación, el resultado es exitoso, luego solo necesito convertir la dirección de imagen dinámica en código base64 cada vez que exporto, hágalo.

Consulte  vue para convertir la dirección de red de la imagen al formato base64

código superior

data(){
    imgSrc: null
}
mounted(){
    //...执行你的查询方法获取图片网络路径,仅为了演示所以写成回调方式
    this.search().then(()=>{
        this.toBase64('图片全路径')
    })
}

methods(){
    toBase64(imgUrl: any) {
        try {
          let image = new Image()
          // 解决跨域问题
          image.setAttribute('crossOrigin', 'anonymous')
          let imageUrl = imgUrl
          image.src = imageUrl
          // image.onload为异步加载
          image.onload = () => {
            let canvas = document.createElement('canvas')
            canvas.width = image.width
            canvas.height = image.height
            let context: any = canvas.getContext('2d')
            context.drawImage(image, 0, 0, image.width, image.height)
            let quality = 0.8
            // 这里的dataurl就是base64类型
            // 使用toDataUrl将图片转换成jpeg的格式,不要把图片压缩成png,因为压缩成png后base64的字符串可能比不转换前的长!
            let dataurl = canvas.toDataURL('image/jpeg', quality)
            this.imgSrc = dataurl
          }
        } catch (e) {
          console.log(e)
        }
      }
}

Simplemente asigne el valor directamente en la página

<img :src="imgSrc">

No afectará el código html2pdf en absoluto, por lo que el contenido exportado puede ver la imagen.

En este punto, nos paramos sobre los hombros de los gigantes para resolver este problema, y ​​la idea de los gigantes es convertir el dominio cruzado en local, pero los beneficios del marco vue se reflejan, jajaja.

A continuación se muestra el código clave de vue+TS

import html2Canvas from 'html2canvas'
export default class SingleHealthAnalysisModal extends Vue{
    imgSrc: any = null

    created() {
        this.initBasicInfo(this.equipId)
    }
    
    render(){
        <div>
            <img
               style={
   
   { width: '100%', height: '100%' }}
               src={this.imgSrc ? this.imgSrc : require('@/assets/images/default_pic.jpg')}>
            </img>
            <a-button
                type="primary"
                on-click={() => {
                    this.$AntMessage.loading({ duration: 0, content: '文件导出中...' })
                    this.printOut('装备健康情况分析')
                }}
              >
            导出PDF
            </a-button>
        </div>
    }
    
    initBasicInfo(equipId:any){
        // 查询详情请求
        .then((res:any)=>{
            if (res.code === window.CROSS_CODE) {
                this.imgSrc = null // 重置
                this.equipBasicInfo = res.map
                if (this.equipBasicInfo.equipmentImage && this.equipBasicInfo.equipmentImage !== 'null') {
                    this.toBase64(window.config.imgShowUrl + this.equipBasicInfo.equipmentImage.split(',')[0])
                }
            }
        })
    }

  printOut(name: any) {
    try {
      let shareContent: any = document.querySelector('.allLifeDetail') //需要截图的包裹的(原生的)DOM 对象
      let width = shareContent.clientWidth //获取dom 宽度
      let height = shareContent.clientHeight //获取dom 高度
      let canvas: any = document.createElement('canvas') //创建一个canvas节点
      let scale = 1 //定义任意放大倍数 支持小数
      canvas.width = width * scale //定义canvas 宽度 * 缩放
      canvas.height = height * scale //定义canvas高度 *缩放
      canvas.style.width = shareContent.clientWidth * scale + 'px'
      canvas.style.height = shareContent.clientHeight * scale + 'px'
      canvas.getContext('2d').scale(scale, scale) //获取context,设置scale
      let opts = {
        scale: scale, // 添加的scale 参数
        canvas: canvas, //自定义 canvas
        logging: false, //日志开关,便于查看html2canvas的内部执行流程
        width: width, //dom 原始宽度
        height: height,
        useCORS: true, // 【重要】开启跨域配置
        // allowTaint: true,
        // taintTest: true,
        // logging: true,
      }

      html2Canvas(shareContent, opts).then(() => {
        var contentWidth = canvas.width
        var contentHeight = canvas.height
        //一页pdf显示html页面生成的canvas高度;
        var pageHeight = (contentWidth / 592.28) * 841.89
        //未生成pdf的html页面高度
        var leftHeight = contentHeight
        //页面偏移
        var position = 0
        //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
        var imgWidth = 595.28
        var imgHeight = (592.28 / contentWidth) * contentHeight
        var pageData = canvas.toDataURL('image/jpeg', 1.0)
        var PDF = new jsPDF('', 'pt', 'a4')
        if (leftHeight < pageHeight) {
          PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
        } else {
          while (leftHeight > 0) {
            PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
            leftHeight -= pageHeight
            position -= 841.89
            if (leftHeight > 0) {
              PDF.addPage()
            }
          }
        }
        this.$AntMessage.destroy()
        PDF.save(name + '.pdf') // 这里是导出的文件名
      })
    } catch (error) {
      this.$AntMessage.destroy()
      this.$AntMessage.error('导出失败')
    }
  }

  toBase64(imgUrl: any) {
    try {
      imgUrl = imgUrl.replace('\\', '/')
      // 一定要设置为let,不然图片不显示
      let image = new Image()
      // 解决跨域问题
      image.setAttribute('crossOrigin', 'anonymous')
      let imageUrl = imgUrl
      image.src = imageUrl
      // image.onload为异步加载
      image.onload = () => {
        var canvas = document.createElement('canvas')
        canvas.width = image.width
        canvas.height = image.height
        var context: any = canvas.getContext('2d')
        context.drawImage(image, 0, 0, image.width, image.height)
        var quality = 0.8
        // 这里的dataurl就是base64类型
        // 使用toDataUrl将图片转换成jpeg的格式,不要把图片压缩成png,因为压缩成png后base64的字符串可能比不转换前的长!
        let dataurl = canvas.toDataURL('image/jpeg', quality)
        this.imgSrc = dataurl
      }
    } catch (e) {
      console.log(e)
    }
  }
}

 

Artículo de referencia:

HTML a PDF, la solución definitiva al fallo de exportación de imágenes

Vue convierte la dirección de red de la imagen al formato base64

Error de seguridad no detectado: no se pudo ejecutar 'toDataURL' en 'HTMLCanvasElement': los lienzos contaminados pueden no

Supongo que te gusta

Origin blog.csdn.net/rrrrroy_Ha/article/details/109990259
Recomendado
Clasificación