Skip to content

ktx

stable

KTX2 GPU texture container format parser for reading headers, querying dimensions, mip levels, format names, and supercompression schemes.

use plugin ktx::{is_ktx2, parse_ktx2_header, format_name, …}
9 functions Graphics
/ filter jk navigate Esc clear
Functions (9)
  1. is_ktx2 Check if bytes are a valid KTX2 file
  2. parse_ktx2_header Parse full KTX2 header into a table
  3. format_name Map a VkFormat ID to a human-readable name
  4. get_dimensions Get width, height, and depth from bytes
  5. get_mip_levels Get the number of mip levels
  6. get_type_size Get the element type size in bytes
  7. get_face_count Get the number of cube map faces
  8. supercompression_name Map supercompression scheme ID to name
  9. get_layer_count Get the number of array layers

Overview

ktx is a read-only parser for the KTX2 GPU texture container format (the Khronos successor to KTX, used to ship compressed and mipmapped textures to graphics APIs like Vulkan and WebGPU). It operates directly on the raw file bytes you load — there is no handle or open texture object to manage; every function takes the byte buffer and pulls a specific field out of the 48-byte header. Reach for it when you need to inspect a .ktx2 asset: validate it, discover its pixel dimensions and mip chain, or decode its vkFormat and supercompression scheme into readable names.

The typical flow is to validate with is_ktx2, then either grab the whole header at once with parse_ktx2_header or pull individual fields with the focused get_* helpers, finally turning the numeric format and supercompression codes into strings with format_name and supercompression_name.

Common patterns

Validate a buffer before parsing, then read its full header:

use plugin ktx::{is_ktx2, parse_ktx2_header, format_name, supercompression_name}

let data = // ... read texture file bytes
if is_ktx2(data) {
  let header = parse_ktx2_header(data)
  print("Format: {format_name(header["format"])}")
  print("Size: {header["width"]}x{header["height"]}")
  print("Levels: {header["levels"]}")
  print("Compression: {supercompression_name(header["supercompression"])}")
} else {
  print("Not a KTX2 file")
}

Classify a texture from its face and layer counts without parsing the full header:

use plugin ktx::{get_face_count, get_layer_count, get_dimensions}

let dims = get_dimensions(data)
let faces = get_face_count(data)
let layers = get_layer_count(data)

if faces == 6 {
  print("Cubemap {dims["width"]}x{dims["height"]}")
} else if layers > 0 {
  print("Texture array with {layers} layers")
} else {
  print("Plain 2D texture {dims["width"]}x{dims["height"]}")
}

Check if bytes are a valid KTX2 file

Returns true if the first 12 bytes match the KTX2 magic identifier. Use this to quickly validate a file before attempting to parse it.

use plugin ktx::{is_ktx2}

let data = // ... read file bytes
if is_ktx2(data) {
  print("Valid KTX2 texture")
}

Parse full KTX2 header into a table

Parses the KTX2 file header and returns a table with keys: format (VkFormat int), width, height, layers, faces, levels, and supercompression. Requires at least 48 bytes and a valid KTX2 magic header.

use plugin ktx::{parse_ktx2_header, format_name}

let data = // ... read texture file bytes
let header = parse_ktx2_header(data)
print("Format: {header["format"]}")
print("Size: {header["width"]}x{header["height"]}")
print("Mip levels: {header["levels"]}")
print("Format name: {format_name(header["format"])}")

Because every numeric field is returned in one table, you can summarize a texture in a single pass:

use plugin ktx::{parse_ktx2_header, format_name, supercompression_name}

let h = parse_ktx2_header(data)
print("{h["width"]}x{h["height"]} | {format_name(h["format"])}")
print("levels={h["levels"]} faces={h["faces"]} layers={h["layers"]}")
print("compression={supercompression_name(h["supercompression"])}")

Map a VkFormat ID to a human-readable name

Maps a Vulkan VkFormat integer to its human-readable name string (e.g. "VK_FORMAT_R8G8B8A8_SRGB"). Returns "UNKNOWN" for unrecognized format IDs.

use plugin ktx::{format_name}

print(format_name(43))
print(format_name(145))
print(format_name(0))

It pairs naturally with parse_ktx2_header to turn the raw format code from a file into a readable label:

use plugin ktx::{parse_ktx2_header, format_name}

let id = parse_ktx2_header(data)["format"]
print("vkFormat {id} = {format_name(id)}")

Get width, height, and depth from bytes

Extracts only the pixel dimensions from the KTX2 header. Returns a table with width, height, and depth. Depth is 0 for 2D textures.

use plugin ktx::{get_dimensions}

let data = // ... read texture file bytes
let dims = get_dimensions(data)
print("Texture: {dims["width"]}x{dims["height"]}")

A non-zero depth indicates a 3D (volume) texture rather than a flat image:

use plugin ktx::{get_dimensions}

let d = get_dimensions(data)
if d["depth"] > 0 {
  print("Volume texture {d["width"]}x{d["height"]}x{d["depth"]}")
} else {
  print("2D texture {d["width"]}x{d["height"]}")
}

Get the number of mip levels

Returns the number of mip levels stored in the texture. A value of 1 means no mipmaps.

use plugin ktx::{get_mip_levels}

let levels = get_mip_levels(data)
print("Mip levels: {levels}")

Get the element type size in bytes

Returns the size in bytes of a single element for uncompressed formats (e.g. 4 for RGBA8). Returns 1 for block-compressed formats.

use plugin ktx::{get_type_size}

let size = get_type_size(data)
print("Type size: {size} bytes")

Get the number of cube map faces

Returns the number of cubemap faces in the texture. Standard 2D textures return 1; cubemaps return 6.

use plugin ktx::{get_face_count}

let faces = get_face_count(data)
if faces == 6 {
  print("Cubemap texture")
} else {
  print("2D texture")
}

Map supercompression scheme ID to name

Maps a KTX2 supercompression scheme integer to its name. Recognized values: 0"NONE", 1"BASIS_LZ", 2"ZSTD", 3"ZLIB". Returns "UNKNOWN" for other values.

use plugin ktx::{parse_ktx2_header, supercompression_name}

let header = parse_ktx2_header(data)
let compression = supercompression_name(header["supercompression"])
print("Compression: {compression}")

Branch on the decoded name to decide whether a transcode step is needed:

use plugin ktx::{parse_ktx2_header, supercompression_name}

let scheme = supercompression_name(parse_ktx2_header(data)["supercompression"])
if scheme == "BASIS_LZ" {
  print("Universal texture — transcode before upload")
} else if scheme == "NONE" {
  print("Ready to upload as-is")
}

Get the number of array layers

Returns the number of array layers in the texture. Returns 0 for non-array textures (single layer is represented as 0 in KTX2).

use plugin ktx::{get_layer_count}

let layers = get_layer_count(data)
print("Array layers: {layers}")
enespt-br