国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > JS > 正文

使用 Node.js 實現圖片的動態裁切及算法實例代碼詳解

2024-05-06 16:46:15
字體:
來源:轉載
供稿:網友

背景&概覽

目前常見的圖床服務都會有圖片動態裁切的功能,主要的應用場景用以為各種終端和業務形態輸出合適尺寸的圖片。

一張動輒以 MB 為計量單位的原始大圖,通常不會只設置一下顯示尺寸就直接輸出到終端中,因為體積太大加載體驗會很差,除了影響加載速度還會增加終端設備的內存占用。所以要想在各種終端下都能保證圖片質量的同時又確保輸出合適的尺寸,那么此時就需要根據圖片 URL 來對原始圖片進行裁切,然后動態生成并輸出一張新的圖片。

URL 的設計

圖片 URL 需要包含圖片 id、尺寸、質量等信息。有兩種類型的圖片 URL,分別是原圖 URL 和帶動態裁切信息的 URL。

// 原圖 URLhttp://example.com/$imgId// 帶裁切信息的圖片 URLhttp://example.com/$cropType/$width_$height_$quality/$imgId

來分析一下上面 URL 中的變量:

  • $imgId
  • $cropType
  • $width
  • $height
  • $quality

那么一張圖片 id 為 4b2d4edcc1f82452 的原圖 URL 應該是:

http://example.com/4b2d4edcc1f82452.jpg

如果想要一張該圖 800×600 的版本,裁切的 URL 大致是下面這樣的:

http://example.com/es/800_600_/4b2d4edcc1f82452.jpg

裁切算法

該來說說以上 URL 背后的算法了。在 Node.js 中可以使用著名的圖片裁切庫 GM ,該庫是基于 imagemagick 和 graphicsmagick 底層庫的封裝。

最常見的裁切算法是等比例裁切,等比裁切的算法需要至少給出裁切目標圖片的寬度和高度的其中一個,如果圖片限寬就給出寬度,限高就給出高度,如果兩個參數都有,就需要確保裁切的目標寬高相對于原始的寬高是按比例計算的,否則裁切的結果就會出現拉伸。

var gm = require('gm');// 裁切的最小尺寸var minSize = 48;var defaultQuality = 90;/** * 等比例縮放 equal scaling * @param { String } 原文件路徑 * @param { String } 新文件路徑 * @param { String } 縮放規則 * @return { promise } */var es = function(src, dest, rules) {  return new Promise(function(resolve, reject) {    // 900_600_90 => 寬度900/高度600/品質90    rules = rules.split('_');    if (rules.length !== 3) {      return reject(new Error('Resize rules invalid'));    }    // 解析裁切的目標寬高    let resizeWidth = parseInt(rules[0]);    let resizeHeight = parseInt(rules[1]);    let quality = parseInt(rules[2]) || defaultQuality;    const readStream = fs.createReadStream(src);    const writeStream = fs.createWriteStream(dest);    gm(readStream)      .size({        bufferStream: true      }, function(err, size) {        if (err) {          return reject(err);        }        const origWidth = size.width;        const origHeight = size.height;        let resizeResult;        // 縮放的寬度和高度做最大最小值限制        if (resizeWidth) {          if (resizeWidth > origWidth * 1.5) {            resizeWidth = Math.floor(origWidth * 1.5);          }          else if (resizeWidth < minSize) {            resizeWidth = minSize;          }        }        if (resizeHeight) {          if (resizeHeight > origHeight * 1.5) {            resizeHeight = Math.floor(origHeight * 1.5);          }          else if (resizeHeight < minSize) {            resizeHeight = minSize;          }        }        resizeResult = this.resize(resizeWidth, resizeHeight);        resizeResult          .quality(quality)          .interlace('line') // 使用逐行掃描方式          .unsharp(2, 0.5, 0.5, 0)          .stream()          .on('end', resolve)          .pipe(writeStream);      });  });};

說說幾個重要的 API:

quality 設置圖片的質量,GM 圖片質量范圍是 0-100,默認的質量是 75。
interlace 用于設置圖片在顯示器上加載時的顯示方式,當然顯示方式本身還要受圖片本身的影響。
unsharp 用來設置圖片的銳度,將一張大圖縮放成一張小圖時,會損失很多像素,需要適當的增加圖片銳度來保證圖片的質量。關于 unsharp 的使用,詳見 Using ImageMagick to make sharp web-sized photographs 。
等比例裁切嚴格來說實際上還只是對圖片進行縮放,并未動用圖片裁切的 API。

還有一種比較常見的裁切方式,會先將圖片等比例縮放后再從中心裁切,裁切出來的圖片是一個正方形,這樣能盡可能保證圖片的內容。

/* * 等比例縮放后從中心裁切 equal scaling crop center(正方形裁切) * @param { String } 原文件路徑 * @param { String } 新文件路徑 * @param { String } 縮放規則 * @return { promise } */var escc = function(src, dest, rules) {  return new Promise(function(resolve, reject) {  // 600_90 => 寬度600/高度600/品質90    rules = rules.split('_');    if (rules.length !== 2) {      return reject(new Error('Resize rules invalid'));    }    let cropSize = parseInt(rules[0]);    let quality = parseInt(rules[1]) || defaultQuality;    const readStream = fs.createReadStream(src);    const writeStream = fs.createWriteStream(dest);    if (!cropSize) {      reject(new Error('Crop params invalid'));      return;    }    gm(readStream)      .size({        bufferStream: true      }, function(err, size) {        if (err) {          reject(err);          return;        }        const origWidth = size.width;        const origHeight = size.height;        let cropX = 0;        let cropY = 0;        let resizeWidth;        let resizeHeight;        let resizeResult;        // 裁切的寬度和高度做最大最小值限制        if (cropSize > origWidth) {          cropSize = origWidth;        }        else if (cropSize > origHeight) {          cropSize = origHeight;        }        else if (cropSize < minSize) {          cropSize = minSize;        }        // 先計算出等比縮放的尺寸,然后再根據此尺寸計算出裁切位置        if (origWidth > origHeight) {          resizeWidth = cropSize / origHeight * origWidth;          resizeHeight = cropSize;          cropX = Math.floor((resizeWidth - cropSize) / 2);          cropY = 0;        }        else {          resizeHeight = cropSize / origWidth * origHeight;          resizeWidth = cropSize;          cropX = 0;          cropY = Math.floor((resizeHeight - cropSize) / 2);        }        resizeResult = this.resize(resizeWidth, resizeHeight);        resizeResult          .quality(quality)          .interlace('line') // 使用逐行掃描方式          .crop(cropSize, cropSize, cropX, cropY)          .unsharp(2, 0.5, 0.5, 0)          .stream()          .on('end', resolve)          .pipe(writeStream);      });  });};

上面的 crop 就是對圖片進行裁切。當然除了中心裁切,還能延伸出頂部裁切,底部裁切等,相對來說使用場景要少很多。

結語

在服務的實際應用中,還會做一些優化,比如對服務的接口做一些安全限制,確保該接口不會被刷,裁切本身是比較消耗資源的操作。由于裁切操作比較耗資源,那么相同的尺寸應該保證只有一次裁切操作,這樣只有第一次請求裁切圖片才會真正有裁切操作,后續的訪問就直接讀取原來就裁切好的實體文件即可。

以上所述是小編給大家介紹的使用 Node.js 實現圖片的動態裁切及算法實例代碼詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VeVb武林網網站的支持!


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 平阳县| 蒙阴县| 开鲁县| 赤城县| 兴仁县| 屏东县| 茶陵县| 潮州市| 刚察县| 灌阳县| 横峰县| 南安市| 德江县| 柏乡县| 桦川县| 治县。| 高碑店市| 古田县| 辽阳市| 玛多县| 安宁市| 中方县| 泗水县| 榕江县| 石家庄市| 安乡县| 大名县| 开鲁县| 乌拉特后旗| 于田县| 藁城市| 揭阳市| 永德县| 黄大仙区| 海伦市| 武乡县| 金秀| 夏邑县| 饶平县| 伊吾县| 林西县|