texture2ddecoder-wasm
v1.2.2
Published
WebAssembly bindings for Texture2DDecoder - decode various texture formats (BC1-7, ETC, PVRTC, ASTC, etc.) with Unity asset decoder
Downloads
547
Maintainers
Readme
texture2ddecoder-wasm
A WebAssembly-based JavaScript/TypeScript library for decoding compressed texture formats. This project was inspired by K0lb3's texture2ddecoder Python wrapper and brings the same powerful texture decoding capabilities to Node.js and web environments through WebAssembly.
Built on top of Perfare's Texture2DDecoder from AssetStudio, with cross-platform WebAssembly bindings for JavaScript/TypeScript environments.
Features
- Zero native dependencies - Pure WebAssembly, works on any platform
- Browser and Node.js compatible - Works in both browser and Node.js environments
- Comprehensive format support - Decode BC1-7, ETC1/2, PVRTC, ASTC, ATC, EAC, and Crunch formats
- TypeScript support - Full type definitions included
- Unity Asset support - Decode textures from Unity game assets
- Fast performance - Native-speed decoding via WebAssembly
Supported Formats
BCn (Block Compression)
- BC1 (DXT1) - RGB compression
- BC3 (DXT5) - RGBA compression
- BC4 - Single channel compression
- BC5 - Dual channel compression
- BC6 - HDR compression
- BC7 - High quality compression
ETC (Ericsson Texture Compression)
- ETC1 - RGB compression
- ETC2 - Improved RGB compression
- ETC2A1 - RGB + 1-bit alpha
- ETC2A8 - RGB + 8-bit alpha
EAC (Ericsson Alpha Compression)
- EAC R11 - Single channel
- EAC R11 (signed) - Single channel signed
- EAC RG11 - Dual channel
- EAC RG11 (signed) - Dual channel signed
Other Formats
- PVRTC - PowerVR Texture Compression (2bpp and 4bpp)
- ASTC - Adaptive Scalable Texture Compression (various block sizes)
- ATC - AMD Texture Compression (RGB4 and RGBA8)
- Crunch - Crunch compressed textures
- Unity Crunch - Unity's variant of Crunch compression
Installation
npm install texture2ddecoder-wasmor
yarn add texture2ddecoder-wasm🚀 New to this library? Check out the Quick Start Guide for the fastest way to get running!
📖 Need bundler setup? See the Complete Bundler Guide for detailed configurations.
Usage
💡 See the examples/ directory for complete working configurations for popular frameworks!
Node.js Usage
import { decode_astc } from "texture2ddecoder-wasm";
import * as fs from "fs";
// Load compressed texture data
const data = fs.readFileSync("texture.astc");
// Decode ASTC texture
const width = 512;
const height = 512;
const blockWidth = 4;
const blockHeight = 4;
const decoded = await decode_astc(data, width, height, blockWidth, blockHeight);
if (decoded) {
// decoded is a Uint8Array containing BGRA pixel data
// Use with image libraries like sharp, jimp, etc.
console.log("Decoded successfully!");
}Browser Usage with Modern Bundlers (Webpack, Vite, etc.)
For modern frameworks (React, Vue, Svelte, Next.js, etc.), you can use CDN for quick setup or local files for production:
Quick Start - Using CDN (Recommended for Development)
import { initialize, decode_bc1 } from "texture2ddecoder-wasm";
// Initialize with CDN
await initialize({
wasmPath: "https://cdn.jsdelivr.net/npm/[email protected]/wasm",
});
// Load and decode texture
const response = await fetch("texture.bin");
const data = new Uint8Array(await response.arrayBuffer());
const decoded = await decode_bc1(data, 512, 512);Benefits:
- ✅ No manual file copying needed
- ✅ Fastest setup time
- ✅ Cached by CDN globally
- ✅ Perfect for prototyping and development
Production Setup - Using Local Files
For production, copy WASM files to your public directory:
npx texture2ddecoder-copy-wasm public/wasmimport { initialize, decode_bc1 } from "texture2ddecoder-wasm";
// Initialize with local path
await initialize({ wasmPath: "/wasm" });
const decoded = await decode_bc1(data, 512, 512);Benefits:
- ✅ Faster loading (same domain)
- ✅ Works offline
- ✅ No external dependencies
Framework-Specific Examples:
Vite + React:
import { initialize, decode_bc1 } from "texture2ddecoder-wasm";
// Development: Use CDN
await initialize({
wasmPath: "https://cdn.jsdelivr.net/npm/[email protected]/wasm",
});
// Production: Use local files (copy with: npx texture2ddecoder-copy-wasm public/wasm)
await initialize({ wasmPath: "/wasm" });Next.js:
// In a 'use client' component
import { initialize, decode_bc1 } from "texture2ddecoder-wasm";
// Development: Use CDN
await initialize({
wasmPath: "https://cdn.jsdelivr.net/npm/[email protected]/wasm",
});
// Production: Use local files (copy with: npx texture2ddecoder-copy-wasm public/wasm)
await initialize({ wasmPath: "/wasm" });Webpack 5:
import { initialize, decode_bc1 } from "texture2ddecoder-wasm";
// Development: Use CDN
await initialize({
wasmPath: "https://cdn.jsdelivr.net/npm/[email protected]/wasm",
});
// Production: Use local files (copy with: npx texture2ddecoder-copy-wasm public/wasm)
await initialize({ wasmPath: "/wasm" });CDN Usage (jsDelivr)
You can use the library directly from jsDelivr CDN without any installation:
<!DOCTYPE html>
<html>
<head>
<title>Texture Decoder - CDN Example</title>
</head>
<body>
<h1>Decode Textures from CDN</h1>
<div id="status">Loading...</div>
<script type="module">
// Import from jsDelivr CDN
import {
initialize,
decode_bc1,
} from "https://cdn.jsdelivr.net/npm/[email protected]/dist/index.mjs";
// Initialize with CDN path for WASM files
await initialize({
wasmPath:
"https://cdn.jsdelivr.net/npm/[email protected]/wasm",
});
document.getElementById("status").textContent = "✓ Ready to decode!";
// Now you can use any decode function
// const decoded = await decode_bc1(textureData, width, height);
</script>
</body>
</html>Benefits:
- ✅ Zero build setup
- ✅ No npm install needed
- ✅ Cached by jsDelivr globally
- ✅ Perfect for quick prototypes
Production tip: Pin to a specific version (e.g., @1.2.1) instead of @latest for stability.
Complete working example: See examples/cdn-example.html for a full interactive demo.
Manual Initialization
import { initialize, decode_bc3 } from "texture2ddecoder-wasm";
// Node.js - no parameter needed (auto-detects module location)
await initialize();
// Browser - provide path to WASM files
await initialize({ wasmPath: "/wasm" });
// Browser with CDN - provide full CDN URL
await initialize({
wasmPath: "https://cdn.jsdelivr.net/npm/[email protected]/wasm",
});
// Browser with custom locateFile for advanced use cases
await initialize({
wasmPath: "/wasm",
locateFile: (path) => `/custom-path/${path}`,
});
// Now decode functions will use the already-initialized module
const result = await decode_bc3(data, width, height);API Reference
All decode functions accept Uint8Array | ArrayBuffer as input and return a Promise<Uint8Array | null>. The returned Uint8Array contains BGRA pixel data (4 bytes per pixel).
Note: In Node.js, you can still pass Buffer objects (which extend Uint8Array) and receive Uint8Array results that are compatible with Buffer operations.
BC Decoders
decode_bc1(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes BC1 (DXT1) compressed texture to BGRA.
decode_bc3(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes BC3 (DXT5) compressed texture to BGRA.
decode_bc4(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes BC4 compressed texture to BGRA.
decode_bc5(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes BC5 compressed texture to BGRA.
decode_bc6(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes BC6 compressed texture to BGRA.
decode_bc7(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes BC7 compressed texture to BGRA.
ETC Decoders
decode_etc1(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes ETC1 compressed texture to BGRA.
decode_etc2(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes ETC2 compressed texture to BGRA.
decode_etc2a1(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes ETC2 with 1-bit alpha compressed texture to BGRA.
decode_etc2a8(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes ETC2 with 8-bit alpha compressed texture to BGRA.
EAC Decoders
decode_eacr(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes EAC R11 compressed texture to BGRA.
decode_eacr_signed(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes EAC R11 signed compressed texture to BGRA.
decode_eacrg(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes EAC RG11 compressed texture to BGRA.
decode_eacrg_signed(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes EAC RG11 signed compressed texture to BGRA.
Other Format Decoders
decode_pvrtc(data: Uint8Array | ArrayBuffer, width: number, height: number, is2bpp: boolean = false): Promise<Uint8Array | null>
Decodes PVRTC compressed texture to BGRA.
is2bpp: Set totruefor 2 bits-per-pixel mode,falsefor 4 bits-per-pixel (default)
decode_astc(data: Uint8Array | ArrayBuffer, width: number, height: number, blockWidth: number, blockHeight: number): Promise<Uint8Array | null>
Decodes ASTC compressed texture to BGRA.
blockWidth: Block width (typically 4, 5, 6, 8, 10, or 12)blockHeight: Block height (typically 4, 5, 6, 8, 10, or 12)
decode_atc_rgb4(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes ATC RGB4 compressed texture to BGRA.
decode_atc_rgba8(data: Uint8Array | ArrayBuffer, width: number, height: number): Promise<Uint8Array | null>
Decodes ATC RGBA8 compressed texture to BGRA.
Crunch Decoders
unpack_crunch(data: Uint8Array | ArrayBuffer): Promise<Uint8Array | null>
Unpacks Crunch compressed data.
unpack_unity_crunch(data: Uint8Array | ArrayBuffer): Promise<Uint8Array | null>
Unpacks Unity Crunch compressed data.
Initialization
initialize(options?: { wasmPath?: string; locateFile?: (path: string, prefix: string) => string }): Promise<void>
Manually initialize the WebAssembly module. This is called automatically on first use of any decode function in Node.js, but must be called explicitly in browser environments.
Parameters:
options.wasmPath- (Browser required) Path or URL to the directory containing WASM filesoptions.locateFile- (Optional) Custom function to locate WASM binary files for advanced use cases
Node.js Example:
await initialize(); // Auto-detects and loads from dist/wasm/Browser Examples:
// Basic usage - local path
await initialize({ wasmPath: "/wasm" });
// With CDN
await initialize({
wasmPath: "https://cdn.jsdelivr.net/npm/[email protected]/wasm",
});
// With custom locateFile for advanced scenarios
await initialize({
wasmPath: "/wasm",
locateFile: (path) => `https://cdn.example.com/custom/${path}`,
});Framework Integration: This approach works seamlessly with:
- ✅ React / Next.js
- ✅ Vue / Nuxt
- ✅ Svelte / SvelteKit
- ✅ Webpack 5 / Vite / Rollup
- ✅ Server-Side Rendering (SSR) - Call
initialize()in client-side code only
Building from Source
Prerequisites
- Node.js ≥14.0.0
- Docker - Required for building the WebAssembly module (no local Emscripten installation needed)
Install Docker from: https://www.docker.com/get-started
Build Steps
# Clone the repository
git clone https://github.com/fatal10110/texture2ddecoder-wasm.git
cd texture2ddecoder-wasm
# Install dependencies
npm install
# Build WebAssembly module (uses Docker + Emscripten)
npm run build:wasm
# Build TypeScript
npm run build:ts
# Or build both at once
npm run build
# Run tests
npm testBuild Scripts
npm run build:wasm- Build the WebAssembly module using Docker and Emscriptennpm run build:ts- Compile TypeScriptnpm run build- Build both WASM and TypeScriptnpm test- Run tests
About the Docker Build
The WebAssembly build uses Docker with the official Emscripten SDK image, which means:
- No need to install Emscripten locally
- Consistent build environment across all platforms
- Automatic compiler toolchain setup
- Works on Windows, macOS, and Linux
The build script (scripts/build-wasm.sh) automatically:
- Checks if Docker is installed
- Pulls the latest Emscripten SDK image
- Compiles the C++ texture decoders to WebAssembly
- Generates optimized WASM and JavaScript glue code
License & Credits
This project is licensed under MIT.
Inspired by K0lb3's texture2ddecoder Python library.
The texture compression codecs were derived from the following sources:
| Codec | License | Source | | -------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | ATC | MIT | Perfare/AssetStudio - Texture2DDecoderNative/atc.cpp | | ASTC | MIT | Ishotihadus/mikunyan - ext/decoders/native/astc.c | | BCn | MIT | Perfare/AssetStudio - Texture2DDecoderNative/bcn.cpp | | ETC | MIT | Ishotihadus/mikunyan - ext/decoders/native/etc.c | | f16 | MIT | Maratyszcza/FP16 | | PVRTC | MIT | Ishotihadus/mikunyan - ext/decoders/native/pvrtc.c | | Crunch | PUBLIC DOMAIN | BinomialLLC/crunch | | Crunch (Unity) | ZLIB | Unity-Technologies/crunch |
Related Projects
- texture2ddecoder - Python wrapper (original inspiration)
- AssetStudio - Original C++ texture decoders
- UnityPy - Unity asset extraction tool
Contributing
Contributions are welcome! Please read our Contributing Guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes.
Quick Start for Contributors
- Fork the repository
- Clone your fork:
git clone https://github.com/YOUR_USERNAME/texture2ddecoder-wasm.git - Initialize submodules:
git submodule update --init --recursive - Install dependencies:
npm install - Build the project:
npm run build - Run tests:
npm test - Create a branch, make your changes, and submit a Pull Request
See CONTRIBUTING.md for detailed guidelines.
Platform Support
- Node.js: ≥14.0.0
- Browsers: Modern browsers with WebAssembly support (Chrome, Firefox, Safari, Edge)
- Operating Systems: Windows, macOS, Linux (WebAssembly is platform-independent)
Browser Compatibility
The package works in all modern browsers that support:
- WebAssembly
- ES6 Modules (or use a bundler like Webpack/Vite)
- Typed Arrays (Uint8Array)
Tested and working in:
- Chrome/Edge 57+
- Firefox 52+
- Safari 11+
- Opera 44+
Examples
See browser-example.html for a complete browser usage example.
