JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 6
  • Score
    100M100P100Q73829F

WebAssembly port of ETCPACK - ETC/EAC texture compression for the web

Package Exports

  • etcpack-wasm
  • etcpack-wasm/wasm

Readme

ETCPACK WASM API 文档

概述

ETCPACK WASM 提供了完整的 ETC/EAC 纹理压缩功能,支持在浏览器中进行高质量的纹理压缩。

安装

# 构建 WASM 模块
cd wasm
./build.sh prod

快速开始

import { createETCPACK, TextureFormat } from './etcpack-api.js';

// 初始化
const encoder = await createETCPACK();

// 压缩 RGB 图像
const compressed = encoder.compressRGB({
  data: rgbData,        // Uint8Array
  width: 512,
  height: 512,
  format: TextureFormat.ETC2_RGB
});

console.log(`压缩比: ${compressed.compressionRatio.toFixed(2)}:1`);

TypeScript 类型

TextureFormat

enum TextureFormat {
  ETC1_RGB = 0,           // ETC1 RGB (向后兼容)
  ETC2_RGB = 1,           // ETC2 RGB
  ETC2_RGBA1 = 2,         // ETC2 RGB + 1-bit Alpha
  ETC2_RGBA = 3,          // ETC2 RGBA (with EAC)
  EAC_R11 = 4,            // EAC R11 unsigned
  EAC_R11_SIGNED = 5,     // EAC R11 signed
  EAC_RG11 = 6,           // EAC RG11 unsigned
  EAC_RG11_SIGNED = 7     // EAC RG11 signed
}

CompressOptions

interface CompressOptions {
  data: Uint8Array | Uint8ClampedArray;  // 图像数据
  width: number;                          // 宽度(必须是 4 的倍数)
  height: number;                         // 高度(必须是 4 的倍数)
  format?: TextureFormat;                 // 格式(可选)
}

CompressResult

interface CompressResult {
  data: Uint8Array;           // 压缩后的数据
  width: number;              // 图像宽度
  height: number;             // 图像高度
  format: TextureFormat;      // 压缩格式
  compressedSize: number;     // 压缩后大小(字节)
  originalSize: number;       // 原始大小(字节)
  compressionRatio: number;   // 压缩比
}

DecompressOptions

interface DecompressOptions {
  data: Uint8Array;          // 压缩数据
  width: number;             // 宽度
  height: number;            // 高度
  format: TextureFormat;     // 压缩格式
}

DecompressResult

interface DecompressResult {
  data: Uint8Array;          // 解压后的数据
  width: number;             // 图像宽度
  height: number;            // 图像高度
  channels: number;          // 通道数 (3=RGB, 4=RGBA, 1=R, 2=RG)
}

API 方法

ETCPACKEncoder

compressRGB(options: CompressOptions): CompressResult

压缩 RGB 图像为 ETC1/ETC2 格式。

参数

  • data: Uint8Array - RGB 图像数据
  • width: number - 图像宽度(必须是 4 的倍数)
  • height: number - 图像高度(必须是 4 的倍数)
  • format: TextureFormat - 压缩格式(默认 ETC2_RGB)

返回: CompressResult

示例

const result = encoder.compressRGB({
  data: rgbData,
  width: 512,
  height: 512,
  format: TextureFormat.ETC2_RGB
});

decompressRGB(options: DecompressOptions): DecompressResult

解压 RGB 图像。

参数

  • data: Uint8Array - 压缩数据
  • width: number - 图像宽度
  • height: number - 图像高度
  • format: TextureFormat - 压缩格式

返回: DecompressResult(channels = 3)


compressRGBA(options: CompressOptions): CompressResult

压缩 RGBA 图像为 ETC2 + EAC Alpha 格式(16 字节/块)。

参数

  • data: Uint8Array - RGBA 图像数据
  • width: number - 图像宽度
  • height: number - 图像高度

返回: CompressResult

示例

const result = encoder.compressRGBA({
  data: rgbaData,
  width: 256,
  height: 256
});

decompressRGBA(options: DecompressOptions): DecompressResult

解压 RGBA 图像。

返回: DecompressResult(channels = 4)


compressRGBA1(options: CompressOptions): CompressResult

压缩 RGBA 图像为 ETC2 + 1-bit Alpha(punchthrough)格式(8 字节/块)。

适用于二值 Alpha(完全透明或完全不透明)。

示例

const result = encoder.compressRGBA1({
  data: rgbaData,
  width: 512,
  height: 512
});

decompressRGBA1(options: DecompressOptions): DecompressResult

解压 RGBA1 图像。


compressR11(options: CompressOptions & { signed?: boolean }): CompressResult

压缩单通道 11-bit 数据(EAC R11)。

参数

  • data: Uint8Array - 单通道数据(16-bit)
  • width: number - 宽度
  • height: number - 高度
  • signed: boolean - 是否有符号(默认 false)

用途

  • 高度图 / 位移贴图
  • 法线贴图(单通道)
  • 灰度图

示例

const result = encoder.compressR11({
  data: heightmapData,
  width: 1024,
  height: 1024,
  signed: false
});

decompressR11(options: DecompressOptions & { signed?: boolean }): DecompressResult

解压 R11 图像。

返回: DecompressResult(channels = 1,16-bit 输出)


compressRG11(options: CompressOptions & { signed?: boolean }): CompressResult

压缩双通道 11-bit 数据(EAC RG11)。

用途

  • 法线贴图(XY 通道)
  • 双通道数据

示例

const result = encoder.compressRG11({
  data: normalMapData,
  width: 512,
  height: 512,
  signed: true  // 法线通常使用有符号
});

getCompressedSize(width: number, height: number, format: TextureFormat): number

计算压缩后的数据大小(字节)。

示例

const size = encoder.getCompressedSize(512, 512, TextureFormat.ETC2_RGB);
console.log(`预期大小: ${size} 字节`); // 32768 字节

validateDimensions(width: number, height: number): boolean

验证图像尺寸是否有效(必须是 4 的倍数)。

抛出: Error - 如果尺寸无效

示例

try {
  encoder.validateDimensions(513, 512);
} catch (e) {
  console.error(e.message); // "Image dimensions must be multiples of 4..."
}

使用场景

1. WebGL 纹理压缩

async function uploadCompressedTexture(
  gl: WebGLRenderingContext,
  imageData: Uint8Array,
  width: number,
  height: number
) {
  const encoder = await createETCPACK();

  const compressed = encoder.compressRGB({
    data: imageData,
    width,
    height,
    format: TextureFormat.ETC2_RGB
  });

  const texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texture);

  const ext = gl.getExtension('WEBGL_compressed_texture_etc');
  gl.compressedTexImage2D(
    gl.TEXTURE_2D, 0,
    ext.COMPRESSED_RGB8_ETC2,
    width, height, 0,
    compressed.data
  );

  return texture;
}

2. Canvas 图像压缩

async function compressCanvas(canvas: HTMLCanvasElement) {
  const encoder = await createETCPACK();
  const ctx = canvas.getContext('2d')!;
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

  return encoder.compressRGBA({
    data: imageData.data,
    width: canvas.width,
    height: canvas.height
  });
}

3. 批量纹理处理

async function compressBatch(textures: Array<{name: string, data: Uint8Array, width: number, height: number}>) {
  const encoder = await createETCPACK();

  const results = textures.map(tex => ({
    name: tex.name,
    ...encoder.compressRGB({
      data: tex.data,
      width: tex.width,
      height: tex.height
    })
  }));

  return results;
}

性能参考

格式 压缩比 质量 速度 用途
ETC1 RGB 6:1 旧设备兼容
ETC2 RGB 6:1 不透明纹理
ETC2 RGBA1 6:1 Cutout 透明
ETC2 RGBA 4:1 完整 Alpha
EAC R11 2:1 极高 高度图
EAC RG11 1:1 极高 法线贴图

注意事项

  1. 尺寸要求:图像宽高必须是 4 的倍数
  2. 内存使用:压缩/解压过程会临时分配内存
  3. 浏览器兼容:需要 WebAssembly 支持(现代浏览器)
  4. 纹理格式支持:使用前检查 WEBGL_compressed_texture_etc 扩展

错误处理

try {
  const result = encoder.compressRGB({
    data: imageData,
    width: 513,  // 不是 4 的倍数
    height: 512
  });
} catch (error) {
  if (error.message.includes('multiples of 4')) {
    console.error('图像尺寸必须是 4 的倍数');
  }
}

文件大小对比

分辨率 RGB 原始 ETC2 压缩 节省
512×512 768 KB 128 KB 83%
1024×1024 3 MB 512 KB 83%
2048×2048 12 MB 2 MB 83%
4096×4096 48 MB 8 MB 83%

更多资源