国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【PDF】html/dom生成pdf

這篇具有很好參考價值的文章主要介紹了【PDF】html/dom生成pdf。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

1、簡要描述

上一篇博客主要講的是pdf文件轉(zhuǎn)換成canvas,然后進行相關(guān)的畫框截圖操作。

【PDF】Canvas繪制PDF及截圖

本篇博客主要講html中dom如何生成pdf文件(前端生成pdf),后端生成pdf當(dāng)然也可以,原理也是將html網(wǎng)頁通過后端服務(wù)導(dǎo)出成pdf,然后css設(shè)置break-after:always;作為分頁邏輯,但是我們不深入講,這里著重講前端生成pdf。

2、相關(guān)插件及知識

還是使用的老朋友jspdf插件和html2canvas

1、jspdf

"jspdf": "^2.5.1"

?使用方法:

import JsPDF from 'jspdf';

const PDF = new jsPDF({
  unit: "mm", // 單位,本示例為mm
  format: "a4", // 頁面大小
  orientation: "portrait", // 頁面方向,portrait: 縱向,landscape: 橫向
  putOnlyUsedFonts: true, // 只包含使用的字體
  compress: true, // 壓縮文檔
  precision: 16, // 浮點數(shù)的精度
});

// 或者

const PDF = new JsPDF('p', 'mm', [210, 297]);

<!-- 常用方法 -->
// 添加圖片
PDF.addImage(
  imageData, // 此值可以為下面這些類型 string | HTMLImageElement | HTMLCanvasElement | Uint8Array | RGBAData
  'JPEG', // 轉(zhuǎn)換后的格式
  x, // 被切割的imageData的橫坐標(biāo)
  y, // 被切割的imageData的縱坐標(biāo)
  w, // 當(dāng)前圖片的寬度
  h, // 當(dāng)前圖片的高度
);
// 添加新的一頁
PDF.addPage();
// 輸出格式
PDF.output(type: "arraybuffer"): ArrayBuffer;
PDF.output(type: "blob"): Blob;
PDF.output(type: "bloburi" | "bloburl"): URL;
// 本地保存為pdf文件
PDF.save('lindadayo.pdf')

2、html2canvas

"html2canvas": "^1.4.1"
// 實例方法   
html2canvas(dom, config).then(function(canvas) {})

?config相關(guān)配置參考下圖:【PDF】html/dom生成pdf,pdf

3、源碼

1、dom結(jié)構(gòu)

【PDF】html/dom生成pdf,pdf

2、核心邏輯

這里為什么要將dom進行分區(qū)處理呢?請看第四點疑難解答中1、為什么要對dom進行分區(qū)操作?

    /**
     * 生成pdf
     * @param CommonPage 需要轉(zhuǎn)換的dom節(jié)點
     * @param i 分區(qū)索引
     * @returns
     */
    async generatePdf(CommonPage?: Element, childLen?: number) {
      PDF = new JsPDF('p', 'mm', [210, 297]); // pdf實例
      for (let i = 0; i < childLen; i++) {
        await asyncSingleAreaControl(CommonPage, i)
      }
      generateUploadPdf();
    },
    /**
     * 上傳pdf文件
     */
    async generateUploadPdf() {
      // 文件重命名,修改生成pdf后的文件名
      const pdfName = pdfNameHandle()
      const uri = PDF.output('blob')
      const file = await blobUriToFile(uri, pdfName)
      // 此時的file是File類對象,你可以選擇上傳到服務(wù)器噢~當(dāng)然你也可以選擇直接導(dǎo)出到前端
      // PDF.output('lindadayo.pdf');
    },
    /**
     * 單個分區(qū)生成pdf操作
     * @param CommonPage 父節(jié)點dom
     * @param i 分區(qū)索引
     * @returns
     */
    async asyncSingleAreaControl(CommonPage, i) {
      const canvas = await singleHandle(CommonPage, i)
      await areaPage(canvas, i)
    },
    /**
     * 分區(qū)pdf處理
     * @param canvas 各個分區(qū)dom轉(zhuǎn)換后的canvas
     * @param areaNo 分區(qū)索引
     */
    areaPage(canvas, areaNo) {
      // 是否是第一個分區(qū)(作用于是否開始就addPage)
      const isFirstArea = areaNo === 0
      return new Promise((resolve, _reject) => {
        // a4紙寬高
        const A4Origin = {
          width: PDF.internal.pageSize.getWidth(),
          height: PDF.internal.pageSize.getHeight()
        }
        const contentWidth = canvas.width;
        /**
         * html2canvas放大3.125倍時精度丟失導(dǎo)致多了2像素
         * 3368: 高度285mm紙張html2canvas放大300dpi后像素
         * 3366:正常實際高度
         */
        const contentHeight = canvas.height <= 3368 ? 3366 : canvas.height;
        const pageHeight = Math.round(contentWidth / A4Origin.width * A4Origin.height);
        let leftHeight = contentHeight;
        let position = 0;
        const imgWidth = A4Origin.width;
        const imgHeight = Math.ceil(A4Origin.width / contentWidth * contentHeight);
        const pageData = canvas.toDataURL('image/jpeg', 1);
        // 非首個分區(qū),得先addPage,因為不然會少一頁 && 大于某個范圍才新增一頁,避免因為浮點數(shù)計算精度造成多增一頁
        if (!isFirstArea && leftHeight > 0) {
          PDF.addPage()
        }
        while (leftHeight > 0) {
          PDF.addImage(pageData, 'JPEG', 0, position, imgWidth + (isBrower() ? 0.62 : 0), imgHeight + (isBrower() ? 0.32 : 0));
          position -= A4Origin.height;
          leftHeight -= pageHeight
          // 大于某個范圍才新增一頁,避免因為浮點數(shù)計算精度造成多增一頁
          if (leftHeight > 0) {
            PDF.addPage()
          }
        }
        resolve(true)
      })
    },
    /**
     * 單頁pdf處理
    //  * @param root 總節(jié)點
     * @param index 分區(qū)索引
     */
    async singleHandle(CommonPage, index) {
      // 報錯Unable to find element in cloned iframe解決方法
      // getDiv在外部聲明, 內(nèi)部賦值
      try {
        getDiv = CommonPage.querySelector(`#CommonPageItemArea-${index}`)
        const res = await html2canvas(getDiv, {
          useCORS: true,
          allowTaint: true,
          scale: 3.125
        }).then(function(canvas) {
          return canvas
        })
        return res
      } catch (e) {
        console.log(e)
      }
    }

4、疑難解答

1、為什么要對dom進行分區(qū)操作?

其實如果你不使用html2canvas的參數(shù)scale,就沒必要進行分區(qū),但是在很多時候,你不放大canvas的話,會導(dǎo)致pdf中的圖片很模糊,還有鋸齒,所以要對canvas進行方法,但是放大后,會導(dǎo)致一些問題:生成pdf后,超過15000px以后的dom會有樣式丟失,所以得對dom進行分區(qū)操作,讓每個分區(qū)的dom高度 * 放大倍數(shù)不超過15000px。我們一般都會導(dǎo)出a4紙大小,a4紙寬高是210mm*297mm,換算成像素是793.29px * 1122.52px,如果你選擇放大兩倍,那么,單頁高度就是2245px,結(jié)論為一個分區(qū)能夠放六個a4紙高度的dom,所以你在開發(fā)頁面時,就要做好這種頁面結(jié)構(gòu)噢~

2、html2canvas仍然報圖片出錯/跨域的問題,即使后端oss已經(jīng)解決跨域了

報錯Error loading image

【PDF】html/dom生成pdf,pdf

這個涉及知識點:img標(biāo)簽實例化獲取屬于非跨域操作,Image類實例化屬于跨域操作,所以得再html2canvas依賴中打補丁,當(dāng)圖片是你本地的靜態(tài)圖片,那不需要轉(zhuǎn),還是按照Image實例化來做,當(dāng)圖片已經(jīng)是base64格式的話,也不需要轉(zhuǎn),賦值給img標(biāo)簽,否則的話加上隨機數(shù)。

/dist/html2canvas.js 第5759行

【PDF】html/dom生成pdf,pdf

3、報錯Unable to find element in cloned iframe解決方法

在分區(qū)中循環(huán)處理dom生成canvas時會報出這種錯誤,原因是html2canvas第一參數(shù)的變量應(yīng)該設(shè)置為全局變量而不應(yīng)該是局部變量

    try {
        getDiv = CommonPage.querySelector(`#CommonPageItemArea-${index}`)
        const res = await html2canvas(getDiv, {
          useCORS: true,
          allowTaint: true,
          scale: 3.125
        }).then(function(canvas) {
          return canvas
        })
        return res
      } catch (e) {
        console.log(e)
      }

4、dom-to-image和html2canvas相比,哪個更優(yōu)?

dom-to-image是一個js庫,可以將任意dom節(jié)點轉(zhuǎn)換為矢量(SVG)或光柵(PNG或JPEG)圖像。和html2canvas相比的話,算是一個新起之秀,更輕巧,相同點就是都會先將dom轉(zhuǎn)成canvas進行操作,所以在dom層級深和多的情況下,還是建議使用html2canvas這種老牌插件

5、生成pdf里圖片缺失

那是因為圖片轉(zhuǎn)換及獲取是異步的,需要時間渲染,所以生成pdf的步驟應(yīng)該在圖片完全加載完之后,由此我們可以加個定時器來循環(huán)判斷全部圖片是否加載完成,加載完成再進行生成操

    /**
     * CommonPage生成dom渲染完成
     * @param callback
     */
    commonPageLoadFinish(callback) {
      nextTick(() => {
        // 生成節(jié)點
        const CommonPage = document.querySelector('#CommonPage')
        const childLen = CommonPage.querySelectorAll('.CommonPageItemArea').length
        console.log('分區(qū)數(shù)量', childLen)
        if (childLen > 0) {
          let timer = null;
          // 監(jiān)聽頁面中所有轉(zhuǎn)base64圖片是否已生成完畢,如果已生成完畢,則進入下一步與dom相關(guān)的操作
          timer = setInterval(() => {
            // isImageAllCompleted.sum => 圖片總數(shù)量, isImageAllCompleted.loadSum => 目前圖片已經(jīng)加載完的數(shù)量
            if (isImageAllCompleted.sum === isImageAllCompleted.loadSum) {
              clearInterval(timer)
              timer = null
              callback(CommonPage, childLen)
            }
          }, 1000)
        }
      })
    }

將生成pdf步驟作為回調(diào)函數(shù)放在上述函數(shù)里

commonPageLoadFinish(generatePdf)

?那在組件中如何監(jiān)聽圖片是否加載完成呢?按照以下代碼來寫

    onMounted(() => {
      nextTick(() => {
        // commonRef.value 為某dom的refs
        // 被動檢測是否有圖片, 無則直接進入主邏輯
        const img = commonRef.value.querySelectorAll('img');
        if (!img.length) return methods.successCallback();
        let imgSum = 0;
        asyncImgCompLoad(img).then((res) => {
          res.forEach(() => imgSum++);
          // 設(shè)置圖片總數(shù)量和加載數(shù)量
          setImageAllCompleted({ sum: isImageAllCompleted.sum + img.length, loadSum: imgSum + isImageAllCompleted.loadSum });
        })
      })
    })


    async asyncImgCompLoad(imgList) {
        const promiseList = []
        for await (const item of imgList) {
          promiseList.push(new Promise((res, rej) => {
            // 參數(shù)沒有被賦值
            if (!item.src) {
              rej(false)
            }
            if (item.complate) {
              res(true)
            } else {
              item.addEventListener('load', () => {
                res(true)
              })
              // 圖片被賦值,但是賦的是錯誤的值
              item.addEventListener('error', () => {
                rej(false)
              })
            }
          }))
        }
        return Promise.allSettled(promiseList)
      }

?6、生成的pdf里,單頁底部有白邊?

在使用PDFjs插件時候,加入需要導(dǎo)出a4紙大小,那么很多童鞋就會將寬高固定設(shè)置為210mm, 297mm,但是實際上不是整數(shù),是小數(shù),所以獲取時按照下述方法獲取

        // a4紙寬高
        const A4Origin = {
          width: PDF.internal.pageSize.getWidth(),
          height: PDF.internal.pageSize.getHeight()
        }

PDF分頁核心源碼

        // a4紙寬高
        const A4Origin = {
          width: PDF.internal.pageSize.getWidth(),
          height: PDF.internal.pageSize.getHeight()
        }
        const contentWidth = canvas.width;
        /**
         * html2canvas放大3.125倍時精度丟失導(dǎo)致多了2像素
         * 3368: 高度285mm紙張html2canvas放大300dpi后像素
         * 3366:正常實際高度
         */
        const contentHeight = canvas.height <= 3368 ? 3366 : canvas.height;
        const pageHeight = Math.round(contentWidth / A4Origin.width * A4Origin.height);
        let leftHeight = contentHeight;
        let position = 0;
        const imgWidth = A4Origin.width;
        const imgHeight = Math.ceil(A4Origin.width / contentWidth * contentHeight);
        const pageData = canvas.toDataURL('image/jpeg', 1);
        // 非首個分區(qū),得先addPage,因為不然會少一頁 && 大于某個范圍才新增一頁,避免因為浮點數(shù)計算精度造成多增一頁
        if (!isFirstArea && leftHeight > 0) {
          PDF.addPage()
        }
        while (leftHeight > 0) {
          PDF.addImage(pageData, 'JPEG', 0, position, imgWidth + (isBrower() ? 0.62 : 0), imgHeight + (isBrower() ? 0.32 : 0));
          position -= A4Origin.height;
          leftHeight -= pageHeight
          // 大于某個范圍才新增一頁,避免因為浮點數(shù)計算精度造成多增一頁
          if (leftHeight > 0) {
            PDF.addPage()
          }
        }

?有兩個地方可能童鞋們沒看懂,1、首先為啥非首個分區(qū),得先addPage呢?因為PDF默認(rèn)就有一頁,所以你能夠直接addImage而不出錯,然后后續(xù)PDF想要新增一頁,都得先addPage,這時候默認(rèn)背景顏色是白色的,然后再將canvas轉(zhuǎn)成圖片,貼到這白板上的,所以你看到PDF文檔里有白邊,那毫無疑問,就是貼的圖片沒占完那一頁,并且火狐瀏覽器和谷歌瀏覽器還有一些細(xì)微的差別所以你這就得一點一點微調(diào)來達(dá)到最佳顯示效果。2、為啥addIMage時,里面?zhèn)鞯膮?shù)不同呢?

PDF.addImage(pageData, 'JPEG', 0, position, imgWidth + (isBrower() ? 0.62 : 0), imgHeight + (isBrower() ? 0.32 : 0));

?這就是瀏覽器差異問題,火狐瀏覽器不僅底部有白邊,側(cè)面也有白邊,相比之下谷歌要更兼容一些。

?7、pdf生成的File文件對象,想要先傳入oss,再通過服務(wù)端下載怎么實現(xiàn)?

這其實就涉及到大文件上傳技術(shù)了,因為pdf稍微大點可能都上百M,一般都不會一次性上傳完的,所以得做切片上傳,然后在服務(wù)端合并上傳到oss,最后將oss路徑地址返回給前端,前端通過這地址去下載。當(dāng)然具體的大文件上傳我就不寫在這篇博客了,下一篇博客我將著重講大文件上傳如何寫噢~

8、vue-fragment插件配合html2canvas使用有問題?

在@vue/composition-api環(huán)境下開發(fā),想使用fragment就得使用vue-fragment插件,但是搭配上html2canvas導(dǎo)出canvas會出現(xiàn)bug,就是只會渲染第一個fragment標(biāo)簽的dom,其他的都不會渲染,目前還是建議在@vue/composition-api環(huán)境下不使用fragment

--- 有問題可以隨時評論噢~喜歡的請點贊收藏啦 ---文章來源地址http://www.zghlxwxcb.cn/news/detail-563441.html

到了這里,關(guān)于【PDF】html/dom生成pdf的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • Flying HTML生成PDF添加水印

    HTML轉(zhuǎn)PDF并添加水印

    2024年01月22日
    瀏覽(25)
  • Java HTML生成PDF(格式不變)

    Java HTML生成PDF(格式不變)

    Java是大規(guī)模和企業(yè)級應(yīng)用程序最常用的編程語言之一。PDF 格式代表可移植文檔格式,為人們提供了一種簡單、可靠的方式來呈現(xiàn)和交換文檔 - 無論查看文檔的任何人使用何種軟件、硬件或操作系統(tǒng)。因此,pdf 是一種廣泛使用的格式,用于在軟件應(yīng)用程序中生成文檔。 HTML 用

    2024年02月12日
    瀏覽(19)
  • 【jspdf】前端html生成pdf的兩種辦法 以及 引入中文字體

    【jspdf】前端html生成pdf的兩種辦法 以及 引入中文字體

    1、使用canvas把html生成圖片,然后使用jspdf生成pdf。優(yōu)點:生成的pdf 樣式還原度極高,缺點:圖片形式的pdf無法編輯 2、直接使用jspdf的html方法直接把html生成pdf。優(yōu)點:可編輯,缺點:只是把文本內(nèi)容摟出來生成pdf,也就是說樣式基本無,而且jspdf不支持中文字體的,如果有中

    2024年02月10日
    瀏覽(23)
  • 3D數(shù)據(jù)導(dǎo)出工具HOOPS Publish:3D數(shù)據(jù)查看、生成標(biāo)準(zhǔn)PDF或HTML文檔!

    3D數(shù)據(jù)導(dǎo)出工具HOOPS Publish:3D數(shù)據(jù)查看、生成標(biāo)準(zhǔn)PDF或HTML文檔!

    HOOPS中文網(wǎng) http://techsoft3d.evget.com/ 一、3D導(dǎo)出SDK HOOPS Publish是一款功能強大的SDK,可以創(chuàng)作豐富的工程數(shù)據(jù)并將模型文件導(dǎo)出為各種行業(yè)標(biāo)準(zhǔn)格式,包括PDF、STEP、JT和3MF。HOOPS Publish核心的3D數(shù)據(jù)模型是經(jīng)過ISO認(rèn)證的PRC格式(ISO 14739-1:2014),它為裝配樹、拓?fù)浜蛶缀?、產(chǎn)品制造信息

    2024年02月10日
    瀏覽(26)
  • itextpdf7 使用之 html轉(zhuǎn)pdf,生成目錄可跳轉(zhuǎn)、添加頁眉頁腳

    itextpdf7 使用之 html轉(zhuǎn)pdf,生成目錄可跳轉(zhuǎn)、添加頁眉頁腳

    最近有個需求,生成信用報告。 需求: 1、生成pdf有頁眉頁腳 2、生成目錄 3、目錄加錨點可跳轉(zhuǎn)。 難點: 1、生成的目錄不能實時讀取頁碼 2、目錄是后生成的,屬于兩份pdf拼接的,不能添加錨點跳轉(zhuǎn) 思路: 1、freemaker進行html頁面布局及動態(tài)變量替換 2、生成一份pdf文檔,用

    2024年02月20日
    瀏覽(18)
  • 【Java】itext 實現(xiàn) html根據(jù)模板生成pdf 中文不顯示/圖片不顯示問題解決

    【Java】itext 實現(xiàn) html根據(jù)模板生成pdf 中文不顯示/圖片不顯示問題解決

    工作中需要使用生成pdf記錄,選取使用的是itext 生成 pdf方式。分享下實現(xiàn)方式及遇到的問題。 這里隨便找個html課程表作為示例,添加了幾張圖片為了展示圖片轉(zhuǎn)pdf功能。 一:引入jar包 二:導(dǎo)入ftl文件 這塊使用的是html語法,將文件后綴名改為ftl即可,在需要參數(shù)的地方通過

    2024年02月05日
    瀏覽(24)
  • vue2如何將頁面生成 pdf 導(dǎo)出 html2Canvas + jspdf

    vue2如何將頁面生成 pdf 導(dǎo)出 html2Canvas + jspdf

    npm i html2canvas npm i jspdf import html2canvas from \\\'html2canvas\\\'; import jsPDF from \\\'jspdf\\\' export const htmlToPDF = async (htmlId, title = \\\"報表\\\", bgColor = \\\"#fff\\\") = { ? let pdfDom = document.getElementById(htmlId) ? pdfDom.style.padding = \\\'0 10px !important\\\' ? const A4Width = 595.28; ? const A4Height = 841.89; ? let canvas = await html2canvas(pd

    2024年02月16日
    瀏覽(24)
  • (vue)Vue項目中使用jsPDF和html2canvas生成PDF

    (vue)Vue項目中使用jsPDF和html2canvas生成PDF

    效果: 1.:安裝jsPDF和html2canvas 2.在需要生成PDF文檔的組件中引入jsPDF和html2canvas 解決參考: 1.https://www.jianshu.com/p/31d37bef539b 2.https://www.php.cn/faq/556634.html 3.https://blog.csdn.net/m0_54967474/article/details/123820384

    2024年02月10日
    瀏覽(22)
  • 前端生成pdf之html2canvas+jsPDF,以及解決圖片不顯示bug

    開發(fā)背景: 需要給頁面中相應(yīng)的內(nèi)容生成pdf,查找文檔后發(fā)現(xiàn)要用到兩個插件。html2canvas 以及 jsPDF html2canvas 給dom結(jié)構(gòu)轉(zhuǎn)化為canvas,然后生成各種類型圖片 jsPDF 把canvas 生成的圖片url 轉(zhuǎn)化為pdf 參數(shù) image:表示要插入的圖片資源,可以是圖片文件的路徑或者base64編碼字符串。

    2024年02月02日
    瀏覽(28)
  • 【無標(biāo)題】使用html2canvas和jspdf生成的pdf在不同大小的屏幕下文字大小不一樣

    【無標(biāo)題】使用html2canvas和jspdf生成的pdf在不同大小的屏幕下文字大小不一樣

    問題:使用html2canvas和jspdf生成的pdf在不同大小的屏幕下文字大小不一樣,在mac下,一切正常,看起來很舒服,但是當(dāng)我把頁面放在擴展屏幕下(27寸),再生成一個pdf,雖然排版一樣,但是文字就變得非常小 下面的是在mac下的,上面是在擴展屏幕下的,最開始我以為是文字大

    2024年02月16日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包