KTX Javascript Wrappers Reference 4.3.2
Libraries and tools to create and read KTX image texture files.
Loading...
Searching...
No Matches
Basis Universal Image Transcoder binding
Warning
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.

WebIDL for the binding

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"
};

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 src 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.

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.

<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>

After the module is initialized, invoke code that will directly or indirectly cause a function with code like the following to be executed.

Somewhere in the loader/transcoder

Assume a KTX file is fetched via an XMLHttpRequest which deposits the data into a Uint8Array, "buData"...

Note
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.
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.' );
}

This is the function for transcoding etc1s.

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.

This is the function for transcoding Uastc.

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.
}