壓縮和水印
在現代網路應用中,影象處理是一項重要的任務,尤其是在需要展示使用者上傳的圖片時。但是,經常會面臨兩個主要問題:影象大小和影象安全。一方面,大尺寸的圖片會增加載入時間,降低使用者體驗,另一方面,保護圖片免受盜用或篡改是至關重要的。
在本文中,我們將討論如何透過前端技術來解決這些問題,具體而言,我們將關注影象的壓縮和水印新增。
影象壓縮
大多數現代瀏覽器都支援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…