11import sharp from 'sharp' ;
22import path from 'path' ;
3- import fs from 'fs' ;
3+ import fs from 'fs/promises ' ;
44import pngToIco from 'png-to-ico' ;
55import { fileURLToPath } from 'url' ;
66
@@ -20,76 +20,128 @@ const SETTINGS = {
2020
2121const transparent = { r : 0 , g : 0 , b : 0 , alpha : 0 } ;
2222
23- SETTINGS . androidChromeIconSizes . forEach ( ( size ) => {
24- generateIcon ( {
25- size,
26- padding : Math . floor ( size / 20 ) ,
23+ try {
24+ SETTINGS . androidChromeIconSizes . forEach ( async ( size ) => {
25+ await generateIcon ( {
26+ size,
27+ padding : Math . floor ( size / 20 ) ,
28+ inputFilename : SETTINGS . iconLightFilename ,
29+ outputFilename : `android-chrome-${ size } x${ size } .png` ,
30+ background : transparent ,
31+ } )
32+ } ) ;
33+
34+ SETTINGS . appleTouchIconSizes . forEach ( async ( size ) => {
35+ await generateIcon ( {
36+ size,
37+ padding : Math . floor ( size / 10 ) ,
38+ inputFilename : SETTINGS . iconDarkFilename ,
39+ outputFilename : `apple-touch-icon-${ size } x${ size } .png` ,
40+ background : { r : 255 , g : 255 , b : 255 , alpha : 1 } ,
41+ } ) ;
42+ } ) ;
43+
44+ SETTINGS . faviconSizes . forEach ( async ( size ) => {
45+ await generateIcon ( {
46+ size,
47+ padding : 0 ,
48+ inputFilename : SETTINGS . iconDarkFilename ,
49+ outputFilename : `favicon-${ size } x${ size } .png` ,
50+ background : transparent ,
51+ } ) ;
52+ } ) ;
53+
54+ SETTINGS . faviconSizes . forEach ( async ( size ) => {
55+ await generateIcon ( {
56+ size,
57+ padding : 0 ,
58+ inputFilename : SETTINGS . iconLightFilename ,
59+ outputFilename : `favicon-dark-mode-${ size } x${ size } .png` ,
60+ background : transparent ,
61+ } ) ;
62+ } ) ;
63+
64+ const faviconBuffer = await pngToIco ( SETTINGS . faviconSizes . map ( ( size ) => path . join ( __dirname , SETTINGS . outputDirectory , `favicon-${ size } x${ size } .png` ) ) ) ;
65+ await fs . writeFile ( path . join ( __dirname , SETTINGS . outputDirectory , 'favicon.ico' ) , faviconBuffer ) ;
66+
67+ const faviconDarkBuffer = await pngToIco ( SETTINGS . faviconSizes . map ( ( size ) => path . join ( __dirname , SETTINGS . outputDirectory , `favicon-dark-mode-${ size } x${ size } .png` ) ) ) ;
68+ await fs . writeFile ( path . join ( __dirname , SETTINGS . outputDirectory , 'favicon-dark-mode.ico' ) , faviconDarkBuffer ) ;
69+
70+ // MS Tile icons - these are more faffy as regards padding and sizes
71+ await generateIcon ( {
72+ size : 144 ,
73+ padding : 0 ,
2774 inputFilename : SETTINGS . iconLightFilename ,
28- outputFilename : `android-chrome- ${ size } x ${ size } .png` ,
75+ outputFilename : 'mstile-144x144 .png' ,
2976 background : transparent ,
30- } )
31- } ) ;
32-
33- SETTINGS . appleTouchIconSizes . forEach ( ( size ) => {
34- generateIcon ( {
35- size,
36- padding : Math . floor ( size / 10 ) ,
37- inputFilename : SETTINGS . iconDarkFilename ,
38- outputFilename : `apple-touch-icon-${ size } x${ size } .png` ,
39- background : { r : 255 , g : 255 , b : 255 , alpha : 1 } ,
4077 } ) ;
41- } ) ;
4278
43- SETTINGS . faviconSizes . forEach ( ( size ) => {
44- generateIcon ( {
45- size ,
46- padding : 0 ,
47- inputFilename : SETTINGS . iconDarkFilename ,
48- outputFilename : `favicon- ${ size } x ${ size } .png` ,
79+ await generateIcon ( {
80+ width : 128 ,
81+ height : 81 ,
82+ padding : 16 ,
83+ inputFilename : SETTINGS . iconLightFilename ,
84+ outputFilename : 'mstile-70x70 .png' ,
4985 background : transparent ,
5086 } ) ;
51- } ) ;
5287
53- SETTINGS . faviconSizes . forEach ( ( size ) => {
54- generateIcon ( {
55- size,
56- padding : 0 ,
88+ await generateIcon ( {
89+ width : 270 ,
90+ height : 208 ,
91+ xPadding : 70 ,
92+ yPadding : 50 ,
5793 inputFilename : SETTINGS . iconLightFilename ,
58- outputFilename : `favicon-dark-mode- ${ size } x ${ size } .png` ,
94+ outputFilename : 'mstile-150x150 .png' ,
5995 background : transparent ,
6096 } ) ;
61- } ) ;
6297
63- pngToIco ( SETTINGS . faviconSizes . map ( ( size ) => path . join ( __dirname , SETTINGS . outputDirectory , `favicon-${ size } x${ size } .png` ) ) )
64- . then ( buf => {
65- fs . writeFileSync ( path . join ( __dirname , SETTINGS . outputDirectory , 'favicon.ico' ) , buf ) ;
98+ await generateIcon ( {
99+ width : 558 ,
100+ height : 208 ,
101+ xPadding : 216 ,
102+ yPadding : 50 ,
103+ inputFilename : SETTINGS . iconLightFilename ,
104+ outputFilename : 'mstile-310x150.png' ,
105+ background : transparent ,
66106 } ) ;
67107
68- pngToIco ( SETTINGS . faviconSizes . map ( ( size ) => path . join ( __dirname , SETTINGS . outputDirectory , `favicon-dark-mode-${ size } x${ size } .png` ) ) )
69- . then ( buf => {
70- fs . writeFileSync ( path . join ( __dirname , SETTINGS . outputDirectory , 'favicon-dark-mode.ico' ) , buf ) ;
108+ await generateIcon ( {
109+ width : 558 ,
110+ height : 430 ,
111+ xPadding : 150 ,
112+ yPadding : 128 ,
113+ inputFilename : SETTINGS . iconLightFilename ,
114+ outputFilename : 'mstile-310x310.png' ,
115+ background : transparent ,
71116 } ) ;
117+ } catch ( error ) {
118+ console . error ( 'Error generating icons:' , error ) ;
119+ }
72120
73121/**
74122 * @param {Object } options - Options for generating the icon
75- * @param {number } options.size - The size of the icon to generate
76- * @param {number } options.padding - The margin to apply around the icon
123+ * @param {number } options.size - The size (width and height) of the icon to generate
124+ * @param {number } options.width - The width of the icon (overrides options.size)
125+ * @param {number } options.height - The height of the icon (overrides options.size)
126+ * @param {number } options.padding - The padding (horizontal and vertical) to apply around the icon
127+ * @param {number } options.xPadding - The horizontal padding to apply around the icon (overrides options.padding)
128+ * @param {number } options.yPadding - The vertical padding to apply around the icon (overrides options.padding)
77129 * @param {string } options.inputFilename - The input SVG file to use as the base for the icon (no directory needed)
78130 * @param {string } options.outputFilename - The filename for the generated icon (no directory needed)
79131 * @param {Object | string } options.background - The background color or an object with r, g, b, alpha properties
80132 */
81- function generateIcon ( options ) {
133+ async function generateIcon ( options ) {
82134 const img = sharp ( path . join ( __dirname , options . inputFilename ) )
83135 . resize ( {
84- width : ( options . size - ( 2 * options . padding ) ) ,
85- height : ( options . size - ( 2 * options . padding ) ) ,
136+ width : ( ( options . width ?? options . size ) - ( 2 * ( options . xPadding ?? options . padding ) ) ) ,
137+ height : ( ( options . height ?? options . size ) - ( 2 * ( options . yPadding ?? options . padding ) ) ) ,
86138 fit : 'contain' ,
87139 background : options . background
88140 } ) . extend ( {
89- top : options . padding ,
90- bottom : options . padding ,
91- left : options . padding ,
92- right : options . padding ,
141+ top : options . yPadding ?? options . padding ,
142+ bottom : options . yPadding ?? options . padding ,
143+ left : options . xPadding ?? options . padding ,
144+ right : options . xPadding ?? options . padding ,
93145 background : options . background ,
94146 } ) ;
95147
@@ -102,8 +154,5 @@ function generateIcon(options) {
102154 . toFile ( path . join ( __dirname , SETTINGS . outputDirectory , options . outputFilename ) )
103155 . then ( ( ) => {
104156 console . log ( `Generated icon: ${ options . outputFilename } ` ) ;
105- } )
106- . catch ( ( err ) => {
107- console . error ( `Error generating icon: ${ options . outputFilename } - ` , err ) ;
108157 } ) ;
109158}
0 commit comments