import fs from 'fs' ; import path from 'path' ; import del from 'del' ; import os from 'os' ; import { v4 as uuidv4 } from 'uuid' ; import mkdirP from 'mkdirp' ; import generatePNG , { ImageInfo } from './png' ; import generateICO , { REQUIRED_IMAGE_SIZES as ICO_SIZES } from './ico' ; import generateICNS , { REQUIRED_IMAGE_SIZES as ICNS_SIZES } from './icns' ; import generateFavicon , { REQUIRED_IMAGE_SIZES as FAV_SIZES } from './favicon' ; import Logger from './logger' ; /** Options of icon generation. */ export type ICONOptions = { /** Output setting of ICO file. */ ico ? : { /** Name of an output file. */ name ? : string ; /** Structure of an image sizes. */ sizes ? : number [ ] ; } ; /** Output setting of ICNS file. */ icns ? : { /** Name of an output file. */ name ? : string ; /** Structure of an image sizes. */ sizes ? : number [ ] ; } ; /** Output setting of Favicon file (PNG and ICO). */ favicon ? : { /** Prefix of an output PNG files. Start with the alphabet, can use `-` and `_`. This option is for PNG. The name of the ICO file is always `favicon.ico`. */ name ? : string ; /** Size structure of PNG files to output. */ pngSizes ? : number [ ] ; /** Structure of an image sizes for ICO. */ icoSizes ? : number [ ] ; } ; /** `true` to display the processing status of the tool to `stdout`. */ report : boolean ; } ; param sizes param filterSizes return const filterSizes = ( sizes = [ ] , filterSizes = [ ] ) => { if ( filterSizes . length === 0 ) { return sizes ; } return sizes . filter ( ( size ) => { for ( let filterSize of filterSizes ) { if ( size === filterSize ) { return true ; } } return false ; } ) ; } ; param options return const getRequiredPNGImageSizes = ( options ) => { let sizes = [ ] ; if ( options . icns ) { sizes = sizes . concat ( filterSizes ( ICNS_SIZES , options . icns . sizes ) ) ; } if ( options . ico ) { sizes = sizes . concat ( filterSizes ( ICO_SIZES , options . ico . sizes ) ) ; } if ( options . favicon ) { if ( options . favicon . pngSizes ) { sizes = sizes . concat ( options . favicon . pngSizes ) ; } else { sizes = sizes . concat ( FAV_SIZES ) ; } } if ( sizes . length === 0 ) { sizes = FAV_SIZES . concat ( ICNS_SIZES ) . concat ( ICO_SIZES ) ; } return sizes . filter ( ( value , index , array ) => array . indexOf ( value ) === index ) . sort ( ( a , b ) => a - b ) ; } ; param images param dest param options param logger return const generate = async ( images , dest , options , logger ) : Promise < string [ ] > => { if ( ! ( images && 0 < images . length ) ) { throw new Error ( 'Targets is empty.' ) ; } const dir = path . resolve ( dest ) ; mkdirP . sync ( dir ) ; const results = [ ] ; if ( options . icns ) { results . push ( await generateICNS ( images , dir , logger , options . icns ) ) ; } if ( options . ico ) { results . push ( await generateICO ( images , dir , logger , options . ico ) ) ; } if ( options . favicon ) { const files = await generateFavicon ( images , dir , logger , options . favicon ) ; for ( const file of files ) { results . push ( file ) ; } } return results ; } ; param src param dir param options param logger return const generateIconFromPNG = ( src , dir , options , logger ) : Promise < string [ ] > => { const pngDirPath = path . resolve ( src ) ; const destDirPath = path . resolve ( dir ) ; logger . log ( 'Icon generator from PNG:' ) ; logger . log ( '  src: ' + pngDirPath ) ; logger . log ( '  dir: ' + destDirPath ) ; const images = getRequiredPNGImageSizes ( options ) . map ( ( size ) => { return path . join ( pngDirPath , size + '.png' ) ; } ) . map ( ( filePath ) => { const size = Number ( path . basename ( filePath , '.png' ) ) ; return { filePath , size } ; } ) ; let notExistsFile = null ; images . some ( ( image ) => { const stat = fs . statSync ( image . filePath ) ; if ( ! ( stat && stat . isFile ( ) ) ) { notExistsFile = path . basename ( image . filePath ) ; return true ; } return false ; } ) ; if ( notExistsFile ) { throw new Error ( '"' + notExistsFile + '" does not exist.' ) ; } return generate ( images , dir , options , logger ) ; } ; param src param dir param options param logger return const generateIconFromSVG = async ( src , dir , options , logger ) : Promise < string [ ] > => { const svgFilePath = path . resolve ( src ) ; const destDirPath = path . resolve ( dir ) ; logger . log ( 'Icon generator from SVG:' ) ; logger . log ( '  src: ' + svgFilePath ) ; logger . log ( '  dir: ' + destDirPath ) ; const workDir = path . join ( os . tmpdir ( ) , uuidv4 ( ) ) ; fs . mkdirSync ( workDir ) ; if ( ! fs . existsSync ( workDir ) ) { throw new Error ( 'Failed to create the working directory.' ) ; } try { const images = await generatePNG ( svgFilePath , workDir , getRequiredPNGImageSizes ( options ) , logger ) ; const results = await generate ( images , destDirPath , options , logger ) ; del . sync ( [ workDir ] , { force : true } ) ; return results ; } catch ( err ) { del . sync ( [ workDir ] , { force : true } ) ; throw err ; } } ; param src param dest param options return const generateIcon = async ( src , dest , options = { ico : { } , icns : { } , favicon : { } , report : false } ) : Promise < string [ ] > => { if ( ! fs . existsSync ( src ) ) { throw new Error ( 'Input file or directory is not found.' ) ; } if ( ! fs . existsSync ( dest ) ) { throw new Error ( 'Output directory is not found.' ) ; } if ( ! ( options . ico || options . icns || options . favicon ) ) { options . ico = { } ; options . icns = { } ; options . favicon = { } ; } const logger = new Logger ( options . report ) ; if ( fs . statSync ( src ) . isDirectory ( ) ) { return generateIconFromPNG ( src , dest , options , logger ) ; } else { return generateIconFromSVG ( src , dest , options , logger ) ; } } ; export default generateIcon ; module . exports = generateIcon ;