<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          在上傳前用JavaScript壓縮圖片

          共 10843字,需瀏覽 22分鐘

           ·

          2023-08-22 18:35

          在這個(gè)快速教程中,我們將使用JavaScript壓縮帶有文件輸入元素的圖像。我們將壓縮圖像并將它們保存回文件輸入,以便上傳。

          為了確保用戶可以上傳圖片,并防止超大圖片被上傳,我們可以在上傳前壓縮圖片數(shù)據(jù),而不必向用戶提出各種要求。

          如果您趕時(shí)間,或者覺(jué)得閱讀代碼本身更方便,可以跳轉(zhuǎn)到這里的最終代碼片段[1]

          獲取選定的圖像文件

          在下面的示例中,我們將接受所有類型的文件,但只壓縮圖像。multiple 屬性允許選擇多個(gè)文件。

          為了防止添加其他文件,我們可以將文件輸入接受屬性設(shè)置為 image/*

          讓我們?cè)O(shè)置一個(gè)文件輸入框,當(dāng)用戶選擇了一個(gè)或多個(gè)文件時(shí),我們將偵聽(tīng) change 來(lái)檢測(cè)。我們將在下一節(jié)處理 TODO 項(xiàng)目。

          <input type="file" multiple class="my-image-field" />

          <script>
              // 從文件輸入中獲取所選文件
              const input = document.querySelector('.my-image-field');
              input.addEventListener('change', (e) => {
                  // 獲取文件
                  const { files } = e.target;

                  // 未選定文件
                  if (!files.length) return;

                  // 對(duì)于文件列表中的每個(gè)文件
                  for (const file of files) {
                      // 我們不必壓縮非圖像文件
                      if (!file.type.startsWith('image')) {
                          // TODO: 不是圖像
                      }

                      // TODO: 壓縮圖像
                  }

                  // TODO: 儲(chǔ)存文件
              });
          </script>

          現(xiàn)在,當(dāng)用戶選擇一個(gè)或多個(gè)圖像文件時(shí),我們的代碼就會(huì)運(yùn)行。接下來(lái)是壓縮圖像。

          壓縮圖像

          我們將實(shí)現(xiàn) compressImage 函數(shù)。該函數(shù)將把傳遞的文件對(duì)象轉(zhuǎn)換為 ImageBitmap,并將其繪制到 <canvas> 元素中,然后畫(huà)布將使用  toBlob[2] API 返回壓縮后的 JPEG。

          請(qǐng)注意,我們也可以要求WEBP,但這(在撰寫(xiě)本文時(shí))在 Safari 上不支持???♂?

          讓我們開(kāi)始吧。

          <input type="file" multiple class="my-image-field" />

          <script>
              const compressImage = async (file, { quality = 1, type = file.type }) => {
                  // 獲取圖像數(shù)據(jù)
                  const imageBitmap = await createImageBitmap(file);

                  // 繪制到畫(huà)布上
                  const canvas = document.createElement('canvas');
                  canvas.width = imageBitmap.width;
                  canvas.height = imageBitmap.height;
                  const ctx = canvas.getContext('2d');
                  ctx.drawImage(imageBitmap, 00);

                  // 變成Blob
                  return await new Promise((resolve) =>
                      canvas.toBlob(resolve, type, quality)
                  );
              };

              // 從文件輸入中獲取所選文件
              const input = document.querySelector('.my-image-field');
              input.addEventListener('change'async (e) => {
                  // 獲取文件
                  const { files } = e.target;

                  // 未選擇文件
                  if (!files.length) return;

                  // 對(duì)于文件列表中的每個(gè)文件
                  for (const file of files) {
                      // 我們不必壓縮非圖像文件
                      if (!file.type.startsWith('image')) {
                          // TODO: 不是圖像
                      }

                      // 我們將文件壓縮 50%
                      const compressedFile = await compressImage(file, {
                          // 0: 為最大壓縮率
                          // 1: 沒(méi)有壓縮
                          quality0.5,

                          // 我們想要一個(gè) JPEG 文件
                          type'image/jpeg',
                      });
                  }

                  // TODO: 儲(chǔ)存文件
              });
          </script>

          現(xiàn)在,compressedFile 變量將包含壓縮后的圖像文件。

          接下來(lái)就是將壓縮后的圖像文件(以及忽略的文件)保存回文件輸入端。

          將壓縮圖像保存回文件輸入端

          我們將創(chuàng)建一個(gè) DataTransfer 對(duì)象,用它來(lái)創(chuàng)建我們的新文件列表。之后,我們可以將該列表保存回文件輸入端

          DataTransfer 對(duì)象只接受 File 對(duì)象,因此我們需要將 Blob 轉(zhuǎn)換為文件,讓我們更新 compressImage 函數(shù)。

          <input type="file" multiple class="my-image-field" />

          <script>
              const compressImage = async (file, { quality = 1, type = file.type }) => {
                  // 獲取圖像數(shù)據(jù)
                  const imageBitmap = await createImageBitmap(file);

                  // 繪制到畫(huà)布上
                  const canvas = document.createElement('canvas');
                  canvas.width = imageBitmap.width;
                  canvas.height = imageBitmap.height;
                  const ctx = canvas.getContext('2d');
                  ctx.drawImage(imageBitmap, 00);

                  // 變成Blob
                  const blob = await new Promise((resolve) =>
                      canvas.toBlob(resolve, type, quality)
                  );

                  // 將 Blob 變?yōu)?nbsp;File
                  return new File([blob], file.name, {
                      type: blob.type,
                  });
              };

              // 從文件輸入中獲取所選文件
              const input = document.querySelector('.my-image-field');
              input.addEventListener('change'async (e) => {
                  // 獲取文件
                  const { files } = e.target;

                  // 未選擇文件
                  if (!files.length) return;

                  // 對(duì)于文件列表中的每個(gè)文件
                  for (const file of files) {
                      // 我們不必壓縮非圖像文件
                      if (!file.type.startsWith('image')) {
                          // TODO: 不是圖像
                      }

                      // 我們將文件壓縮 50%
                      const compressedFile = await compressImage(file, {
                          // 0: 為最大壓縮率
                          // 1: 沒(méi)有壓縮
                          quality0.5,

                          // 我們想要一個(gè) JPEG 文件
                          type'image/jpeg',
                      });

                      // 保存壓縮文件而不是原始文件
                      dataTransfer.items.add(compressedFile);
                  }

                  // 將文件輸入值設(shè)置為我們的新文件列表
                  e.target.files = dataTransfer.files;
              });
          </script>

          總結(jié)

          我們已經(jīng)學(xué)會(huì)了如何使用 canvas 和 DataTransfer 來(lái)設(shè)置一個(gè)不起眼的小腳本,幫助我們?cè)谏蟼髑皦嚎s圖片。該腳本將使我們的用戶更容易上傳圖片。

          當(dāng)然,我們還有很多需要改進(jìn)的地方,例如,我們可以

          • 調(diào)整圖像大小以適應(yīng)最大邊界框。

          • 將圖像裁剪成一定的長(zhǎng)寬比。

          • 更好地處理錯(cuò)誤輸入并顯示合適的錯(cuò)誤信息。

          • 確保我們能處理 Safari 內(nèi)存問(wèn)題。

          如果我們需要一個(gè)更強(qiáng)大的解決方案,我們可以使用 FilePond[3] 來(lái)處理文件上傳,它可以調(diào)整圖像大小、壓縮等。

          如果我們需要更多的控制,我們可以使用 Pintura[4] 讓用戶在上傳前編輯圖片,Pintura 也可以直接替代我們的 compressImage 功能。


          原文:https://pqina.nl/blog/compress-image-before-upload

          參考資料

          [1]

          跳轉(zhuǎn)到這里的最終代碼片段: https://pqina.nl/blog/compress-image-before-upload#saving-the-compressed-image-back-to-the-file-input

          [2]

          toBlob: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob

          [3]

          FilePond: https://pqina.nl/filepond/

          [4]

          Pintura: https://pqina.nl/pintura/

          瀏覽 311
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人人摸在线观看 | 天天艹天天日天天干 | 一线二线精品视频在线 | 婷婷国产无码 | 久久人妖TS三区系列电影 |