OPEN-IMAGE-TINY,一個基于 Electron + VUE3 的圖片壓縮工具,項目開源地址:https://github.com/0604hx/open-image-tiny
?? 需求描述
在上一篇文章一段代碼利用 snapdom 將 CSDN 博文轉化為長圖片(PNG/JPG/PDF)中,我截取到一張長圖,想要垂直切割成多張高度一致的小圖。雖然用美圖秀秀之類的軟件很快就能做到,奈何我覺得圖片壓縮工具也應該有這樣的一個功能,于是就有了這篇文章😄。
功能說明:
- 只需要按設定的高度
垂直切割
- 最后一張小圖高度不足時
填充
指定顏色
🧑?💻 核心代碼
后端
//electron\tool.js
/*** @typedef {Object} SplitConfig - 切割配置* @property {Number} height - 高度* @property {Boolean} fit - 是否自動填充* @property {String} bgColor - 填充顏色** 垂直切割圖片** @param {String} origin - 原圖片* @param {SplitConfig} config - 配置*/
exports.splitImageVertical = async (origin, config)=>{const { width, height } = await this.readImgSize(origin)config.fit ??= trueconst ext = path.extname(origin)const count = Math.ceil(height / config.height)const outputDir = path.join(path.dirname(origin), `${path.basename(origin, ext)}-${config.height}px`)if(!existsSync(outputDir))mkdirSync(outputDir)const image = sharp(origin)let fileCount = 0let started = Date.now()for(let i=0;i<count;i++){const top = i * config.heightconst curHeight = Math.min(config.height, height - top)let chunk = image.clone().extract({ left:0, top, width, height: curHeight })//自動填充白色背景if(config.fit === true && config.height > curHeight){chunk = chunk.extend({ top:0, bottom: config.height - curHeight, left:0, right:0, background: config.bgColor||"#ffffff" })}let outFile = path.join(outputDir, `切割-${i+1}.${ext}`)await chunk.toFile(outFile)console.debug(`切割圖片 > ${outFile}`)fileCount ++}return { total:fileCount, dir: outputDir, used: Date.now() - started }
}
注冊 ipcMain 處理函數:
const handlers = {/**** @param {Electron.IpcMainInvokeEvent} e* @param {String} filePath* @param {import("./tool").SplitConfig} config* @returns {Object}*/'split': async (e, filePath, config)=> await splitImageVertical(filePath, config)
}
UI界面
<template><n-form :show-feedback="false" label-placement="left"><n-flex vertical><n-form-item label="切割高度"><n-input-number class="cell" :min="0" :step="50" v-model:value="config.height"><template #suffix><Tag>px</Tag></template></n-input-number></n-form-item><n-form-item label="自動填充"><n-switch v-model:value="config.fit" /></n-form-item><n-form-item v-if="config.fit==true" label="填充顏色"><n-color-picker v-model:value="config.bgColor" :show-alpha="false" /></n-form-item><n-button block type="primary" secondary :loading @click="toSplit">開始切割</n-button></n-flex></n-form>
</template><script setup>const props = defineProps({img:{ type:Object }})const config = reactive({ height:1000, fit:true, bgColor:"#ffffff" })const loading = ref(false)const toSplit=()=>{if(config.height >= props.img.height) return M.warn(`切割高度不能大于圖片原高度`)loading.value = trueH.action('split', props.img.path, toRaw(config)).then(v=>{loading.value = falselet { total, dir, used } = vM.dialog({maskClosable: false, showIcon: true,title: `切割完成`,content: `共生成 ${total} 張小圖,耗時 ${used} 毫秒。`,positiveText:"打開圖片文件夾",onPositiveClick: ()=>H.action('open', dir)})})}
</script>