切換語言為:簡體

利用 HTML5 的 Canvas 實現影象水印和壓縮

  • 爱糖宝
  • 2024-06-02
  • 2066
  • 0
  • 0

壓縮和水印

在現代網路應用中,影象處理是一項重要的任務,尤其是在需要展示使用者上傳的圖片時。但是,經常會面臨兩個主要問題:影象大小和影象安全。一方面,大尺寸的圖片會增加載入時間,降低使用者體驗,另一方面,保護圖片免受盜用或篡改是至關重要的。

在本文中,我們將討論如何透過前端技術來解決這些問題,具體而言,我們將關注影象的壓縮和水印新增。

影象壓縮

大多數現代瀏覽器都支援HTML5的<canvas>元素,它可以在客戶端進行影象處理。我們可以利用這個特性來壓縮使用者上傳的圖片。

程式碼分析:

/**
 * 將影象檔案壓縮以減小其大小。
 * @param {File} file - 要壓縮的影象檔案。
 * @param {number} maxSizeMB - 壓縮後圖像的最大大小,以兆位元組為單位。
 * @returns {Promise<File>} 一個解析為壓縮後圖像檔案的 Promise。
 */
compressImage(file, maxSizeMB) {
  return new Promise((resolve, reject) => {
    let reader = new FileReader();

    reader.onload = function () {
      let img = new Image();

      img.onload = function () {
        let canvas = document.createElement("canvas");
        let ctx = canvas.getContext("2d");
        let maxSizeBytes = maxSizeMB * 1024 * 1024;
        let scaleFactor = 0.5;

        if (file.size > maxSizeBytes) {
          scaleFactor = Math.min(
            scaleFactor,
            Math.sqrt(maxSizeBytes / file.size)
          ); // 計算縮放比例,保持寬高比
        }

        canvas.width = img.width * scaleFactor;
        canvas.height = img.height * scaleFactor;
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

        canvas.toBlob(
          (blob) => {
            const compressedFile = new File([blob], file.name, {
              type: file.type,
              lastModified: Date.now(),
            });
            resolve(compressedFile);
          },
          file.type,
          0.8 // 設定壓縮質量引數為 0.8
        );
      };

      img.onerror = reject;

      img.src = reader.result;
    };

    reader.onerror = reject;

    reader.readAsDataURL(file);
  });
},


這段程式碼實現了一個compressImage函式,它接受一個影象檔案和最大允許大小作為引數,並返回一個Promise物件,解析為壓縮後的影象檔案。主要步驟包括:

  • 使用FileReader物件讀取檔案內容。

  • 將檔案內容載入到<img>元素中。

  • 建立一個新的<canvas>元素,並將影象繪製到畫布上。

  • 根據影象大小和指定的最大大小,計算壓縮比例。

  • 將繪製後的影象資料轉換為Blob物件,並返回壓縮後的檔案。

影象水印

爲了標識圖片的來源和保護版權,我們通常會新增水印。在本文中,我們使用HTML5的<canvas>元素來實現水印效果。

程式碼分析:

/**
 * 新增水印到圖片
 * @param {File} file 圖片檔案
 * @param {string} gasName 油站名稱
 * @param {string} location 地址
 * @returns {Promise<Blob>} 返回新增水印後的 Blob 物件
 */
addWatermarkToImage(file, gasName, location) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.src = URL.createObjectURL(file);

    img.onload = () => {
      const canvas = document.createElement("canvas");
      const ctx = canvas.getContext("2d");

   
      const watermarkWidthPercentage = 0.9;

      canvas.width = img.width;
      canvas.height = img.height;

      ctx.drawImage(img, 0, 0);

     
      ctx.fillStyle = "rgba(0, 0, 0, 0.2)";
      ctx.fillRect(0, 0, canvas.width, canvas.height);

     
      const watermarkWidth = canvas.width * watermarkWidthPercentage;
      const watermarkX = (canvas.width - watermarkWidth) / 2; 

      const currentDate = new Date();
      const timeString = currentDate.toLocaleTimeString([], {
        hour: "2-digit",
        minute: "2-digit",
      });

      
      const dateString = currentDate.toLocaleDateString();
      const dayOfWeek = new Intl.DateTimeFormat("en-US", {
        weekday: "long",
      }).format(currentDate);
      CanvasUtils.drawText(
        ctx,
        `${dateString} ${dayOfWeek} ${timeString}`,
        CanvasUtils.calculateFontSize(watermarkWidth),
        CanvasUtils.calculateFontSize(watermarkWidth) * 2,
        watermarkX + watermarkWidth / 2
      );

     
      CanvasUtils.drawText(
        ctx,
        gasName,
        CanvasUtils.calculateFontSize(watermarkWidth),
        CanvasUtils.calculateFontSize(watermarkWidth) * 3.5,
        watermarkX + watermarkWidth / 2
      );

   
      CanvasUtils.drawText(
        ctx,
        location,
        CanvasUtils.calculateFontSize(watermarkWidth),
        CanvasUtils.calculateFontSize(watermarkWidth) * 5,
        watermarkX + watermarkWidth / 2
      );

      canvas.toBlob((blob) => {
        resolve(blob);
      }, file.type);
    };

    img.onerror = (error) => {
      reject(error);
    };
  });
},


這段程式碼實現了一個addWatermarkToImage函式,它接受一個圖片檔案和水印資訊作為引數,並返回一個Promise物件,解析為新增水印後的Blob物件。主要步驟包括:

  • 載入圖片並繪製到畫布上。

  • 繪製一個半透明的矩形作為背景。

  • 在背景上新增日期、時間、油站名稱和地址等資訊。

  • 將繪製後的影象資料轉換為Blob物件,並返回新增水印後的檔案。

結論

透過前端技術,我們可以輕鬆地實現影象壓縮和水印新增功能,從而改善使用者體驗和保護影象安全。本文提供了核心的程式碼分析和實現,希望能夠幫助讀者更好地理解影象處理的實現原理和技術細節。 完整程式碼:github.com/itc-1118/im…

效果

利用 HTML5 的 Canvas 實現影象水印和壓縮

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.