import type { ImageConverter } from './image.js'; import { MIME_PNG } from './image.js'; import decodeIco from 'decode-ico'; /** * Decoded image object. */ interface DecodeImage { /** Image width. */ readonly width: number; /** Image height. */ readonly height: number; /** Color depth as bits per pixel. */ readonly bpp: number; /** Image buffer. */ readonly buffer: ArrayBuffer; /** Cursor hotspot coordinates. This field is present only when the format is CUR. */ readonly hotspot?: { readonly x: number; readonly y: number; }; } interface IconData { readonly type: string; readonly data: Uint8Array | Uint8ClampedArray; readonly width: number; readonly height: number; readonly bpp: number; } /** * Decode an ICO buffer into images. * * @param data - ICO file buffer. * @param mime - MIME type for output. * @param imageConverter - Image encoder/decoder. * @returns Resolves to an array of decoded image objects. * @private */ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types const decode = async (data: ArrayBuffer | Buffer, mime: string, imageConverter: ImageConverter): Promise> => { const icons = decodeIco(data); // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types const transcodeImage = async (icon: IconData): Promise => { if (mime === MIME_PNG && icon.type === 'png') { return { ...icon, buffer: new Uint8Array(icon.data).buffer }; } if (icon.type === 'png') { const decoded = await imageConverter.decode(new Uint8Array(icon.data).buffer); Object.assign(icon, { data: decoded.data, type: 'bmp' }); } return Object.assign(icon, { buffer: await imageConverter.encode(icon, mime), type: mime.replace('image/', '') }); }; const decodedImages = await Promise.all(icons.map(transcodeImage)); return decodedImages; }; export type { DecodeImage }; export { decode }; export default decode;