feat: add bidirectional ICO image converter
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
import fs from 'node:fs/promises';
|
||||
import sharp from 'sharp';
|
||||
import { decodeIco, encodeIco } from 'icojs';
|
||||
import { register } from './registry.js';
|
||||
import { sharpFormatName, buildFormatOptions } from './image.js';
|
||||
|
||||
const IMAGE_FORMATS = ['jpg', 'jpeg', 'png', 'webp', 'gif', 'tiff', 'avif'];
|
||||
export const DEFAULT_ICON_SIZE = 256;
|
||||
|
||||
export async function encodeIcoFromInput(input, size = DEFAULT_ICON_SIZE) {
|
||||
const pngBuffer = await sharp(input).resize(size, size, { fit: 'contain' }).png().toBuffer();
|
||||
return Buffer.from(await encodeIco([{ buffer: pngBuffer }]));
|
||||
}
|
||||
|
||||
async function decodeIcoLargestImage(inputPath) {
|
||||
const buffer = await fs.readFile(inputPath);
|
||||
const images = await decodeIco(buffer, 'image/png');
|
||||
return images.reduce((a, b) => (a.width * a.height >= b.width * b.height ? a : b));
|
||||
}
|
||||
|
||||
export function registerIcoConverter() {
|
||||
for (const format of IMAGE_FORMATS) {
|
||||
register({
|
||||
family: 'image',
|
||||
sourceFormat: 'ico',
|
||||
targetFormat: format,
|
||||
convert: async (inputPath, outputPath, { quality } = {}) => {
|
||||
const largest = await decodeIcoLargestImage(inputPath);
|
||||
await sharp(Buffer.from(largest.buffer))
|
||||
.toFormat(sharpFormatName(format), buildFormatOptions(format, quality))
|
||||
.toFile(outputPath);
|
||||
},
|
||||
});
|
||||
|
||||
register({
|
||||
family: 'image',
|
||||
sourceFormat: format,
|
||||
targetFormat: 'ico',
|
||||
convert: async (inputPath, outputPath, { iconSize } = {}) => {
|
||||
const icoBuffer = await encodeIcoFromInput(inputPath, iconSize ?? DEFAULT_ICON_SIZE);
|
||||
await fs.writeFile(outputPath, icoBuffer);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { register } from './registry.js';
|
||||
|
||||
const IMAGE_FORMATS = ['jpg', 'jpeg', 'png', 'webp', 'gif', 'tiff', 'avif'];
|
||||
|
||||
function sharpFormatName(format) {
|
||||
export function sharpFormatName(format) {
|
||||
return format === 'jpg' ? 'jpeg' : format;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user