.TH "msc_basis_transcoder" 3 "Sun Jun 14 2026 18:00:57" "Version 0.0.0" "KTX Javascript Wrappers Reference" \" -*- nroff -*- .ad l .nh .SH NAME msc_basis_transcoder \- Basis Universal Image Transcoder binding .PP .PP \fBWarning\fP .RS 4 Deprecated\&. Use the container independent transcoder from the Binomial LLC repo instead: https://github.com/BinomialLLC/basis_universal\&. This JS wrapper was designed to use an underlying C++ API that accepted image info in a structure\&. The API actually added to basis_universal uses explicit parameters so users of this transcoder will be packing the info into a struct from which it will be immediately unpacked before the underlying transcoder is called\&. .RE .PP .SS "WebIDL for the binding" .PP .nf void initTranscoders(); bool isFormatSupported(TranscodeTarget targetFormat, TextureFormat texFormat); interface BasisTranscoderState { void BasisTranscoderState(); }; interface TranscodedImage { ArrayBufferView get_typed_memory_view(); }; interface TranscodeResult { TranscodedImage transcodedImage; }; interface BasisLzEtc1sImageTranscoder { void BasisLzEtc1sImageTranscoder(); uint32_t getBytesPerBlock(TranscodeTarget format); bool decode_palettes(uint32_t num_endpoints, const Uint8Array endpoints, uint32_t num_selectors, const Uint8Array selectors); bool decode_tables(const Uint8Array tableData); TranscodeResult transcode_image( TranscodeTarget targetFormat, const Uint8Array jsInSlices, ImageInfo imageInfo, uint32_t decodeFlags = 0, bool isVideo = false); }; interface BasisUastcImageTranscoder { void BasisUastcImageTranscoder(); uint32_t getBytesPerBlock(const TranscodeTarget format); TranscodeResult transcode_image( TranscodeTarget targetFormat, const Uint8Array jsInImage, basisu_image_desc& imageDesc, uint32_t decodeFlags = 0, bool hasAlpha = false, bool isVideo = false); interface ImageInfo = { ImageInfo(TextureFormat texFormat, uint32_t width, uint32_t height, uint32_t level); attribute uint32_t flags; attribute long rgbByteOffset; attribute long rgbByteLength; attribute long alphaByteOffset; attribute long alphaByteLength; attribute uint32_t width; attribute uint32_t height; attribute uint32_t numBlocksX; attribute uint32_t numBlocksY; attribute uint32_t level; }; // Some targets may not be available depending on options used when compiling // the web assembly\&. enum TranscodeTarget = { "ETC1_RGB", "BC1_RGB", "BC4_R", "BC5_RG", "BC3_RGBA", "PVRTC1_4_RGB", "PVRTC1_4_RGBA", "BC7_RGBA", "BC7_M6_RGB", //Deprecated\&. Use BC7_RGBA\&. "BC7_M5_RGBA", //Deprecated\&. Use BC7_RGBA\&. "ETC2_RGBA", "ASTC_4x4_RGBA", "RGBA32", "RGB565", "BGR565", "RGBA4444", "PVRTC2_4_RGB", "PVRTC2_4_RGBA", "EAC_R11", "EAC_RG11" }; enum TextureFormat = { "ETC1S", "UASTC4x4", }; enum TranscodeFlagBits = "TRANSCODE_ALPHA_DATA_TO_OPAQUE_FORMATS", "HIGH_QUALITY", }; enum TranscodeFlagBits = { "TRANSCODE_ALPHA_DATA_TO_OPAQUE_FORMATS", "HIGH_QUALITY" }; .fi .PP .SS "How to use" Put msc_basis_transcoder\&.js and msc_basis_transcoder\&.wasm in a directory on your server\&. Create a script tag with msc_basis_tranacoder\&.js as the \fRsrc\fP as shown below, changing the path as necessary for the relative locations of your \&.html file and the script source\&. msc_basis_transcoder\&.js will automatically load msc_basis_transcoder\&.wasm\&. .SS "Create an instance of the MSC_TRANSCODER module" For example, add this to the \&.html file to initialize the transcoder and make it available on the main window\&. .PP .nf <script src="msc_transcoder_wrapper\&.js"></script> <script type="text/javascript"> MSC_TRANSCODER()\&.then(module => { window\&.MSC_TRANSCODER = module; module\&.initTranscoders(); // Call a function to begin loading or transcoding\&.\&. </script> .fi .PP .PP \fIAfter\fP the module is initialized, invoke code that will directly or indirectly cause a function with code like the following to be executed\&. .SS "Somewhere in the loader/transcoder" Assume a KTX file is fetched via an XMLHttpRequest which deposits the data into a Uint8Array, "buData"\&.\&.\&. .PP \fBNote\fP .RS 4 The names of the data items used in the following code are those from the KTX2 specification but the actual data is not specific to that container format\&. .RE .PP .PP .nf const { BasisLzEtc1sImageTranscoder, BasisUastcImageTranscoder, TranscodeTarget } = MSC_TRANSCODER; // Determine from the KTX2 header information in buData if // the data format is BasisU or Uastc\&. // supercompressionScheme value == 1, it's TextureFormat\&.ETC1S\&. // DFD colorModel == 166, it's TextureFormat\&.UASTC4x4\&. const texFormat = \&.\&.\&. // Determine appropriate transcode format from available targets, // info about the texture, e\&.g\&. texture\&.numComponents, and // expected use\&. Use values from TranscodeTarget\&. const targetFormat = \&.\&.\&. if ( !MSC_TRANSCODER\&.isFormatSupported(targetFormat, texFormat) { throw new Error( \&.\&.\&. ); } if (TextureFormat\&.UASTC4x4) { var result = transcodeUastc(targetFormat); } else { var result = transcodeEtc1s(targetFormat); } if ( result\&.transcodedImage === undefined ) { throw new Error( 'Unable to transcode image\&.' ); } .fi .PP .PP This is the function for transcoding etc1s\&. .PP .PP .nf transcodeEtc1s(targetFormat) { // Locate the supercompression global data and compresssed // mip level data within buData\&. var bit = new BasisLzEtc1sImageTranscoder(); // Find the index of the starts of the endpoints, selectors and tables // data within buData\&.\&.\&. var endpointsStart = \&.\&.\&. var selectorsStart = \&.\&.\&. var tablesStart = \&.\&.\&. // The numbers of endpoints & selectors and their byteLengths are items // within buData\&. They are in the header of a \&.ktx2 file's // supercompressionGlobalData and in the header of a \&.basis file\&. var endpoints = new Uint8Array(buData, endpointsStart, endpointsByteLength); var selectors = new Uint8Array(buData, selectorsStart, selectorsByteLength); bit\&.decodePalettes(numEndpoints, endpoints, numSelectors, selectors); var tables = new UInt8Array(buData, tablesStart, tablesByteLength); bit\&.decodeTables(tables); // Determine if the file contains a video sequence\&.\&.\&. var isVideo = \&.\&.\&. // Calculate the total number of images in the data var numImages = \&.\&.\&. // Set up a subarray pointing at the deflated image descriptions // in buData\&. This is for \&.ktx2 containers\&. The image descriptions // are located in supercompressionGlobalData\&. \&.basis containers will // require different code to locate the slice descriptions within // the file\&. var imageDescsStart = \&.\&.\&.: // An imageDesc has 5 uint32 values\&. var imageDescs = new Uint32Data(buData, imageDescsStart, numImages * 5 * 4); var curImageIndex = 0; // Pseudo code for processing the levels of a \&.ktx2 container\&.\&.\&. foreach level { var leveWidth = width of image at this level var levelHeight = height of image at this level imageInfo = new ImageInfo(TextureFormat::ETC1S, levelWidth, levelHeight, level); foreach image in level { // In KTX2 container locate the imageDesc for this image\&. var imageDesc = imageDescs[curImageIndex++]; imageInfo\&.flags = imageDesc\&.imageFlags; imageInfo\&.rgbByteOffset = 0; imageInfo\&.rgbByteLength = imageDesc\&.rgbSliceByteLength; imageInfo\&.alphaByteOffset = imageDesc\&.alphaSliceByteOffset > 0 ? imageDesc\&.rgbSliceByteLength : 0; imageInfo\&.alphaByteLength = imageDesc\&.alphaSliceByteLength; // Determine the location in the ArrayBuffer of the start // of the deflated data for level\&. var levelOffset = \&.\&.\&. // Make a \&.subarray of the rgb slice data\&. var levelData = new Uint8Array( buData, levelOffset + imageDesc\&.rgbSliceByteOffset, imageDesc\&.rgbSliceByteLength + imageDesc\&.alphaByteLength ); var result = bit\&.transcodeImage( targetFormat, levelData, imageInfo, 0, isVideo); if ( result\&.transcodedImage === undefined ) { throw new Error( \&.\&.\&. ); } let imgData = transcodedImage\&.get_typed_memory_view(); // Upload data in imgData to WebGL\&.\&.\&. // Do not call delete() until data has been uploaded // or otherwise copied\&. transcodedImage\&.delete(); } } // For \&.basis containers, it is necessary to locate the slice // description(s) for the image and set the values in imageInfo // from them\&. Use of the \&.basis\-specific transcoder is recommended\&. // The definition of the basis_slice_desc struct makes it difficult // to create JS interface for it with embind\&. .fi .PP .PP This is the function for transcoding Uastc\&. .PP .PP .nf transcodeUastc(targetFormat) { var uit = new UastcImageTranscoder(); // Determine if the data is supercompressed\&. var zstd = (supercompressionScheme == 2); // Determine if the data has alpha\&. var hasAlpha = (Channel ID of sample[0] in DFD == 1); var dctx; if (zstd) { // Initialize the zstd decoder\&. Zstd JS wrapper + wasm is // a separate package\&. dctx = ZSTD_createDCtx(); } // Pseudo code for processing the levels of a \&.ktx2 container\&.\&.\&. foreach level { // Determine the location in the ArrayBuffer buData of the // start of the deflated data for the level\&. var levelData = \&.\&.\&. if (zstd) { // Inflate the level data levelData = ZSTD_decompressDCtx(dctx, levelData, \&.\&.\&. ); } var levelWidth = width of image at this level var levelHeight = height of image at this level var depth = depth of texture at this level var levelImageCount = number of layers * number of faces * depth; var imageOffsetInLevel = 0; var imageInfo = new ImageInfo(TextureFormat::UASTC4x4, levelWidth, levelHeight, level); var levelImageByteLength = imageInfo\&.numBlocksX * imageInfo\&.numBlocksY * DFD bytesPlane0; foreach image in level { inImage = Uint8Array(levelData, imageOffsetInLevel, levelImageByteLength); imageInfo\&.flags = 0; imageInfo\&.rgbByteOffset = 0; imageInfo\&.rgbByteLength = levelImageByteLength; imageInfo\&.alphaByteOffset = 0; imageInfo\&.alphaByteLength = 0; const {transcodedImage} = uit\&.transcodeImage( targetFormat, inImage, imageInfo, 0, hasAlpha, isVideo); if ( result\&.transcodedImage === undefined ) { throw new Error( \&.\&.\&. ); } let imgData = transcodedImage\&.get_typed_memory_view(); // Upload data in imgData to WebGL\&.\&.\&. // Do not call delete() until data has been uploaded // or otherwise copied\&. transcodedImage\&.delete(); imageOffsetInLevel += levelImageByteLength; } } // For \&.basis containers, as with ETC1S, it is necessary to locate // the slice description for the image and set the values in imageInfo // from it\&. } .fi .PP