
-
个人首页: VON
-
鸿蒙系列专栏: 鸿蒙开发小型案例总结
-
综合案例 :鸿蒙综合案例开发
-
鸿蒙6.0:从0开始的开源鸿蒙6.0.0
-
鸿蒙5.0:鸿蒙5.0零基础入门到项目实战
-
本文章所属专栏:Electron for HarmonyOS
-
文章专属视频教程:别再拉伸图片了!教你3秒保持原比例缩放
纯图片尺寸调节工具(支持锁定纵横比)
-
- 前言
- 功能概述
- [✅ 功能清单](#✅ 功能清单)
- [📂 项目结构](#📂 项目结构)
- [🧩 完整代码](#🧩 完整代码)
-
- [1. `main.js`(主进程)](#1.
main.js(主进程)) - [2. `preload.js`(安全暴露 API)](#2.
preload.js(安全暴露 API)) - [3. `index.html`(核心功能)](#3.
index.html(核心功能)) - [4. `package.json`](#4.
package.json)
- [1. `main.js`(主进程)](#1.
- [▶️ 如何运行?](#▶️ 如何运行?)
- [🔍 技术亮点](#🔍 技术亮点)
- [🚀 鸿蒙部分](#🚀 鸿蒙部分)
- 测试
- [✅ 总结](#✅ 总结)

前言
通过前面两篇文章的学习想必大家已经对Electron有所了解了,接下来仅进入实战环节。
先说一下为何做这么一个项目?
不知道大家有没有遇到这种情况,就是有些网页需要指定图片尺寸才可以进行上传,网上也有这样的网页但是网上那些网页不是广告就是付费,真正实现免费的并不多,我在wps上面以及电脑自带的图库上面也都没有找到类似的功能,所以就自己开发了一个,可以直接运行到我的真机上面,也可以打包成应用程序供大家来使用
功能概述
一句话功能:上传图片 → 输入目标尺寸 → 自动/手动缩放 → 保存高清结果
✅ 功能清单
| 功能 | 说明 |
|---|---|
| 图片上传 | 支持 JPG / PNG / WebP 等常见格式 |
| 尺寸输入 | 可分别设置宽度和高度(单位:px) |
| 锁定纵横比 | 勾选后修改宽/高自动计算另一值 |
| 高质量缩放 | 使用 Canvas 高质量重绘(非简单拉伸) |
| 一键保存 | 导出为 PNG(透明通道保留) |
📂 项目结构
image-resize-app/
├── main.js # 主进程:窗口 + 文件保存
├── preload.js # 安全桥接 API
├── index.html # 前端界面 + 缩放逻辑
└── package.json
🧩 完整代码
1. main.js(主进程)
javascript
const { app, BrowserWindow, ipcMain, dialog } = require('electron');
const path = require('path');
const fs = require('fs');
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 650,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true
}
});
win.loadFile('index.html');
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
// 保存图片到本地
ipcMain.handle('save-image', async (_, { dataUrl }) => {
const { canceled, filePath } = await dialog.showSaveDialog({
filters: [
{ name: 'PNG', extensions: ['png'] },
{ name: 'JPEG', extensions: ['jpg', 'jpeg'] }
]
});
if (!canceled && filePath) {
const buffer = Buffer.from(dataUrl.split(',')[1], 'base64');
fs.writeFileSync(filePath, buffer);
return filePath;
}
});
2. preload.js(安全暴露 API)
javascript
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('api', {
saveImage: (data) => ipcRenderer.invoke('save-image', data)
});
3. index.html(核心功能)
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>图片尺寸调节工具</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
margin: 0;
padding: 20px;
background: #f9fafb;
}
.container {
max-width: 750px;
margin: 0 auto;
background: white;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
padding: 25px;
}
h1 {
text-align: center;
color: #2d3748;
margin-bottom: 25px;
}
.controls {
display: flex;
flex-wrap: wrap;
gap: 15px;
align-items: center;
margin-bottom: 20px;
}
.input-group {
display: flex;
align-items: center;
gap: 8px;
}
input[type="number"] {
width: 90px;
padding: 6px 8px;
border: 1px solid #cbd5e0;
border-radius: 6px;
font-size: 14px;
}
label {
display: flex;
align-items: center;
gap: 6px;
font-size: 14px;
color: #4a5568;
}
button {
padding: 8px 18px;
background: #3182ce;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
}
button:hover { background: #2c5aa0; }
button:disabled {
background: #cbd5e0;
cursor: not-allowed;
}
canvas {
width: 100%;
height: auto;
border: 1px solid #e2e8f0;
border-radius: 8px;
background: #f8fafc;
margin-top: 10px;
}
.info {
text-align: center;
color: #718096;
font-size: 13px;
margin-top: 12px;
}
</style>
</head>
<body>
<div class="container">
<h1>📐 图片尺寸调节工具</h1>
<div class="controls">
<input type="file" id="imageInput" accept="image/*">
<div class="input-group">
<label>宽:</label>
<input type="number" id="widthInput" min="1" value="800">
<span>×</span>
<input type="number" id="heightInput" min="1" value="600">
<label><input type="checkbox" id="aspectLock" checked> 锁定比例</label>
</div>
<button id="saveBtn" disabled>💾 保存图片</button>
</div>
<canvas id="outputCanvas"></canvas>
<p class="info">上传图片后,可自由调整尺寸。勾选"锁定比例"避免图像变形。</p>
</div>
<script>
const imageInput = document.getElementById('imageInput');
const widthInput = document.getElementById('widthInput');
const heightInput = document.getElementById('heightInput');
const aspectLock = document.getElementById('aspectLock');
const saveBtn = document.getElementById('saveBtn');
const canvas = document.getElementById('outputCanvas');
const ctx = canvas.getContext('2d');
let originalImage = null;
let originalRatio = 1;
// 修改宽度时联动高度(如果锁定比例)
widthInput.addEventListener('input', () => {
if (aspectLock.checked && originalImage) {
const w = parseInt(widthInput.value) || 1;
heightInput.value = Math.round(w / originalRatio);
}
render();
});
// 修改高度时联动宽度(如果锁定比例)
heightInput.addEventListener('change', () => {
if (aspectLock.checked && originalImage) {
const h = parseInt(heightInput.value) || 1;
widthInput.value = Math.round(h * originalRatio);
}
render();
});
// 切换锁定比例状态
aspectLock.addEventListener('change', render);
// 上传图片
imageInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (!file) return;
const img = new Image();
img.onload = () => {
originalImage = img;
originalRatio = img.width / img.height;
// 默认设为目标尺寸(不超过原图)
const maxWidth = Math.min(img.width, 1920);
const maxHeight = Math.min(img.height, 1080);
widthInput.value = maxWidth;
heightInput.value = Math.round(maxWidth / originalRatio);
render();
saveBtn.disabled = false;
};
img.src = URL.createObjectURL(file);
});
// 渲染缩放后的图片
function render() {
if (!originalImage) return;
const w = parseInt(widthInput.value) || 1;
const h = parseInt(heightInput.value) || 1;
canvas.width = w;
canvas.height = h;
// 关键:使用高质量缩放(关闭 imageSmoothing 可实现像素风,但这里要清晰)
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = 'high';
ctx.clearRect(0, 0, w, h);
ctx.drawImage(originalImage, 0, 0, w, h);
}
// 保存图片
saveBtn.addEventListener('click', async () => {
const mimeType = 'image/png'; // 也可根据扩展名动态切换
const dataUrl = canvas.toDataURL(mimeType);
const path = await window.api.saveImage({ dataUrl });
if (path) alert(`✅ 已保存至:\n${path}`);
});
</script>
</body>
</html>
4. package.json
json
{
"name": "image-resize-app",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"devDependencies": {
"electron": "^latest"
}
}
▶️ 如何运行?
bash
npm install --save-dev electron
npm start
💡 建议使用
cnpm或设置淘宝镜像加速安装。
bash
npm config set registry https://registry.npmmirror.com
npm install -g cnpm --registry=https://registry.npmmirror.com
cnpm install --save-dev electron
npm start
🔍 技术亮点
- 高质量缩放 :通过
ctx.imageSmoothingQuality = 'high'保证缩放清晰 - 安全架构 :使用
contextBridge隔离主/渲染进程 - 用户体验:默认尺寸不超过 1920×1080,避免内存溢出
- 格式兼容:支持透明 PNG、JPG 等主流格式
🚀 鸿蒙部分
如何让原本用于 Electron 的前端 + 主进程架构,在鸿蒙系统中运行并兼容?
我们的最终目的是打包在真机上面,所以要去将代码迁移到dev上面,通过观察不难看出,结构都是类似的,所以理论上来说直接copy上去即可,理论成立就开始实战

✅ 答案总结
🔹 鸿蒙的"Electron 兼容"本质是:Web Engine 模拟 Chromium + Node.js 环境
华为在 HarmonyOS 的 Web Engine(Web 引擎) 中,通过以下方式实现了对 Electron 应用的部分兼容:
项目 说明
🌐 Web 页面渲染 使用 Chromium 内核,支持 HTML/CSS/JS,与 Electron 一致
💻 Node.js API 模拟 通过 libadapter 层模拟部分 Node.js 接口(如文件、IPC)
🧩 主进程 → 渲染进程通信 使用 contextBridge + ipcRenderer 模式,与 Electron 保持一致
📁 资源打包机制 将 main.js, preload.js, index.html 打包进 HAP(HarmonyOS Ability Package)
测试
图片之前的尺寸

开始进行修改

修改后的尺寸

✅ 总结
我们通过一个简单的 图片尺寸调节工具,展示了如何:
✅ 用 Electron 快速构建桌面应用
✅ 利用 Canvas 实现高质量图像缩放
✅ 通过鸿蒙 DevEco 的 Web Engine + libadapter 机制,无缝迁移到 HarmonyOS
✅ 实现"一套代码,双端运行"(PC + 鸿蒙设备)