diff --git a/public/images/items/armors-table_thumb.jpg b/public/images/items/armors-table_thumb.jpg index 1e0cfb11c..2db14af9c 100644 Binary files a/public/images/items/armors-table_thumb.jpg and b/public/images/items/armors-table_thumb.jpg differ diff --git a/public/images/items/backpacks-table_thumb.jpg b/public/images/items/backpacks-table_thumb.jpg index d2c6de73b..9d7ce9401 100644 Binary files a/public/images/items/backpacks-table_thumb.jpg and b/public/images/items/backpacks-table_thumb.jpg differ diff --git a/public/images/items/barter-items-table_thumb.jpg b/public/images/items/barter-items-table_thumb.jpg index 830ff1a35..9a1a78076 100644 Binary files a/public/images/items/barter-items-table_thumb.jpg and b/public/images/items/barter-items-table_thumb.jpg differ diff --git a/public/images/items/containers-table_thumb.jpg b/public/images/items/containers-table_thumb.jpg index dee7f80ad..f9014eb1c 100644 Binary files a/public/images/items/containers-table_thumb.jpg and b/public/images/items/containers-table_thumb.jpg differ diff --git a/public/images/items/glasses-table_thumb.jpg b/public/images/items/glasses-table_thumb.jpg index 474c84e92..6b291ce39 100644 Binary files a/public/images/items/glasses-table_thumb.jpg and b/public/images/items/glasses-table_thumb.jpg differ diff --git a/public/images/items/grenades-table_thumb.jpg b/public/images/items/grenades-table_thumb.jpg index 7a2b6f603..7494a5c42 100644 Binary files a/public/images/items/grenades-table_thumb.jpg and b/public/images/items/grenades-table_thumb.jpg differ diff --git a/public/images/items/guns-table_thumb.jpg b/public/images/items/guns-table_thumb.jpg index e253ad6d1..0c50954b3 100644 Binary files a/public/images/items/guns-table_thumb.jpg and b/public/images/items/guns-table_thumb.jpg differ diff --git a/public/images/items/headsets-table_thumb.jpg b/public/images/items/headsets-table_thumb.jpg index 731f0cb14..445de3b06 100644 Binary files a/public/images/items/headsets-table_thumb.jpg and b/public/images/items/headsets-table_thumb.jpg differ diff --git a/public/images/items/helmets-table_thumb.jpg b/public/images/items/helmets-table_thumb.jpg index b3b20be7c..1f87d53f6 100644 Binary files a/public/images/items/helmets-table_thumb.jpg and b/public/images/items/helmets-table_thumb.jpg differ diff --git a/public/images/items/keys-table_thumb.jpg b/public/images/items/keys-table_thumb.jpg index 6268c802d..af522bbbc 100644 Binary files a/public/images/items/keys-table_thumb.jpg and b/public/images/items/keys-table_thumb.jpg differ diff --git a/public/images/items/mods-table_thumb.jpg b/public/images/items/mods-table_thumb.jpg index fc20cf4f1..b1a525257 100644 Binary files a/public/images/items/mods-table_thumb.jpg and b/public/images/items/mods-table_thumb.jpg differ diff --git a/public/images/items/pistol-grips-table_thumb.jpg b/public/images/items/pistol-grips-table_thumb.jpg index b3954c1f2..bfb447f82 100644 Binary files a/public/images/items/pistol-grips-table_thumb.jpg and b/public/images/items/pistol-grips-table_thumb.jpg differ diff --git a/public/images/items/provisions-table_thumb.jpg b/public/images/items/provisions-table_thumb.jpg index ef4ee8f96..9a5de4e26 100644 Binary files a/public/images/items/provisions-table_thumb.jpg and b/public/images/items/provisions-table_thumb.jpg differ diff --git a/public/images/items/rigs-table_thumb.jpg b/public/images/items/rigs-table_thumb.jpg index 556948691..409e944d6 100644 Binary files a/public/images/items/rigs-table_thumb.jpg and b/public/images/items/rigs-table_thumb.jpg differ diff --git a/public/images/items/suppressors-table_thumb.jpg b/public/images/items/suppressors-table_thumb.jpg index 662ae98a1..056607f6b 100644 Binary files a/public/images/items/suppressors-table_thumb.jpg and b/public/images/items/suppressors-table_thumb.jpg differ diff --git a/scripts/generate_items_thumbs.js b/scripts/generate_items_thumbs.js new file mode 100644 index 000000000..5a255ee74 --- /dev/null +++ b/scripts/generate_items_thumbs.js @@ -0,0 +1,147 @@ +const fs = require('fs'); +const path = require('path'); +const sharp = require('sharp'); + +const fetch = require('cross-fetch'); + +const categoryPages = require('../src/data/category-pages.json'); +const { exit } = require('process'); + + +const ignoredCategories = [ + 'headsets', + 'helmets', + 'glasses', + 'armors', + 'rigs', + 'backpacks', + 'guns', + // 'mods', + 'pistol-grips', + 'suppressors', + 'grenades', + 'containers', + 'barter-items', + 'keys', + 'provisions' +]; + +const graphqlRequest = (queryString) => { + return fetch('https://api.tarkov.dev/graphql', { + method: 'POST', + cache: 'no-store', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ + query: queryString + }), + }).then(response => response.json()); +}; + +function shuffle(array) { + let currentIndex = array.length; + let randomIndex; + + // While there remain elements to shuffle. + while (currentIndex > 0) { + // Pick a remaining element. + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex--; + + // And swap it with the current element. + [array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]]; + } + + return array; +} + +(async () => { + try { + console.time('Generating thumbnails'); + + const maxWidth = 256; + const maxHeight = 144; + const mapsPath = './public/images/items/'; + + for (const categoryPage of categoryPages) { + if (ignoredCategories.includes(categoryPage.key)) { + continue + } + + const originalImg = await sharp(mapsPath + categoryPage.key + '-table.png'); + const metadata = await originalImg.metadata(); + const scale = metadata.width / maxWidth; + const cropHeight = Math.ceil(scale * maxHeight); + const itemWidth = metadata.width / 2; + const itemHeight = cropHeight / 2; + + const croppedImage = originalImg.extract({ left: 0, top: 0, width: metadata.width, height: cropHeight }); + // const croppedImage = await sharp({ + // create: { + // width: metadata.width, + // height: cropHeight, + // channels: 4, + // background: { r: 45, g: 45, b: 47, alpha: 1.0 } + // } + // }).png(); + + let type = categoryPage.type; + const query = `{ + items(type: ${type}, limit:420) { + image512pxLink + } + }`; + const itemsOfType = await graphqlRequest(query); + + const items = itemsOfType.data.items; + shuffle(items); + + const itemResize = {width: itemWidth, height: itemHeight, fit: sharp.fit.contain, background: { r: 255, g: 255, b: 255, alpha: 0.0 }}; + const itemRotate = 0; //7 + Math.random()*4-2; + + const tlImageFetch = await fetch(items[0].image512pxLink); + const tlImageBuffer = await tlImageFetch.buffer(); + const tlImage = await sharp(tlImageBuffer).resize(itemResize).rotate(-itemRotate).toBuffer(); + + const trImageFetch = await fetch(items[1].image512pxLink); + const trImageBuffer = await trImageFetch.buffer(); + const trImage = await sharp(trImageBuffer).resize(itemResize).rotate(itemRotate).toBuffer(); + + const blImageFetch = await fetch(items[2].image512pxLink); + const blImageBuffer = await blImageFetch.buffer(); + const blImage = await sharp(blImageBuffer).resize(itemResize).rotate(itemRotate).toBuffer(); + + const brImageFetch = await fetch(items[3].image512pxLink); + const brImageBuffer = await brImageFetch.buffer(); + const brImage = await sharp(brImageBuffer).resize(itemResize).rotate(-itemRotate).toBuffer(); + + const cImageFetch = await fetch(items[4].image512pxLink); + const cImageBuffer = await cImageFetch.buffer(); + const cImage = await sharp(cImageBuffer).resize(itemResize).toBuffer(); + + const composedImage = await croppedImage + .blur(6) + .composite([ + { input: tlImage, gravity: 'northwest', blend: 'over' }, + { input: trImage, gravity: 'northeast', blend: 'over' }, + { input: blImage, gravity: 'southwest', blend: 'over' }, + { input: brImage, gravity: 'southeast', blend: 'over' }, + { input: cImage, gravity: 'centre', blend: 'over' }, + ]).toBuffer(); + + const finalImage = await sharp(composedImage).resize(maxWidth, maxHeight).jpeg({mozjpeg: true, quality: 100}); + // const finalImage = await sharp(composedImage).jpeg({mozjpeg: true, quality: 90}); + + await finalImage.toFile(mapsPath + categoryPage.key + '-table_thumb.jpg'); + + console.log(`Generated thumbnail for ${categoryPage.key}`); + // return; + }; + console.timeEnd('Generating thumbnails'); + } catch (error) { + console.error(error) + console.log('error generating thumbnail (offline mode?)') + } +})(); diff --git a/src/data/category-pages.json b/src/data/category-pages.json index b902b1e5e..8b86d723c 100644 --- a/src/data/category-pages.json +++ b/src/data/category-pages.json @@ -2,76 +2,91 @@ { "key": "headsets", "displayText": "Headsets", - "icon": "mdiHeadset" + "icon": "mdiHeadset", + "type": "headphones" }, { "key": "helmets", "displayText": "Helmets", - "icon": "mdiRacingHelmet" + "icon": "mdiRacingHelmet", + "type": "helmet" }, { "key": "glasses", "displayText": "Glasses", - "icon": "mdiSunglasses" + "icon": "mdiSunglasses", + "type": "glasses" }, { "key": "armors", "displayText": "Armors", - "icon": "mdiTshirtCrew" + "icon": "mdiTshirtCrew", + "type": "armor" }, { "key": "rigs", "displayText": "Rigs", - "icon": "mdiTshirtCrewOutline" + "icon": "mdiTshirtCrewOutline", + "type": "rig" }, { "key": "backpacks", "displayText": "Backpacks", - "icon": "mdiBagPersonal" + "icon": "mdiBagPersonal", + "type": "backpack" }, { "key": "guns", "displayText": "Guns", - "icon": "mdiPistol" + "icon": "mdiPistol", + "type": "preset" }, { "key": "mods", "displayText": "Mods", - "icon": "mdiMagazineRifle" + "icon": "mdiMagazineRifle", + "type": "mods" }, { "key": "pistol-grips", "displayText": "Pistol Grips", - "icon": "mdiHandPointingLeft" + "icon": "mdiHandPointingLeft", + "type": "pistolGrip" }, { "key": "suppressors", "displayText": "Suppressors", - "icon": "mdiBottleWine" + "icon": "mdiBottleWine", + "type": "suppressor" }, { "key": "grenades", "displayText": "Grenades", - "icon": "mdiGasCylinder" + "icon": "mdiGasCylinder", + "type": "grenade" }, { "key": "containers", "displayText": "Containers", - "icon": "mdiArchive" + "icon": "mdiArchive", + "type": "container" }, { "key": "barter-items", "displayText": "Barter Items", - "icon": "mdiPliers" + "icon": "mdiPliers", + "type": "barter" }, { "key": "keys", "displayText": "Keys", - "icon": "mdiKeyVariant" + "icon": "mdiKeyVariant", + "type": "keys" }, { "key": "provisions", "displayText": "Provisions", - "icon": "mdiFoodForkDrink" + "icon": "mdiFoodForkDrink", + "type": "provisions" } ]