Last active
March 11, 2025 13:41
-
-
Save michaeldll/ea976e723967df998ca346c6ff9e053b to your computer and use it in GitHub Desktop.
Compress KTX2 with toktx using Node.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { exec } from 'child_process'; | |
import fs from 'fs'; | |
import path from 'path'; | |
// This script compresses a single PNG or JPG texture to KTX2 using the Khronos toktx tool. | |
// Uses low quality but highly compressed ETC1S compression by default. | |
// Feel free to extend it! | |
// REQUIREMENTS: | |
// Install toktx 4.3.1 from https://github.com/KhronosGroup/KTX-Software/releases/tag/v4.3.1 | |
// USAGE: | |
// node compress-textures.js [options] input.jpg | |
// OPTIONS: | |
// --high - Use high quality "lossless" UASTC compression | |
// --medium - Use regular "lossless" UASTC compression | |
// --low - Use lossy ETC1S compression | |
// --flip - Flip the texture vertically | |
// --noMipmaps - Do not generate mipmaps | |
// --linear - Use linear color space, e.g. for normal maps and other non-color textures such as ORM maps | |
// EXAMPLE USAGE FOR TEXTURES: | |
// Albedo: --low (=etc1s) | |
// Emissive: --low (=etc1s) | |
// Normal: --high --linear | |
// ORM: --high --linear OR --medium --linear | |
// Transmission: --medium --linear | |
// Clearcoat: --medium --linear | |
// Additional information: https://github.com/KhronosGroup/3D-Formats-Guidelines/blob/main/KTXArtistGuide.md | |
const args = process.argv.slice(2); | |
// Find the input file as the last argument | |
let input = args[args.length - 1]; | |
// Check if input file exists | |
if (!fs.existsSync(input)) { | |
throw new Error('Input file does not exist'); | |
} | |
// Find compression, use ETC1S by default | |
let compression = 'etc1s'; | |
for (let i = 0; i < args.length; i++) { | |
if (args[i] === '--medium') { | |
compression = 'uastc'; | |
} else if (args[i] === '--high') { | |
compression = 'uastcHighQuality'; | |
} | |
} | |
// Check if --flip flag is present | |
let flip = ''; | |
for (let i = 0; i < args.length; i++) { | |
if (args[i] === '--flip') { | |
flip = '--lower_left_maps_to_s0t0'; | |
} | |
} | |
// Build mipmaps by default unless --noMipmaps flag is present | |
let mipmaps = '--genmipmap'; | |
for (let i = 0; i < args.length; i++) { | |
if (args[i] === '--noMipmaps') { | |
mipmaps = ''; | |
} | |
} | |
// Linear color space, e.g. for normal maps | |
let linear = ''; | |
for (let i = 0; i < args.length; i++) { | |
if (args[i] === '--linear') { | |
linear = '--assign_oetf linear --assign_primaries none'; | |
} | |
} | |
// Set compression command | |
let command = ''; | |
if (compression === 'etc1s') { | |
command = '--t2 --encode etc1s --clevel 4 --qlevel 255'; | |
} else if (compression === 'uastc') { | |
command = '--t2 --encode uastc --uastc_quality 4 --uastc_rdo_l .5 --uastc_rdo_d 65536 --zcmp 22'; | |
} else if (compression === 'uastcHighQuality') { | |
command = '--t2 --encode uastc --uastc_quality 4 --uastc_rdo_l .2 --uastc_rdo_d 65536 --zcmp 22'; | |
} | |
// Add new target directory | |
const parent = path.dirname(input); | |
const targetDirectory = parent + '/ktx2'; | |
if (!fs.existsSync(targetDirectory)) { | |
fs.mkdirSync(targetDirectory); | |
} | |
// Set output extensions and path to new targetDirectory | |
const output = targetDirectory + '/' + path.basename(input.replace(/\.[^/.]+$/, '.ktx2')); | |
exec(`toktx ${command} ${flip} ${mipmaps} ${output} ${input}`, (error, stdout, stderr) => { | |
if (error) { | |
console.log(`error when building KTX2: ${error.message}`); | |
return; | |
} | |
if (stderr) { | |
console.log(`stderr when building KTX2: ${stderr}`); | |
return; | |
} | |
console.log('Successfully built KTX2 texture'); | |
}); |
You can use the same logic with either basisu
or ktx create
, yes.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
should we not use ktx create ?