針對小遊戲中PNG、JPG壓縮工具優化(nodejs)

-前言-

博主目前還是主力使用Laya進行遊戲開發,隨着項目擴大,資源量增加,發佈愈發的緩慢。究其根本還是問題出在了圖片壓縮問題上,實在受不了準備將壓縮流程剝離出來,在自己想壓縮的時候再執行命令壓縮也不遲。

-正文-

首先來說一說爲什麼圖片壓縮那麼慢,圖片壓縮分爲兩個步驟:1.PNG壓縮,採用了pngquant,改工具在時間空間複雜度都不高。2.JPEG格式壓縮,採用了guetzli,這個工具就是讓你在壓縮時電腦卡得不行的工具,隨着壓縮的圖片越大暫用率越高。

這裏就不討論兩個工具的使用了,也不討論他們的效率,guetzli雖然效率低不過在jpg格式中的壓縮率還是很不錯,只要我們合適的時候使用也不會影響我們的心情:)

思路

其實思路還是很簡單的,讀取指定目錄下的所有png、jpg然後調用pngquant或者guetzli工具,值得注意的是兩個工具都只有單張圖片的壓縮方式,因此需要不停的調用子進程進行壓縮。png是遊戲中使用較多的圖片格式,jpg一般用於用戶頭像,遊戲log這些應用場景頻率較小的地方,更改頻率也比較小,因此我們可以將工具分爲png壓縮、jpg壓縮、圖片壓縮三個命令,視情況選擇執行。

使用工具時需要安裝下載guetzli,pngquant

1.批處理文件

首先我們定義三個批處理文件,分別處理png壓縮任務,jpg壓縮任務,圖片壓縮任務。

//bat jpg壓縮
node index.js jpg
@pause

//bat png壓縮
node index.js png
@pause

//壓縮png jpg
node index.js png jpg
@pause

2.讀取指定目錄下的所有文件並篩選PNG、JPG文件

//1.首先讀取指定目錄下的所有文件路徑
/**
 * 讀取指定路徑下的所有文件路徑並賦值到out中
 * @param {string} parentPath 
 * @param {Array<string>} out 
 */
function readAll(parentPath, out) {
    try {
        let files = fs.readdirSync(parentPath);
        files.forEach(function (item) {
            let tempPath = path.join(parentPath, item);
            let stats = fs.statSync(tempPath);
            if (stats.isDirectory()) {
                readAll(tempPath, out);
            } else {
                out.push(tempPath);
            }
        });
    } catch (e) {
        console.warn("Path Error:" + e);
        return out;
    }
}
//2.篩選png,jpg
let allFileList = [];
readAll(root_path, allFileList);
let pngList = [];
let jpgList = [];
for (let i = 0; i < allFileList.length; i++) {
	let fileData = path.parse(allFileList[i]);
	if (fileData.ext == ".png") {
		pngList.push(allFileList[i]);
	} else if (fileData.ext == ".jpg" || fileData.ext == ".JPG") {
		jpgList.push(allFileList[i]);
	}
}

3.根據進程參數執行壓縮

之前我們定義的bat分別向nodejs程序傳入的執行參數,這時候我們就可以通過參數來指定執行什麼函數。

if (process.argv.indexOf(TYPE_PNG) != -1) {
	//1.壓縮png
	compressPNG(pngList, compressCache.PNG, onCompressComplete);
} else {
	isPngComplete = true;
}

if (process.argv.indexOf(TYPE_JPG) != -1) {
	//2.壓縮jpg
	compressJPG(jpgList, compressCache.JPG, onCompressComplete);
} else {
	isJpgComplete = true;
}

//所有壓縮完成回調
function onCompressComplete(type) {
    if (type == TYPE_JPG) {
        isJpgComplete = true;
        console.log("JPG 壓縮完成.");
    }
    if (type == TYPE_PNG) {
        isPngComplete = true;
        console.log("PNG 壓縮完成.")
    }
    if (isPngComplete && isJpgComplete) {
        let encodeCache = JSON.stringify(compressCache);
        //回寫cache
        fs.writeFileSync("./cache/cache.json", encodeCache, "utf-8");
        console.log("壓縮完成...");
    }
}

壓縮的時候做了一個小小的優化,通過緩存圖片文件的大小及修改時間來判斷是否需要壓縮文件,對於沒有修改的文件就不進行壓縮。通過文件名轉md5存到cache.json文件中。

4.PNG壓縮

/**壓縮png */
function compressOnePNG(filePath, completeHandler) {
    const exePath = "./lib/pngquant/pngquant.exe";
    let param = ['--strip', '--force'];
    param.push('--skip-if-larger');
    param.push("--quality=" + [pngQualityLow, pngQualityHigh].join("-"));
    param.push('--output', filePath);
    param.push(filePath);
    let childP = child_process.spawn(exePath, param);
    childP.stdout.on('data', function (data) {

    });
    childP.stderr.on('data', function (data) {

    });
    childP.on("close", function (code) {
        let iCode = parseInt(code);
        if (iCode != 0) {//error
        }
        console.log(filePath, "壓縮完成");
        completeHandler && completeHandler(filePath);
    });
}

5.JPG壓縮

/**壓縮jpg */
function compressOneJPG(url, completeHandler) {
    let exePath = "guetzli_" + os.platform() + "_x86";
    if (os.arch == "x64") {
        exePath += "-64";
    }
    if ("win32" == os.platform()) {
        exePath += ".exe";
    }
    console.log("開始壓縮:",url);
    exePath = path.join("./lib/guetzli/", exePath);
    var params = ["--quality", jpgQuality];
    params.push(url, url);
    var childP = child_process.spawn(exePath, params);
    childP.stdout.on('data', function (data) {
        console.log("stdout:", data);
    });
    childP.stderr.on('data', function (data) {
        console.error("stderr:", data);
        console.error("compress fail pic:", url);
    });
    childP.on('close', function (code) {
        console.log("壓縮完成:",url)
        if (completeHandler != null) {
            completeHandler(url);
        }
    });
}

工具使用說明

1.修改conf目錄下的conf.json文件,將root_path配置正確(執行需要壓縮圖片的目錄)

2.運行前執行npm install 命令安裝依賴,目前就只用到md5模塊。

下載路徑:https://download.csdn.net/download/weixin_36719607/12238348

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章