亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

使用 Node.js 實(shí)現(xiàn)圖片的動(dòng)態(tài)裁切及算法實(shí)例代碼詳解

 更新時(shí)間:2018年09月29日 08:50:34   作者:雨夜帶刀  
這篇文章主要介紹了使用 Node.js 實(shí)現(xiàn)圖片的動(dòng)態(tài)裁切功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

背景&概覽

目前常見(jiàn)的圖床服務(wù)都會(huì)有圖片動(dòng)態(tài)裁切的功能,主要的應(yīng)用場(chǎng)景用以為各種終端和業(yè)務(wù)形態(tài)輸出合適尺寸的圖片。

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

URL 的設(shè)計(jì)

圖片 URL 需要包含圖片 id、尺寸、質(zhì)量等信息。有兩種類型的圖片 URL,分別是原圖 URL 和帶動(dòng)態(tài)裁切信息的 URL。

// 原圖 URL
http://example.com/$imgId

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

來(lái)分析一下上面 URL 中的變量:

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

那么一張圖片 id 為 4b2d4edcc1f82452 的原圖 URL 應(yīng)該是:

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

如果想要一張?jiān)搱D 800×600 的版本,裁切的 URL 大致是下面這樣的:

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

裁切算法

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

最常見(jiàn)的裁切算法是等比例裁切,等比裁切的算法需要至少給出裁切目標(biāo)圖片的寬度和高度的其中一個(gè),如果圖片限寬就給出寬度,限高就給出高度,如果兩個(gè)參數(shù)都有,就需要確保裁切的目標(biāo)寬高相對(duì)于原始的寬高是按比例計(jì)算的,否則裁切的結(jié)果就會(huì)出現(xiàn)拉伸。

var gm = require('gm');
// 裁切的最小尺寸
var minSize = 48;
var defaultQuality = 90;
/**
 * 等比例縮放 equal scaling
 * @param { String } 原文件路徑
 * @param { String } 新文件路徑
 * @param { String } 縮放規(guī)則
 * @return { promise }
 */
var es = function(src, dest, rules) {
  return new Promise(function(resolve, reject) {
    // 900_600_90 => 寬度900/高度600/品質(zhì)90
    rules = rules.split('_');
    if (rules.length !== 3) {
      return reject(new Error('Resize rules invalid'));
    }
    // 解析裁切的目標(biāo)寬高
    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);
      });
  });
};

說(shuō)說(shuō)幾個(gè)重要的 API:

quality 設(shè)置圖片的質(zhì)量,GM 圖片質(zhì)量范圍是 0-100,默認(rèn)的質(zhì)量是 75。
interlace 用于設(shè)置圖片在顯示器上加載時(shí)的顯示方式,當(dāng)然顯示方式本身還要受圖片本身的影響。
unsharp 用來(lái)設(shè)置圖片的銳度,將一張大圖縮放成一張小圖時(shí),會(huì)損失很多像素,需要適當(dāng)?shù)脑黾訄D片銳度來(lái)保證圖片的質(zhì)量。關(guān)于 unsharp 的使用,詳見(jiàn) Using ImageMagick to make sharp web-sized photographs 。
等比例裁切嚴(yán)格來(lái)說(shuō)實(shí)際上還只是對(duì)圖片進(jìn)行縮放,并未動(dòng)用圖片裁切的 API。

還有一種比較常見(jiàn)的裁切方式,會(huì)先將圖片等比例縮放后再?gòu)闹行牟们?,裁切出?lái)的圖片是一個(gè)正方形,這樣能盡可能保證圖片的內(nèi)容。

/*
 * 等比例縮放后從中心裁切 equal scaling crop center(正方形裁切)
 * @param { String } 原文件路徑
 * @param { String } 新文件路徑
 * @param { String } 縮放規(guī)則
 * @return { promise }
 */
var escc = function(src, dest, rules) {
  return new Promise(function(resolve, reject) {
  // 600_90 => 寬度600/高度600/品質(zhì)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;
        }
        // 先計(jì)算出等比縮放的尺寸,然后再根據(jù)此尺寸計(jì)算出裁切位置
        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 就是對(duì)圖片進(jìn)行裁切。當(dāng)然除了中心裁切,還能延伸出頂部裁切,底部裁切等,相對(duì)來(lái)說(shuō)使用場(chǎng)景要少很多。

結(jié)語(yǔ)

在服務(wù)的實(shí)際應(yīng)用中,還會(huì)做一些優(yōu)化,比如對(duì)服務(wù)的接口做一些安全限制,確保該接口不會(huì)被刷,裁切本身是比較消耗資源的操作。由于裁切操作比較耗資源,那么相同的尺寸應(yīng)該保證只有一次裁切操作,這樣只有第一次請(qǐng)求裁切圖片才會(huì)真正有裁切操作,后續(xù)的訪問(wèn)就直接讀取原來(lái)就裁切好的實(shí)體文件即可。

以上所述是小編給大家介紹的使用 Node.js 實(shí)現(xiàn)圖片的動(dòng)態(tài)裁切及算法實(shí)例代碼詳解,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • 在node.js中讀寫文件的三種方法總結(jié)

    在node.js中讀寫文件的三種方法總結(jié)

    nodejs中所有與文件相關(guān)的操作都在fs模塊中,而讀寫操作又是我們會(huì)經(jīng)常用到的操作,nodejs的fs模塊針對(duì)讀操作為我們提供了readFile,read, createReadStream三個(gè)方法,接下來(lái)小編就和大家一起來(lái)分析一下這三種方法
    2023-09-09
  • NodeJS 實(shí)現(xiàn)多語(yǔ)言的示例代碼

    NodeJS 實(shí)現(xiàn)多語(yǔ)言的示例代碼

    這篇文章主要介紹了NodeJS 實(shí)現(xiàn)多語(yǔ)言的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • 使用NODE.JS創(chuàng)建一個(gè)WEBSERVER(服務(wù)器)的步驟

    使用NODE.JS創(chuàng)建一個(gè)WEBSERVER(服務(wù)器)的步驟

    在 node.js 中創(chuàng)建一個(gè)服務(wù)器非常簡(jiǎn)單,只需要使用 node.js 為我們提供的 http 模塊及相關(guān) API 即可創(chuàng)建一個(gè)麻雀雖小但五臟俱全的web 服務(wù)器,相比 Java/Python/Ruby 搭建web服務(wù)器的過(guò)程簡(jiǎn)單的很。本文簡(jiǎn)單的講解下實(shí)現(xiàn)步驟
    2021-06-06
  • AngularJS + Node.js + MongoDB開(kāi)發(fā)的基于高德地圖位置的通訊錄

    AngularJS + Node.js + MongoDB開(kāi)發(fā)的基于高德地圖位置的通訊錄

    這篇文章主要介紹了AngularJS + Node.js + MongoDB開(kāi)發(fā)的基于高德地圖位置的通訊錄,需要的朋友可以參考下
    2015-01-01
  • 詳解從NodeJS搭建中間層再談前后端分離

    詳解從NodeJS搭建中間層再談前后端分離

    這篇文章主要介紹了詳解從NodeJS搭建中間層再談前后端分離,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • 基于node.js制作簡(jiǎn)單爬蟲(chóng)教程

    基于node.js制作簡(jiǎn)單爬蟲(chóng)教程

    這篇文章主要為大家詳細(xì)介紹了基于node.js制作簡(jiǎn)單爬蟲(chóng)的教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • React和Node.js快速上傳進(jìn)度條功能實(shí)現(xiàn)

    React和Node.js快速上傳進(jìn)度條功能實(shí)現(xiàn)

    這篇文章主要為大家介紹了React和Node.js快速上傳進(jìn)度條功能實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • node操作mysql數(shù)據(jù)庫(kù)實(shí)例詳解

    node操作mysql數(shù)據(jù)庫(kù)實(shí)例詳解

    這篇文章主要介紹了node操作mysql數(shù)據(jù)庫(kù),結(jié)合實(shí)例形式較為詳細(xì)的分析了node操作數(shù)據(jù)庫(kù)的連接、增刪改查、事務(wù)處理及錯(cuò)誤處理相關(guān)操作技巧,需要的朋友可以參考下
    2017-03-03
  • nodejs連接mongodb數(shù)據(jù)庫(kù)實(shí)現(xiàn)增刪改查

    nodejs連接mongodb數(shù)據(jù)庫(kù)實(shí)現(xiàn)增刪改查

    本篇文章主要結(jié)合了nodejs操作mongodb數(shù)據(jù)庫(kù)實(shí)現(xiàn)增刪改查,包括對(duì)數(shù)據(jù)庫(kù)的增加,刪除,查找和更新,有興趣的可以了解一下。
    2016-12-12
  • NodeJS模塊與ES6模塊系統(tǒng)語(yǔ)法及注意點(diǎn)詳解

    NodeJS模塊與ES6模塊系統(tǒng)語(yǔ)法及注意點(diǎn)詳解

    這篇文章主要給大家介紹了關(guān)于NodeJS模塊與ES6模塊系統(tǒng)語(yǔ)法及注意點(diǎn)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-01-01

最新評(píng)論