node圖片自動壓縮

来源:https://www.cnblogs.com/shukesio/archive/2023/10/13/17761283.html
-Advertisement-
Play Games

圖片壓縮 借用了images、imagemin等第三方庫,壓縮jpg、Png圖片 viteImagemin也可以實現,代碼量更加少,squoosh就沒用過了 輸入需要壓縮的文件 //判斷是否已經有這個文件路徑 function setInputName() { return new Promise( ...


圖片壓縮
借用了images、imagemin等第三方庫,壓縮jpg、Png圖片
viteImagemin也可以實現,代碼量更加少,squoosh就沒用過了

輸入需要壓縮的文件

//判斷是否已經有這個文件路徑
function setInputName() {
    return new Promise((resolve, reject) => {
        inputVlaue.question('請輸入需要壓縮文件夾名稱:', async (val) => {
            let asr = val.replace(/\s+/g, "");
            if (asr == 'imagesTest') {
                console.log("不可以與預設輸出文件夾重名");
                return setFileName("請重新輸入!\n")
            } else if (!reg.test(asr)) {
                console.log("只能輸入英文");
                return setFileName("請重新輸入!\n")
            }
            positionDir = path.join(process.cwd(), asr)
            console.log(positionDir);
            resolve(positionDir)

        })
    })

}

不存在則自動創建文件

不建議在調用 fs.open() 、fs.readFile() 或 fs.writeFile() 之前使用 fs.stat() 檢查一個文件是否存在。 作為替代,用戶代碼應該直接打開/讀取/寫入文件,當文件無效時再處理錯誤。
如果要檢查一個文件是否存在且不操作它,推薦使用 fs.access()
這裡使用node內置path處理文件

function createTimeFile(positionDir) {
    let time_PATH = path.resolve(__dirname, positionDir);//獲取是否已經存在這個文件
    return new Promise((resolve, reject) => {
        fs.stat(time_PATH, (err, stat) => {
            if (err) {
                fs.mkdir(positionDir, { recursive: true }, (err) => {
                    resolve(err)
                    console.log(`創建${positionDir}成功!`);
                })
            } else {
                resolve(stat)

            }


        })

    })


}

文件創建成功,輸入xx指令進行壓縮

function ready() {
    let msg=`請把所需壓縮圖片放入${positionDir}輸入yes,開始壓縮圖片!\n`
    inputVlaue.question(msg, answers => {
        let asr = answers.trim().toLocaleLowerCase()
        if (asr == "yes") {
            console.log("開始壓縮...\n");
            setImageData()
        } else {
            ready("指令錯誤請重新輸入,輸入yes開始壓縮圖片\n")
        }
    })
}

讀取需要壓縮的文件

//讀取需要壓縮的文件夾
function getReadFile() {
    fs.readdir(positionDir, "utf-8", (err, data) => {
        console.log(data.length);

        if (data.length == 0) {
            console.log("還沒有圖片,請添加");
        }
        data.forEach((item, index) => {
            let filePath = path.join(positionDir, item)
            let filename = filePath.replace(/\\/g, "/");//把 \ 替換為 /
            let output = filename.replace(positionDir.replace(/\\/g, "/"), outputDir.replace(/\\/g, "/"));//輸出位置
            if (path.extname(item) == ".png") {
                pngArrayList.push({ filename, output })
            } else if (path.extname(item) == ".jpg") {
                jpgArrayList.push({ filename, output })
            } else if (fs.statSync(filePath).isDirectory()) {
                readfile(filePath)
            }

        })



    })
}

針對jpg和png處理使用不同的方法

function setImageData() {
    if (jpgArrayList.length != 0) {
        jpgArrayList = rmSame(jpgArrayList)
        //壓縮jpg
        console.log(jpgArrayList);
        jpgArrayList.forEach(item => {
            createTimeFile(path.dirname(item.output))
            images(item.filename).save(item.output, { quality: 60 })
        })
    }
    //壓縮png
    pngArrayList = rmSame(pngArrayList)
    pngCompress(pngArrayList, pngArrayList.length - 1)

}



function rmSame(arr) {
    let newArray = []
    let arrObj = []
    for (let index = 0; index < arr.length; index++) {
        const element = arr[index];
        if (newArray.indexOf(element['filename']) == -1 && (fs.statSync(element['filename']).size > 1024)) {
            newArray.push(element['filename'])
            arrObj.push(element)
        } else if (newArray.indexOf(element['filename']) == -1 && (fs.statSync(element['filename']).size <= 1024)) {
            let pathDir = path.dirname(element['output'])
            createTimeFile(pathDir)//判斷存放壓縮的文件夾是否已經存在,不存在則創建
            fs.createReadStream(element['filename']).pipe(fs.createWriteStream(element['output']))
            console.log(`圖片${element['filename']}記憶體過小,直接轉移到${element['output']}`)
        }
    }
    return arrObj
}

//png壓縮圖片
function pngCompress(arr, index) {
    //壓縮結束
    if (index < 0) {
        console.log("\n本視窗在5秒後關閉!")
        setTimeout(() => {
            inputVlaue.close()
        }, 5000)
        return
    }

    let pathDir = path.dirname(arr[index]['output'])
    let filename = arr[index]['filename']
    createTimeFile(pathDir)
    imagemin([filename], {
        destination: pathDir,
        plugins: [
            imageminPngquant({
                quality: [0.6, 0.7]
            })
        ]
    }).then(() => {
        console.log(`圖片${filename}壓縮完成!`);
        pngCompress(arr, index - 1)
    }).catch(err => {
        console.log(`${arr[index]['filename']}圖片壓縮不了了,直接轉移到${arr[index]['output']}`)
        fs.createReadStream(arr[index]['filename']).pipe(fs.createWriteStream(arr[index]['output']))
        pngCompress(arr, index - 1)
    });

}

全部代碼

/*
 * @Author: zlc
 * @Date: 2022-04-14 16:34:12
 * @LastEditTime: 2022-04-15 10:26:16
 * @LastEditors: zlc
 * @Description: 圖片壓縮
 * @FilePath: \git項目\project-template\案例\圖片壓縮\imagemin\src\app.js
 */
const fs = require("fs")
const imagemin = require('imagemin');
const imageminPngquant = require('imagemin-pngquant');
const path = require("path")
const images = require("images")
const readline = require("readline");
const { resolve } = require("path");
const inputVlaue = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});
let outputDir = path.join(process.cwd(), "imagesTest")
let reg = /^[a-zA-Z]+$/

let positionDir, timeId, pngArrayList = [], jpgArrayList = []
let timeIndex = 0
const setCompress = async () => {
    await setInputName();//輸入內容
    await createTimeFile(positionDir);//創建文件
    await getReadFile()//讀取文件
    ready()//開始壓縮
    
    

}

//判斷是否已經有這個文件路徑
function setInputName() {
    return new Promise((resolve, reject) => {
        inputVlaue.question('請輸入需要壓縮文件夾名稱:', async (val) => {
            let asr = val.replace(/\s+/g, "");
            if (asr == 'imagesTest') {
                console.log("不可以與預設輸出文件夾重名");
                return setFileName("請重新輸入!\n")
            } else if (!reg.test(asr)) {
                console.log("只能輸入英文");
                return setFileName("請重新輸入!\n")
            }
            positionDir = path.join(process.cwd(), asr)
            console.log(positionDir);
            resolve(positionDir)

        })
    })

}
//創建圖片文件
function createTimeFile(positionDir) {
    let time_PATH = path.resolve(__dirname, positionDir);//獲取是否已經存在這個文件
    return new Promise((resolve, reject) => {
        fs.stat(time_PATH, (err, stat) => {
            if (err) {
                fs.mkdir(positionDir, { recursive: true }, (err) => {
                    resolve(err)
                    console.log(`創建${positionDir}成功!`);
                })
            } else {
                resolve(stat)

            }


        })

    })


}


//讀取需要壓縮的文件夾
function getReadFile() {
    fs.readdir(positionDir, "utf-8", (err, data) => {
        console.log(data.length);

        if (data.length == 0) {
            console.log("還沒有圖片,請添加");
        }
        data.forEach((item, index) => {
            let filePath = path.join(positionDir, item)
            let filename = filePath.replace(/\\/g, "/");//把 \ 替換為 /
            let output = filename.replace(positionDir.replace(/\\/g, "/"), outputDir.replace(/\\/g, "/"));//輸出位置
            if (path.extname(item) == ".png") {
                pngArrayList.push({ filename, output })
            } else if (path.extname(item) == ".jpg") {
                jpgArrayList.push({ filename, output })
            } else if (fs.statSync(filePath).isDirectory()) {
                readfile(filePath)
            }

        })



    })
}

function ready() {
    let msg=`請把所需壓縮圖片放入${positionDir}輸入yes,開始壓縮圖片!\n`
    inputVlaue.question(msg, answers => {
        let asr = answers.trim().toLocaleLowerCase()
        if (asr == "yes") {
            console.log("開始壓縮...\n");
            setImageData()
        } else {
            ready("指令錯誤請重新輸入,輸入yes開始壓縮圖片\n")
        }
    })
}

function setImageData() {
    if (jpgArrayList.length != 0) {
        jpgArrayList = rmSame(jpgArrayList)
        //壓縮jpg
        console.log(jpgArrayList);
        jpgArrayList.forEach(item => {
            createTimeFile(path.dirname(item.output))
            images(item.filename).save(item.output, { quality: 60 })
        })
    }
    //壓縮png
    pngArrayList = rmSame(pngArrayList)
    pngCompress(pngArrayList, pngArrayList.length - 1)

}
function rmSame(arr) {
    let newArray = []
    let arrObj = []
    for (let index = 0; index < arr.length; index++) {
        const element = arr[index];
        if (newArray.indexOf(element['filename']) == -1 && (fs.statSync(element['filename']).size > 1024)) {
            newArray.push(element['filename'])
            arrObj.push(element)
        } else if (newArray.indexOf(element['filename']) == -1 && (fs.statSync(element['filename']).size <= 1024)) {
            let pathDir = path.dirname(element['output'])
            createTimeFile(pathDir)//判斷存放壓縮的文件夾是否已經存在,不存在則創建
            fs.createReadStream(element['filename']).pipe(fs.createWriteStream(element['output']))
            console.log(`圖片${element['filename']}記憶體過小,直接轉移到${element['output']}`)
        }
    }
    return arrObj
}

//png壓縮圖片
function pngCompress(arr, index) {
    //壓縮結束
    if (index < 0) {
        console.log("\n本視窗在5秒後關閉!")
        setTimeout(() => {
            inputVlaue.close()
        }, 5000)
        return
    }

    let pathDir = path.dirname(arr[index]['output'])
    let filename = arr[index]['filename']
    createTimeFile(pathDir)
    imagemin([filename], {
        destination: pathDir,
        plugins: [
            imageminPngquant({
                quality: [0.6, 0.7]
            })
        ]
    }).then(() => {
        console.log(`圖片${filename}壓縮完成!`);
        pngCompress(arr, index - 1)
    }).catch(err => {
        console.log(`${arr[index]['filename']}圖片壓縮不了了,直接轉移到${arr[index]['output']}`)
        fs.createReadStream(arr[index]['filename']).pipe(fs.createWriteStream(arr[index]['output']))
        pngCompress(arr, index - 1)
    });

}
setCompress()

git地址:https://gitee.com/KingSio/project-template/tree/master/


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 存儲引擎都是把數據存儲在文件系統上,通過通過查詢命令,可以查看數據目錄所在的本機路徑。 mysql> SHOW VARIABLES LIKE 'datadir'; + + + | Variable_name | Value | + + + | datadir | /var/lib/mysql/ ...
  • Trino是一款開源的高性能、分散式SQL查詢引擎,專門用於對各種異構數據源運行互動式分析查詢,支持從GB到PB的數據量範圍。 ...
  • 解決SUM函數返回為NULL SUM函數的作用:計算某一欄位中所有行的數值和, 使用SUM函數進行對符合條件的結果行數進行求和。 問題產生: sum 求和時會對 null 進行過濾,不計算,但如果沒有返回結果,則sum 函數的返回值為 null,不是 0: 解決方式: 1. IFNULL 使用IFN ...
  • 在DBS-集群列表-更多-連接查詢-死鎖中,看到9月22日有資料庫死鎖日誌,後排查發現是因為mysql的優化-index merge(索引合併)導致資料庫死鎖。 ...
  • 本文分享自華為雲社區《【SQL優化】為什麼有時候無法走執行性能更優的hashjoin》,作者: leapdb。 1. hash join通常優於nestloop join 通常nestloop join的複雜度是O(N方),hash join時間複雜度是O(N),所以我們一般傾向於使用hash jo ...
  • 驅動表與被驅動表的含義 在MySQL中進行多表聯合查詢時,MySQL會通過驅動表的結果集作為基礎數據,在被驅動表中匹配對應的數據,匹配成功合併後的臨時表再作為驅動表或被驅動表繼續與第三張表進行匹配合併,直到所有表都已匹配完畢,最後將結果返回出來。匹配演算法:Nested-Loop Join(嵌套迴圈連 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 背景 某一天,前端小餘同學和後端別問我小哥在做登錄業務介面對接,出於業務的特殊性和安全性的考慮,她和後端小哥約定“user”相關信息參數需要通過HTTP協議的header傳遞過來,利用HTTPS協議的頭部中的參數可以通過加密傳輸,從而保證 ...
  • 自動化3D機房、微模塊、3D機房、3D數據中心、科技感數據中心、三維機房、3d建築,3d消防,消防演習模擬,3d庫房,3d檔案室,3d密集架,webGL,threejs,3d機房,bim管理系統 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...