(Feat) Init WebSite
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import sharp from "sharp";
|
||||
import { writeFileSync, readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
const ROOT = resolve(import.meta.dirname, "..");
|
||||
const SOURCE = resolve(ROOT, "public/image/Studio/Logo Flat.png");
|
||||
const OUT_ICON_PNG = resolve(ROOT, "app/icon.png");
|
||||
const OUT_FAVICON_ICO = resolve(ROOT, "app/favicon.ico");
|
||||
const OUT_PUBLIC_PNG = resolve(ROOT, "public/image/Studio/favicon.png");
|
||||
|
||||
const SIZE = 512;
|
||||
const MOUNTAIN_FILL = 0.78;
|
||||
|
||||
async function makeFavicon(size) {
|
||||
const circle = Buffer.from(
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}">
|
||||
<circle cx="${size / 2}" cy="${size / 2}" r="${size / 2}" fill="#000000"/>
|
||||
</svg>`
|
||||
);
|
||||
|
||||
const mountainTargetW = Math.round(size * MOUNTAIN_FILL);
|
||||
const mountain = await sharp(SOURCE)
|
||||
.resize({ width: mountainTargetW })
|
||||
.toBuffer();
|
||||
const mountainMeta = await sharp(mountain).metadata();
|
||||
|
||||
return sharp(circle)
|
||||
.composite([
|
||||
{
|
||||
input: mountain,
|
||||
top: Math.round((size - mountainMeta.height) / 2) + Math.round(size * 0.03),
|
||||
left: Math.round((size - mountainMeta.width) / 2),
|
||||
},
|
||||
])
|
||||
.png()
|
||||
.toBuffer();
|
||||
}
|
||||
|
||||
function buildIco(pngBuffers) {
|
||||
const count = pngBuffers.length;
|
||||
const header = Buffer.alloc(6);
|
||||
header.writeUInt16LE(0, 0);
|
||||
header.writeUInt16LE(1, 2);
|
||||
header.writeUInt16LE(count, 4);
|
||||
|
||||
const dirEntries = [];
|
||||
let offset = 6 + count * 16;
|
||||
for (const { buffer, size } of pngBuffers) {
|
||||
const entry = Buffer.alloc(16);
|
||||
entry.writeUInt8(size === 256 ? 0 : size, 0);
|
||||
entry.writeUInt8(size === 256 ? 0 : size, 1);
|
||||
entry.writeUInt8(0, 2);
|
||||
entry.writeUInt8(0, 3);
|
||||
entry.writeUInt16LE(1, 4);
|
||||
entry.writeUInt16LE(32, 6);
|
||||
entry.writeUInt32LE(buffer.length, 8);
|
||||
entry.writeUInt32LE(offset, 12);
|
||||
dirEntries.push(entry);
|
||||
offset += buffer.length;
|
||||
}
|
||||
|
||||
return Buffer.concat([header, ...dirEntries, ...pngBuffers.map((p) => p.buffer)]);
|
||||
}
|
||||
|
||||
const big = await makeFavicon(SIZE);
|
||||
writeFileSync(OUT_ICON_PNG, big);
|
||||
writeFileSync(OUT_PUBLIC_PNG, big);
|
||||
|
||||
const icoSizes = [16, 32, 48];
|
||||
const icoPngs = await Promise.all(
|
||||
icoSizes.map(async (s) => ({
|
||||
size: s,
|
||||
buffer: await sharp(big).resize(s, s).png({ compressionLevel: 9 }).toBuffer(),
|
||||
}))
|
||||
);
|
||||
writeFileSync(OUT_FAVICON_ICO, buildIco(icoPngs));
|
||||
|
||||
console.log("icon.png:", big.length, "bytes");
|
||||
console.log("favicon.ico:", readFileSync(OUT_FAVICON_ICO).length, "bytes");
|
||||
Reference in New Issue
Block a user