41 lines
1.3 KiB
JavaScript
41 lines
1.3 KiB
JavaScript
import sharp from 'sharp';
|
|
import { readdir, rename, unlink } from 'node:fs/promises';
|
|
import { join, resolve } from 'node:path';
|
|
|
|
const iconDirectory = resolve('./static');
|
|
const iconFiles = (await readdir(iconDirectory))
|
|
.filter((file) => file.toLocaleLowerCase().endsWith('.png'))
|
|
.sort((left, right) => left.localeCompare(right));
|
|
|
|
for (const file of iconFiles) {
|
|
const source = join(iconDirectory, file);
|
|
const temporary = join(iconDirectory, `.${file}.trimmed`);
|
|
const before = await sharp(source).metadata();
|
|
|
|
try {
|
|
const result = await sharp(source)
|
|
.trim({ background: { r: 0, g: 0, b: 0, alpha: 0 } })
|
|
.extend({
|
|
top: 2,
|
|
right: 2,
|
|
bottom: 2,
|
|
left: 2,
|
|
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
|
})
|
|
.png({ compressionLevel: 9, adaptiveFiltering: true })
|
|
.toFile(temporary);
|
|
|
|
if (!result.width || !result.height || result.channels !== 4) {
|
|
throw new Error(`${file} did not produce a valid transparent RGBA icon.`);
|
|
}
|
|
|
|
await rename(temporary, source);
|
|
console.log(`${file}: ${before.width}x${before.height} -> ${result.width}x${result.height}`);
|
|
} catch (error) {
|
|
await unlink(temporary).catch(() => {});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
console.log(`Trimmed ${iconFiles.length} static PNG icons with a 2px transparent safety margin.`);
|