iT邦幫忙

0

jsPDF 自定義截圖順序

  • 分享至 

  • xImage

想請問一下,我今天想使用 jsPDF 搭配 html2canvas 去實現螢幕截圖,並下載下來

目前程式碼中有 divToPrint 跟 divToPrint2 兩個 element 是需要被下載的部分,不過我希望在畫面中 divToPrint 是在 divToPrint2 前面,到了下載時反過來

請問如何同時下載這兩個 element(不在外層包一個 id),然後並讓他們下載順序顛倒?

   const printDocument = () => {
    const input = document.querySelector("#divToPrint");
    html2canvas(input).then((canvas) => {
      const input2 = document.querySelector("#divToPrint2");
      html2canvas(input2).then((canvass) => {
        const imgData = canvass.toDataURL("image/png");
        const imgData2 = canvass.toDataURL("image/png");
        const pdf = new jsPDF();
        pdf.addImage(imgData2, "JPEG", 0, 0);
        pdf.addImage(imgData, "JPEG", 0, 0);
        pdf.save("download.pdf");
      })
    });
  };


  return (
    <div className="App">
      <div>
        <div className="mb5">
          <button onClick={printDocument}>Print</button>
        </div>
        <div id="divToPrint" className="mt4">
          <div>Note: Here the dimensions of div are same as A4</div>
          <div>You Can add any component here</div>
        </div>
        <div id="divToPrint2" className="mt4">
          <div>Note: Here the dimensions of div are same as A4444</div>
          <div>You Can add any component hereeee</div>
        </div>
      </div>
    </div>
看更多先前的討論...收起先前的討論...
淺水員 iT邦大師 6 級 ‧ 2023-09-12 12:17:19 檢舉
下載順序顛倒?
你的程式不是只會下載一次嗎?
要做成兩個PDF依序下載?
janlin002 iT邦好手 1 級 ‧ 2023-09-12 13:46:21 檢舉
希望下載的順序跟畫面上的順序顛倒
淺水員 iT邦大師 6 級 ‧ 2023-09-12 13:55:15 檢舉
所以是要做成兩個 pdf
每個 pdf 只有一張圖片
然後依序下載這兩個 pdf
只是順序是從後面往前面?
janlin002 iT邦好手 1 級 ‧ 2023-09-12 14:03:21 檢舉
沒錯~~
淺水員 iT邦大師 6 級 ‧ 2023-09-12 18:45:12 檢舉
有考慮把所有pdf打包成zip檔讓使用者下載嗎?
因為一個按鈕觸發多次下載可能瀏覽器會有不同的行為
例如chrome會詢問使用者是否同意
janlin002 iT邦好手 1 級 ‧ 2023-09-12 20:32:27 檢舉
目前沒有考慮,只考慮透過套件組成pdf,然後直接下載
你先用array 排序好在產生dom,所謂同時應該只是連續觸發下載吧?
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

0
bizpro
iT邦大師 1 級 ‧ 2023-09-12 10:08:37

有兩個問題:

  1. DataURL是image/png, 但addImage卻是JPEG, 應改為PNG
const imgData = canvass.toDataURL("image/png");

pdf.addImage(imgData2, "JPEG", 0, 0);
  1. 兩個圖重疊在0,0
pdf.addImage(imgData2, "JPEG", 0, 0);
pdf.addImage(imgData, "JPEG", 0, 0);

應該分開一段距離:

pdf.addImage(imgData2, "JPEG", 0, 0);
pdf.addImage(imgData, "JPEG", 0, 100);

問題是, 這個距離可能會因為瀏覽器和解析度不同而產生間隔與誤差. 當然,您也可以計算imgData2的高度來自動調整, 只是要先等imgData2完成才可以計算. 另外, 在您的程式碼中, 您用了兩個promises套在一起, then+then. 建議用async/await分開來同步處理.

const printDocument = async () => {
  try {
    const input1 = document.querySelector("#divToPrint");
    const input2 = document.querySelector("#divToPrint2");
    
    const canvas2 = await html2canvas(input2);
    const imgData2 = canvas2.toDataURL("image/png");

    const canvas1 = await html2canvas(input1);
    const imgData1 = canvas1.toDataURL("image/png");

		//先產生img2
    const img2 = new Image();
    img2.src = imgData2;

    //等候img2完成後才計算
    img2.onload = () => {
      // 計算高度
      const img2Height = img2.height;

      // 產生pdf
      const pdf = new jsPDF();
      pdf.addImage(imgData2, "PNG", 0, 0);
      pdf.addImage(imgData1, "PNG", 0, img2Height);

      pdf.save("download.pdf");
    };
  } catch (error) {
    console.error("Error generating PDF: ", error);
  }
};

bizpro iT邦大師 1 級 ‧ 2023-09-13 14:38:37 檢舉

原來是分開兩個PDF:

const downloadAsPDF = async (selector, fileName) => {
  try {
  	const element = document.querySelector(selector);
    const canvas = await html2canvas(element);
    const imgData = canvas.toDataURL("image/png");

    const pdf = new jsPDF();
    pdf.addImage(imgData, "PNG", 0, 0);
    pdf.save(fileName);
  } catch (error) {
    console.error("Error generating PDF: ", error);
  }
};

const printDocument = async (ms=2000) => {
  await downloadAsPDF("#divToPrint2", "download2.pdf");
  await new Promise(r => setTimeout(r, ms));
  await downloadAsPDF("#divToPrint", "download1.pdf");
};

加入一個等候的時間, 預設2000ms, 以減少瀏覽器處理連續下載可能的問題:
await new Promise(r => setTimeout(r, ms));

0
淺水員
iT邦大師 6 級 ‧ 2023-09-13 00:43:03

要分成兩個檔案下載的話
下面是一個做法
但不同瀏覽器對於單一點擊事件觸發多次下載可能有不同的處理方式
不保證所有瀏覽器都一樣,這部分再看怎麼處理了

/**
 * @param {string} selector CSS 選擇器的字串
 * @param {string} filename 預設輸出檔名
 */
const downloadPdf = async (selector, filename) => {
    const element = document.querySelector(selector);
    const canvas = await html2canvas(element);
    const pdf = new jsPDF();
    pdf.addImage(canvas, "JPEG", 0, 0);
    pdf.save(filename);
}

const printDocument = async () => {
    await downloadPdf("#divToPrint2", "02.pdf");
    await downloadPdf("#divToPrint", "01.pdf");
};

我要發表回答

立即登入回答