@@ -5,7 +5,7 @@ const path = require('path');
5
5
const process = require ( 'process' ) ;
6
6
const EventEmitter = require ( 'events' ) ;
7
7
const got = require ( 'got' ) ;
8
- const Jimp = require ( 'jimp-compact ' ) ;
8
+ const sharp = require ( 'sharp ' ) ;
9
9
10
10
const uploadImages = require ( './upload-images' ) ;
11
11
const hashCalc = require ( './hash-calculator' ) ;
@@ -28,7 +28,8 @@ const getIcon = async (filename, item, options) => {
28
28
}
29
29
30
30
const filepath = path . join ( options . filePath || iconCacheFolder , filename ) ;
31
- const sourceImage = await Jimp . read ( filepath ) ;
31
+ const sourceImage = sharp ( filepath ) ;
32
+ const sourceMeta = await sourceImage . metadata ( ) ;
32
33
33
34
if ( ! options . response . generated [ item . id ] ) options . response . generated [ item . id ] = [ ] ;
34
35
if ( ! options . response . uploaded [ item . id ] ) options . response . uploaded [ item . id ] = [ ] ;
@@ -39,13 +40,15 @@ const getIcon = async (filename, item, options) => {
39
40
if ( options . generateOnlyMissing && ! item . needsBaseImage ) {
40
41
return resolve ( false ) ;
41
42
}
42
- resolve ( imageFunctions . createBaseImage ( sourceImage , item ) . then ( result => {
43
+ resolve ( imageFunctions . createBaseImage ( sourceImage , item ) . then ( async baseImage => {
44
+ const baseImagePath = path . join ( './' , 'generated-images' , `${ item . id } -base-image.png` ) ;
45
+ await baseImage . toFile ( baseImagePath ) ;
43
46
options . response . generated [ item . id ] . push ( 'base' ) ;
44
47
if ( item . needsBaseImage && options . upload ) {
45
48
console . log ( `${ item . id } should be uploaded for base-image` ) ;
46
49
fs . copyFileSync ( result . path , path . join ( './' , 'generated-images-missing' , `${ item . id } -base-image.png` ) ) ;
47
50
}
48
- return { path : result . path , type : 'base' } ;
51
+ return { path : baseImagePath , type : 'base' } ;
49
52
} ) ) ;
50
53
} ) ;
51
54
@@ -54,13 +57,15 @@ const getIcon = async (filename, item, options) => {
54
57
if ( options . generateOnlyMissing && ! item . needsIconImage ) {
55
58
return resolve ( false ) ;
56
59
}
57
- resolve ( imageFunctions . createIcon ( sourceImage , item ) . then ( result => {
60
+ resolve ( imageFunctions . createIcon ( sourceImage , item ) . then ( async iconImage => {
61
+ const iconPath = path . join ( './' , 'generated-images' , `${ item . id } -icon.jpg` ) ;
62
+ await iconImage . toFile ( iconPath ) ;
58
63
options . response . generated [ item . id ] . push ( 'icon' ) ;
59
64
if ( item . needsIconImage && options . upload ) {
60
65
console . log ( `${ item . id } should be uploaded for icon` ) ;
61
- fs . copyFileSync ( result . path , path . join ( './' , 'generated-images-missing' , `${ item . id } -icon.jpg` ) ) ;
66
+ fs . copyFileSync ( iconPath , path . join ( './' , 'generated-images-missing' , `${ item . id } -icon.jpg` ) ) ;
62
67
}
63
- return { path : result . path , type : 'icon' } ;
68
+ return { path : iconPath , type : 'icon' } ;
64
69
} ) ) ;
65
70
} ) ;
66
71
@@ -69,52 +74,85 @@ const getIcon = async (filename, item, options) => {
69
74
if ( options . generateOnlyMissing && ! item . needsGridImage ) {
70
75
return resolve ( false ) ;
71
76
}
72
- resolve ( imageFunctions . createGridImage ( sourceImage , item ) . then ( result => {
77
+ resolve ( imageFunctions . createGridImage ( sourceImage , item ) . then ( async gridImage => {
78
+ const gridImagePath = path . join ( './' , 'generated-images' , `${ item . id } -grid-image.jpg` ) ;
79
+ await gridImage . toFile ( gridImagePath ) ;
73
80
options . response . generated [ item . id ] . push ( 'grid image' ) ;
74
81
if ( item . needsGridImage && options . upload ) {
75
82
console . log ( `${ item . id } should be uploaded for grid-image` ) ;
76
- fs . copyFileSync ( result . path , path . join ( './' , 'generated-images-missing' , `${ item . id } -grid-image.jpg` ) ) ;
83
+ fs . copyFileSync ( gridImagePath , path . join ( './' , 'generated-images-missing' , `${ item . id } -grid-image.jpg` ) ) ;
77
84
}
78
- return { path : result . path , type : 'grid' } ;
85
+ return { path : gridImagePath , type : 'grid' } ;
79
86
} ) ) ;
80
87
} ) ;
81
88
82
- // create large image
83
- const largeImagePromise = new Promise ( resolve => {
84
- if ( options . generateOnlyMissing && ! item . needsLargeImage ) {
89
+ // create inspect image
90
+ const inspectImagePromise = new Promise ( resolve => {
91
+ if ( options . generateOnlyMissing && ! item . needsInspectImage ) {
85
92
return resolve ( false ) ;
86
93
}
87
- resolve ( imageFunctions . createLargeImage ( sourceImage , item ) . then ( result => {
88
- options . response . generated [ item . id ] . push ( 'large image' ) ;
89
- if ( item . needsLargeImage && options . upload ) {
90
- console . log ( `${ item . id } should be uploaded for large image` ) ;
91
- fs . copyFileSync ( result . path , path . join ( './' , 'generated-images-missing' , `${ item . id } -large.png` ) ) ;
94
+ resolve ( imageFunctions . createInspectImage ( sourceImage , item ) . then ( async inspectImage => {
95
+ const inspectImagePath = path . join ( './' , 'generated-images' , `${ item . id } -image.jpg` ) ;
96
+ await inspectImage . toFile ( inspectImagePath ) ;
97
+ options . response . generated [ item . id ] . push ( 'inspect image' ) ;
98
+ if ( item . needsInspectImage && options . upload ) {
99
+ console . log ( `${ item . id } should be uploaded for inspect image` ) ;
100
+ fs . copyFileSync ( inspectImagePath , path . join ( './' , 'generated-images-missing' , `${ item . id } -image.jpg` ) ) ;
92
101
}
93
- return { path : result . path , type : 'large ' } ;
102
+ return { path : inspectImagePath , type : 'image ' } ;
94
103
} ) . catch ( error => {
95
- console . log ( `Error creating large image for ${ item . id } ` , error ) ;
104
+ console . log ( `Error creating inspect image for ${ item . id } ` , error ) ;
96
105
return false ;
97
106
} ) ) ;
98
107
} ) ;
99
108
100
- // create inspect image
101
- const inspectImagePromise = new Promise ( resolve => {
102
- if ( options . generateOnlyMissing && ! item . needsInspectImage ) {
109
+ // create 512 image
110
+ const largeImagePromise = new Promise ( async resolve => {
111
+ if ( options . generateOnlyMissing && ! item . needs512Image ) {
103
112
return resolve ( false ) ;
104
113
}
105
- resolve ( imageFunctions . createInspectImage ( sourceImage , item ) . then ( result => {
106
- options . response . generated [ item . id ] . push ( 'inspect image' ) ;
107
- if ( item . needsLargeImage && options . upload ) {
108
- console . log ( `${ item . id } should be uploaded for inspect image` ) ;
109
- fs . copyFileSync ( result . path , path . join ( './' , 'generated-images-missing' , `${ item . id } -image.jpg` ) ) ;
114
+ if ( ! await imageFunctions . canCreate512Image ( sourceMeta ) ) {
115
+ return resolve ( false ) ;
116
+ }
117
+ resolve ( imageFunctions . create512Image ( sourceImage , item ) . then ( async largeImage => {
118
+ const largeImagePath = path . join ( './' , 'generated-images' , `${ item . id } -512.webp` ) ;
119
+ await largeImage . toFile ( largeImagePath ) ;
120
+ options . response . generated [ item . id ] . push ( '512 image' ) ;
121
+ if ( item . needs512Image && options . upload ) {
122
+ console . log ( `${ item . id } should be uploaded for 512 image` ) ;
123
+ fs . copyFileSync ( largeImagePath , path . join ( './' , 'generated-images-missing' , `${ item . id } -512.webp` ) ) ;
110
124
}
111
- return { path : result . path , type : 'image ' } ;
125
+ return { path : largeImagePath , type : '512 ' } ;
112
126
} ) . catch ( error => {
113
- console . log ( `Error creating inspect image for ${ item . id } ` , error ) ;
127
+ console . log ( `Error creating 512 image for ${ item . id } ` , error ) ;
114
128
return false ;
115
129
} ) ) ;
116
130
} ) ;
117
- return Promise . all ( [ baseImagePromise , iconPromise , gridImagePromise , largeImagePromise , inspectImagePromise ] ) . then ( results => {
131
+
132
+ //create 8x image
133
+ const xlImagePromise = new Promise ( async resolve => {
134
+ if ( options . generateOnlyMissing && ! item . needs8xImage ) {
135
+ return resolve ( false ) ;
136
+ }
137
+ if ( ! await imageFunctions . canCreate8xImage ( sourceMeta , item ) ) {
138
+ return resolve ( false ) ;
139
+ }
140
+ resolve ( imageFunctions . create8xImage ( sourceImage , item ) . then ( async xlImage => {
141
+ const imageFilename = imageFunctions . getImageName ( item , '8x' ) ;
142
+ const xlImagePath = path . join ( './' , 'generated-images' , imageFilename ) ;
143
+ await xlImage . toFile ( xlImagePath ) ;
144
+ options . response . generated [ item . id ] . push ( '8x image' ) ;
145
+ if ( item . needs8xImage && options . upload ) {
146
+ console . log ( `${ item . id } should be uploaded for 8x image` ) ;
147
+ fs . copyFileSync ( xlImagePath , path . join ( './' , 'generated-images-missing' , imageFilename ) ) ;
148
+ }
149
+ return { path : xlImagePath , type : '8x' } ;
150
+ } ) . catch ( error => {
151
+ console . log ( `Error creating 8x image for ${ item . id } ` , error ) ;
152
+ } ) ) ;
153
+ } ) ;
154
+
155
+ return Promise . all ( [ baseImagePromise , iconPromise , gridImagePromise , largeImagePromise , inspectImagePromise , xlImagePromise ] ) . then ( results => {
118
156
return results . filter ( Boolean ) ;
119
157
} ) . catch ( error => {
120
158
console . log ( error ) ;
@@ -241,7 +279,6 @@ const hashItems = async (options) => {
241
279
responseType : 'json' ,
242
280
resolveBodyOnly : true
243
281
} ) ;
244
- hashCalc . init ( bsgData , bsgPresets , presets ) ;
245
282
let missingGridImage = 0 ;
246
283
let missingIcon = 0 ;
247
284
let missingBaseImage = 0 ;
@@ -254,7 +291,8 @@ const hashItems = async (options) => {
254
291
itemData . needsIconImage = false ;
255
292
itemData . needsBaseImage = false ;
256
293
itemData . needsInspectImage = false ;
257
- itemData . needsLargeImage = false ;
294
+ itemData . needs512Image = false ;
295
+ itemData . needs8xImage = false ;
258
296
if ( itemData . gridImageLink . includes ( 'unknown-item' ) ) {
259
297
itemData . needsGridImage = true ;
260
298
missingGridImage ++ ;
@@ -296,6 +334,63 @@ const hashItems = async (options) => {
296
334
}
297
335
} ;
298
336
337
+ const getItemWithHash = async ( options ) => {
338
+ let item = false ;
339
+ if ( options . targetItemId ) {
340
+ if ( ! itemsById [ options . targetItemId ] ) {
341
+ await hashItems ( options ) ;
342
+ }
343
+ item = itemsById [ options . targetItemId ] ;
344
+ } else {
345
+ item = options . item ;
346
+ options . targetItemId = item . id ;
347
+ if ( ! item . backgroundColor ) {
348
+ setBackgroundColor ( item ) ;
349
+ }
350
+ try {
351
+ item . hash = hashCalc . getItemHash ( item . id ) ;
352
+ if ( ! itemsByHash [ item . hash . toString ( ) ] ) {
353
+ itemsByHash [ item . hash . toString ( ) ] = item ;
354
+ }
355
+ } catch ( error ) {
356
+ console . log ( `Error hashing ${ item . id } : ${ error } ` ) ;
357
+ }
358
+ }
359
+ return item ;
360
+ } ;
361
+
362
+ const getIconCacheNumberForItem = async ( item , options ) => {
363
+ options = {
364
+ cacheUpdateTimeout : 0 ,
365
+ ...options
366
+ } ;
367
+ if ( ( Array . isArray ( item . types ) && ( item . types . includes ( 'gun' ) || item . types . includes ( 'preset' ) ) ) ) {
368
+ return Promise . reject ( new Error ( 'Cannot hash weapons and presets' ) ) ;
369
+ }
370
+ const hash = item . hash ;
371
+ if ( ! hash ) return Promise . reject ( new Error ( `Item ${ item . id } has no hash` ) ) ;
372
+ if ( ! iconData [ hash ] ) {
373
+ await new Promise ( ( resolve , reject ) => {
374
+ const cacheUpdateFunc = ( ) => {
375
+ if ( iconData [ hash ] ) {
376
+ clearTimeout ( cacheUpdateTimeout ) ;
377
+ cacheListener . off ( cacheUpdateFunc ) ;
378
+ resolve ( ) ;
379
+ }
380
+ } ;
381
+ const cacheUpdateTimeout = setTimeout ( ( ) => {
382
+ if ( iconData [ hash ] ) {
383
+ cacheListener . off ( cacheUpdateFunc ) ;
384
+ return resolve ( ) ;
385
+ }
386
+ reject ( new Error ( `Item ${ item . id } hash ${ hash } not found in cache` ) ) ;
387
+ } , options . cacheUpdateTimeout ) ;
388
+ cacheListener . on ( 'refresh' , cacheUpdateFunc ) ;
389
+ } ) ;
390
+ }
391
+ return iconData [ hash ] ;
392
+ } ;
393
+
299
394
const initialize = async ( options ) => {
300
395
const defaultOptions = {
301
396
skipHashing : false
@@ -311,6 +406,7 @@ const initialize = async (options) => {
311
406
await loadBsgData ( opts ) ;
312
407
await loadPresets ( opts ) ;
313
408
await loadBsgPresets ( opts ) ;
409
+ hashCalc . init ( bsgData , bsgPresets , presets ) ;
314
410
if ( ! options . skipHashing ) {
315
411
await hashItems ( opts ) ;
316
412
}
@@ -354,6 +450,7 @@ const generate = async (options, forceImageIndex) => {
354
450
if ( ! bsgPresets ) {
355
451
await loadBsgPresets ( options ) ;
356
452
}
453
+ hashCalc . init ( bsgData , bsgPresets , presets ) ;
357
454
if ( ! cacheIsLoaded ( ) ) {
358
455
refreshCache ( ) ;
359
456
}
@@ -383,47 +480,13 @@ const generate = async (options, forceImageIndex) => {
383
480
}
384
481
385
482
if ( options . targetItemId || options . item ) {
386
- let item = false ;
387
- if ( options . targetItemId ) {
388
- if ( ! itemsById [ options . targetItemId ] ) {
389
- await hashItems ( options ) ;
390
- }
391
- item = itemsById [ options . targetItemId ] ;
392
- } else {
393
- item = options . item ;
394
- options . targetItemId = item . id ;
395
- if ( ! item . backgroundColor ) {
396
- setBackgroundColor ( item ) ;
397
- }
398
- try {
399
- hashCalc . init ( bsgData , bsgPresets , presets ) ;
400
- item . hash = hashCalc . getItemHash ( item . id ) ;
401
- if ( ! itemsByHash [ item . hash . toString ( ) ] ) {
402
- itemsByHash [ item . hash . toString ( ) ] = item ;
403
- }
404
- } catch ( error ) {
405
- console . log ( `Error hashing ${ item . id } : ${ error } ` ) ;
406
- }
407
- }
408
- if ( ! item ) return Promise . reject ( new Error ( `Item ${ options . targetItemId } is unknown` ) ) ;
483
+ let item = await getItemWithHash ( options ) ;
484
+ if ( ! item ) return Promise . reject ( new Error ( `Item ${ options . targetItemId || options . item . id } is unknown` ) ) ;
409
485
let fileName = `${ options . forceImageIndex } .png` ;
410
486
if ( ! options . forceImageIndex ) {
411
487
const hash = item . hash ;
412
- if ( ! hash ) return Promise . reject ( new Error ( `Item ${ options . targetItemId } has no hash` ) ) ;
413
- if ( ! iconData [ hash ] ) {
414
- try {
415
- if ( options . cacheUpdateTimeout === false || ( Array . isArray ( item . types ) && item . types . includes ( 'gun' ) ) ) {
416
- throw new Error ( 'not found' ) ;
417
- }
418
- await cacheChanged ( options . cacheUpdateTimeout ) ;
419
- if ( ! iconData [ hash ] ) {
420
- throw new Error ( 'not found' ) ;
421
- }
422
- } catch ( error ) {
423
- return Promise . reject ( new Error ( `Item ${ options . targetItemId } hash ${ hash } not found in cache` ) ) ;
424
- }
425
- }
426
- fileName = `${ iconData [ hash ] } .png` ;
488
+ if ( ! hash ) return Promise . reject ( new Error ( `Item ${ options . targetItemId || options . item . id } has no hash` ) ) ;
489
+ fileName = `${ await getIconCacheNumberForItem ( item , options ) } .png` ;
427
490
}
428
491
try {
429
492
await getIcon ( fileName , item , options ) ;
@@ -518,5 +581,17 @@ module.exports = {
518
581
}
519
582
} ,
520
583
getImagesFromSource : getIcon ,
521
- imageFunctions : imageFunctions
584
+ imageFunctions : imageFunctions ,
585
+ getIconCachePath : async ( options ) => {
586
+ if ( typeof options === 'string' )
587
+ options = { targetItemId : options } ;
588
+ let item = await getItemWithHash ( options ) ;
589
+ if ( ! item )
590
+ return Promise . reject ( new Error ( `Item ${ options . targetItemId || options . item . id } is unknown` ) ) ;
591
+ const hash = item . hash ;
592
+ if ( ! hash )
593
+ return Promise . reject ( new Error ( `Item ${ options . targetItemId || options . item . id } has no hash` ) ) ;
594
+ const filename = `${ await getIconCacheNumberForItem ( item , options ) } .png` ;
595
+ return path . join ( options . filePath || iconCacheFolder , filename ) ;
596
+ }
522
597
} ;
0 commit comments