yingsa/miniprogram/scripts/generateIcons.js

182 lines
5.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* TabBar 图标生成脚本
* 运行: node scripts/generateIcons.js
* 需要先安装依赖: npm install canvas
*/
const fs = require('fs');
const path = require('path');
// 尝试使用 canvas如果没有安装则使用简单的 PNG 生成
let useCanvas = false;
let createCanvas;
try {
const canvas = require('canvas');
createCanvas = canvas.createCanvas;
useCanvas = true;
} catch (e) {
console.log('canvas 未安装,将生成简单的占位图标');
}
const imagesDir = path.join(__dirname, '..', 'images');
// 确保 images 目录存在
if (!fs.existsSync(imagesDir)) {
fs.mkdirSync(imagesDir, { recursive: true });
}
// 图标配置
const icons = [
{ name: 'tab-rank', icon: '排', desc: '排名' },
{ name: 'tab-match', icon: '赛', desc: '比赛' },
{ name: 'tab-points', icon: '分', desc: '积分' },
{ name: 'tab-user', icon: '我', desc: '我的' }
];
const normalColor = '#999999';
const activeColor = '#FF6B35';
const size = 81; // 微信推荐 81x81
function generateIconWithCanvas(iconConfig, isActive) {
const canvas = createCanvas(size, size);
const ctx = canvas.getContext('2d');
// 清空背景(透明)
ctx.clearRect(0, 0, size, size);
// 绘制圆形背景
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2 - 4, 0, Math.PI * 2);
ctx.fillStyle = isActive ? activeColor : '#f5f5f5';
ctx.fill();
// 绘制文字
ctx.font = 'bold 32px sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = isActive ? '#ffffff' : normalColor;
ctx.fillText(iconConfig.icon, size / 2, size / 2);
return canvas.toBuffer('image/png');
}
// 简单的 PNG 生成(不依赖 canvas
function generateSimplePNG(iconConfig, isActive) {
// 创建一个简单的 1x1 像素的 PNG 作为占位符
// 实际项目中应该使用真实的图标文件
const color = isActive ? [255, 107, 53] : [153, 153, 153]; // RGB
// 最简单的 PNG 文件头 + IHDR + IDAT + IEND
// 这是一个 8x8 的纯色 PNG
const width = 8;
const height = 8;
// PNG 签名
const signature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
// IHDR chunk
const ihdr = createChunk('IHDR', Buffer.from([
0, 0, 0, width, // width
0, 0, 0, height, // height
8, // bit depth
2, // color type (RGB)
0, // compression
0, // filter
0 // interlace
]));
// IDAT chunk - 简化的图像数据
const zlib = require('zlib');
const rawData = Buffer.alloc((width * 3 + 1) * height);
for (let y = 0; y < height; y++) {
rawData[y * (width * 3 + 1)] = 0; // filter byte
for (let x = 0; x < width; x++) {
const offset = y * (width * 3 + 1) + 1 + x * 3;
rawData[offset] = color[0];
rawData[offset + 1] = color[1];
rawData[offset + 2] = color[2];
}
}
const compressed = zlib.deflateSync(rawData);
const idat = createChunk('IDAT', compressed);
// IEND chunk
const iend = createChunk('IEND', Buffer.alloc(0));
return Buffer.concat([signature, ihdr, idat, iend]);
}
function createChunk(type, data) {
const length = Buffer.alloc(4);
length.writeUInt32BE(data.length);
const typeBuffer = Buffer.from(type);
const crcData = Buffer.concat([typeBuffer, data]);
const crc = crc32(crcData);
const crcBuffer = Buffer.alloc(4);
crcBuffer.writeUInt32BE(crc >>> 0);
return Buffer.concat([length, typeBuffer, data, crcBuffer]);
}
// CRC32 计算
function crc32(data) {
let crc = 0xffffffff;
const table = getCRC32Table();
for (let i = 0; i < data.length; i++) {
crc = table[(crc ^ data[i]) & 0xff] ^ (crc >>> 8);
}
return crc ^ 0xffffffff;
}
let crc32Table = null;
function getCRC32Table() {
if (crc32Table) return crc32Table;
crc32Table = new Uint32Array(256);
for (let i = 0; i < 256; i++) {
let c = i;
for (let j = 0; j < 8; j++) {
c = (c & 1) ? (0xedb88320 ^ (c >>> 1)) : (c >>> 1);
}
crc32Table[i] = c;
}
return crc32Table;
}
// 生成图标
console.log('开始生成 TabBar 图标...\n');
icons.forEach(iconConfig => {
// 生成普通状态图标
const normalPath = path.join(imagesDir, `${iconConfig.name}.png`);
const normalBuffer = useCanvas
? generateIconWithCanvas(iconConfig, false)
: generateSimplePNG(iconConfig, false);
fs.writeFileSync(normalPath, normalBuffer);
console.log(`✓ 已生成: ${iconConfig.name}.png (${iconConfig.desc})`);
// 生成选中状态图标
const activePath = path.join(imagesDir, `${iconConfig.name}-active.png`);
const activeBuffer = useCanvas
? generateIconWithCanvas(iconConfig, true)
: generateSimplePNG(iconConfig, true);
fs.writeFileSync(activePath, activeBuffer);
console.log(`✓ 已生成: ${iconConfig.name}-active.png (${iconConfig.desc} - 选中)`);
});
console.log('\n图标生成完成');
console.log(`图标目录: ${imagesDir}`);
if (!useCanvas) {
console.log('\n提示: 当前生成的是简单占位图标。');
console.log('如需更好的图标效果,请:');
console.log('1. 安装 canvas: npm install canvas');
console.log('2. 重新运行此脚本');
console.log('或者从 iconfont.cn 下载合适的图标替换');
}