A pure Rust library for working with Blizzard's BLP texture format used in Warcraft III and World of Warcraft.
Key Features:
- 🚀 Pure Rust - No C dependencies, cross-platform (Windows, macOS, Linux)
- 🔄 Complete Format Support - BLP0, BLP1, BLP2 with JPEG and palette compression
- 🎨 Universal Image Handling - Works with BLP, PNG, JPEG, GIF, PSD, and more
- 🖼️ Mipmap Control - Precise control over mipmap generation and extraction
- ⚡ High Performance - Fast encoding/decoding using TurboJPEG
- 🎯 Simple API - Easy to use with comprehensive documentation
Part of the WarRaft toolkit for Warcraft III modding.
Add to your Cargo.toml:
[dependencies]
blp = "1.0"use blp::any_image::{AnyImage, EncodeOptions, EncodeMipOptions};
// Load any image format (PNG, JPEG, GIF, PSD, etc.)
let img_data = std::fs::read("input.png")?;
let img = AnyImage::from_buffer(&img_data)?;
// Convert to BLP with mipmaps
let blp_data = img.encode(&EncodeOptions::Blp {
quality: 85,
mip_options: Some(EncodeMipOptions {
min_size: Some(4), // Generate mipmaps down to 4x4
..Default::default()
}),
raw: None,
})?;
std::fs::write("output.blp", &blp_data)?;use blp::any_image::{AnyImage, EncodeOptions};
let blp_data = std::fs::read("texture.blp")?;
let img = AnyImage::from_buffer(&blp_data)?;
let png_data = img.encode(&EncodeOptions::Png {
compression: Some(6)
})?;
std::fs::write("output.png", &png_data)?;use blp::any_image::AnyImage;
let blp_data = std::fs::read("texture.blp")?;
let img = AnyImage::from_buffer(&blp_data)?;
// Get all mipmap levels as RgbaImage
let mipmaps = img.decode_frames()?;
for (i, mip) in mipmaps.iter().enumerate() {
mip.save(format!("mip_{}.png", i))?;
}The main entry point for working with any image format:
// Load from buffer
let img = AnyImage::from_buffer(&data)?;
// Get dimensions
let (width, height) = img.dimensions();
// Convert to DynamicImage (from image crate)
let dyn_img = img.into_dynamic()?;
// Encode to different formats
let png = img.encode(&EncodeOptions::Png { compression: Some(6) })?;
let jpg = img.encode(&EncodeOptions::Jpeg { quality: 90 })?;
let blp = img.encode(&EncodeOptions::Blp {
quality: 85,
mip_options: None,
raw: None,
})?;
// Decode all frames/mipmaps
let frames = img.decode_frames()?;Control how images are encoded:
// PNG with compression
EncodeOptions::Png {
compression: Some(6) // 0-9, None for default
}
// JPEG with quality
EncodeOptions::Jpeg {
quality: 90 // 0-100
}
// BLP with full control
EncodeOptions::Blp {
quality: 85,
mip_options: Some(EncodeMipOptions { /* ... */ }),
raw: None, // Or Some(mip_index) to extract raw JPEG data
}Fine-tune mipmap generation:
// Generate first 4 mipmaps only
EncodeMipOptions {
mip_count: Some(4),
..Default::default()
}
// Generate until smallest dimension reaches 16px
EncodeMipOptions {
min_size: Some(16),
..Default::default()
}
// Manual control over each mip level
EncodeMipOptions {
specific_mips: Some(vec![true, true, false, true]),
..Default::default()
}
// Palette-based compression (experimental)
EncodeMipOptions {
quantize_colors: Some(256),
quantize_dither: true,
..Default::default()
}Low-level BLP operations without full decoding:
use blp::blp;
// Inspect metadata without decoding pixels
let meta = blp::inspect_buf(&blp_data)?;
println!("Version: {:?}, Size: {}x{}",
meta.version, meta.width, meta.height);
// Get header data (JPEG header or palette)
if let Some(header) = blp::header_data(&blp_data) {
println!("Header size: {} bytes", header.len());
}
// Get raw mipmap data
if let Some(raw) = blp::mip_raw(&blp_data, 0) {
println!("Mip 0 size: {} bytes", raw.len());
}
// Quick dimension check
let (width, height) = blp::inspect_image_dimensions(&blp_data)?;Input Formats:
- BLP (BLP0, BLP1, BLP2)
- PNG, JPEG, GIF, BMP, TIFF, WebP
- PSD (Photoshop documents)
- Any format supported by the image crate
Output Formats:
- BLP (JPEG compression with automatic mipmap generation)
- PNG (with compression level control)
- JPEG (with quality control)
The repository includes complete working examples in the `examples/` directory:
# Convert any image to BLP
cargo run --example convert_to_blp input.png output.blp 85
# Convert BLP to PNG
cargo run --example convert_from_blp input.blp output.png
# Extract all mipmaps from BLP
cargo run --example extract_mipmaps input.blp output_dir/
# Inspect BLP metadata
cargo run --example inspect_blp input.blp
# Palette-based conversion (experimental)
cargo run --example convert_with_palette input.png output.blp 256 --ditherSee `examples/README.md` for detailed documentation.
// Extract raw JPEG data for a specific mipmap level
let raw_jpeg = img.encode(&EncodeOptions::Blp {
quality: 85,
mip_options: None,
raw: Some(0), // Extract mip level 0
})?;
std::fs::write("mip_0.jpg", &raw_jpeg)?;// Access frame metadata
for (i, frame) in img.frames.iter().enumerate() {
println!("Frame {}: {}x{}", i, frame.width, frame.height);
}
// Decode specific frames
let frames = img.decode_frames()?;
let first_frame = &frames[0];// Generate only specific mipmap levels
let mip_options = EncodeMipOptions {
specific_mips: Some(vec![
true, // Mip 0: 1024x1024
true, // Mip 1: 512x512
false, // Mip 2: skip
true, // Mip 3: 128x128
]),
..Default::default()
};
let blp_data = img.encode(&EncodeOptions::Blp {
quality: 90,
mip_options: Some(mip_options),
raw: None,
})?;Built with performance in mind:
- TurboJPEG - Uses turbojpeg for fast JPEG encoding/decoding
- Efficient Memory Usage - Lazy decoding, only loads what you need
- Zero-Copy Operations - Metadata inspection without pixel decoding
Typical performance on modern hardware:
- 1024x1024 BLP encoding with full mipmaps: ~100ms
- BLP → PNG conversion: ~50ms
- Metadata inspection: <1ms (no pixel decoding)
Run the test suite:
# Run all tests
cargo test
# Run with output
cargo test -- --nocapture
# Run specific test
cargo test test_png_to_blp_and_extract- WarRaft - Warcraft III modding toolkit
- JASS-Tree-sitter-Rust - JASS language support
- BLP Specification - Detailed format documentation
Contributions are welcome! Feel free to:
- Report bugs
- Suggest features
- Submit pull requests
- Improve documentation
MIT License - see LICENSE for details.
