Note: This is a personal project ported with Claude. Neither the documentation nor the code has been fully checked. WIP
Color Lithophane Generator for 3D Printing with Multi-Filament Support
Rust port of the original PIXEstL Java application by gaugo87. Generate stunning color lithophanes for 3D printing using CMYK-based additive color mixing with automatic material system (AMS) support.
- π¨ CMYK Additive Color Mixing - Realistic color reproduction with transparent filaments
- π¬ CIELab Color Matching - Perceptually uniform color distance for accurate matching
- π Parallel Processing - Multi-threaded mesh generation using Rayon
- π― Bambu Lab AMS Support - Automatic multi-group filament swapping
- π Physical Dimensions - Direct millimeter-based sizing for accurate prints
- ποΈ Dual Layer Support - Separate color and texture (brightness) layers
- πΎ STL Export - ASCII and binary STL formats with ZIP packaging
- β‘ Run-Length Encoding - Optimized mesh generation
- Rust 1.75 or later β Install via rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
- Modern CPU (multi-core recommended)
- ~100 MB RAM for typical images
# Clone the repository
git clone https://github.com/feurer98/PIXEstL.git
cd PIXEstL/rust
# Build release binary
cargo build --release
# Binary will be at: target/release/pixestlpixestl \
--input image.png \
--palette palette.json \
--output lithophane.zip \
--width 100This will:
- Load
image.pngand resize to 100mm width - Load color palette from
palette.json - Generate color lithophane layers
- Export STL files to
lithophane.zip
A ready-to-use palette file is provided in the palette/ directory of the repository.
Required Arguments:
-i, --input <FILE>- Input image file (PNG, JPG, etc.)-p, --palette <FILE>- Palette JSON file-o, --output <FILE>- Output ZIP file
Image Dimensions:
-w, --width <MM>- Destination width in millimeters (0 = auto)-H, --height <MM>- Destination height in millimeters (0 = auto)
Color Layer Settings:
--color-pixel-width <MM>- Size of each color pixel (default: 0.8)--color-layer-thickness <MM>- Thickness per layer (default: 0.1)--color-layers <N>- Number of layers (default: 5)--no-color- Disable color layers
Texture Layer Settings:
--texture-pixel-width <MM>- Size of each texture pixel (default: 0.25)--texture-min <MM>- Minimum texture thickness (default: 0.3)--texture-max <MM>- Maximum texture thickness (default: 1.8)--texture-color <HEX>- Filament color for texture layer (default: #FFFFFF)--no-texture- Disable texture layer
Export Options:
--format <ascii|binary>- STL format (default: ascii)--plate-thickness <MM>- Base plate thickness (default: 0.2)
Advanced Options:
--color-distance <rgb|cie-lab>- Color matching method (default: cie-lab)--pixel-method <additive|full>- Color creation method (default: additive)--color-number <N>- Limit colors per AMS group (0 = all)-C, --curve <DEG>- Curve angle in degrees for cylindrical lithophanes (default: 0)--debug- Enable debug output
Special Modes:
--palette-info- Show palette information and exit (no input/output required)--calibrate- Generate a calibration pattern instead of processing an image
100mm wide lithophane with 5 color layers:
pixestl -i photo.jpg -p palette.json -o output.zip -w 10080x120mm with texture layer only:
pixestl -i landscape.png -p palette.json -o output.zip \
-w 80 -H 120 --no-colorHigh-resolution color lithophane:
pixestl -i portrait.png -p palette.json -o output.zip \
-w 150 --color-pixel-width 0.4 --color-layers 7Binary STL format (smaller files):
pixestl -i image.png -p palette.json -o output.zip \
-w 100 --format binaryPalettes are defined in JSON with HSL or hex color definitions:
{
"#FF0000": {
"name": "Red",
"active": true,
"layers": {
"5": { "H": 0, "S": 100, "L": 50 }
}
},
"#00FF00": {
"name": "Green",
"active": true,
"layers": {
"5": { "H": 120, "S": 100, "L": 50 }
}
},
"#FFFFFF": {
"name": "White",
"active": true,
"layers": {
"1": "#FFFFFF"
}
}
}Note: White (#FFFFFF) is required for proper color mixing.
use pixestl::{
LithophaneConfig, LithophaneGenerator,
PaletteLoader, PaletteLoaderConfig,
export_to_zip, StlFormat,
};
use std::path::Path;
fn main() -> pixestl::Result<()> {
// Load image
let image = pixestl::image::load_image(Path::new("input.png"))?;
// Load palette
let palette_config = PaletteLoaderConfig {
nb_layers: 5,
creation_method: pixestl::PixelCreationMethod::Additive,
color_number: 0,
distance_method: pixestl::color::ColorDistanceMethod::CieLab,
};
let palette = PaletteLoader::load(Path::new("palette.json"), palette_config)?;
// Generate lithophane
let config = LithophaneConfig {
dest_width_mm: 100.0,
dest_height_mm: 0.0,
..Default::default()
};
let generator = LithophaneGenerator::new(config)?;
let layers = generator.generate(&image, &palette)?;
// Export to ZIP
export_to_zip(&layers, "output.zip", StlFormat::Binary)?;
Ok(())
}pixestl/
βββ color/ # Color space conversions (RGB, HSL, CIELab, CMYK)
βββ palette/ # Palette loading, color combinations, quantization
βββ image/ # Image loading, resizing, processing
βββ lithophane/ # Core mesh generation algorithms
β βββ config # Configuration and validation
β βββ geometry # 3D primitives (Vector3, Triangle, Mesh)
β βββ color_layer # Color layer mesh generation
β βββ texture_layer # Texture layer mesh generation
β βββ support_plate # Base plate generation
βββ stl/ # STL export (ASCII/binary) and ZIP packaging
βββ cli/ # Command-line interface
Color Matching:
- Converts image to CIELab color space
- Computes Delta E distance to palette colors
- Parallel processing with Rayon
Color Layer Generation:
- Stacks transparent CMYK layers
- Run-length encoding for consecutive identical pixels
- Parallel row-based processing
Texture Layer Generation:
- Converts to grayscale using standard luminance formula
- Maps brightness to thickness:
thickness = min + K * (max - min) - Triangulated surface mesh with edge handling
- Multi-threaded: Uses all CPU cores via Rayon
- Optimized: Run-length encoding reduces mesh complexity
- Memory efficient: Streaming STL generation
- Fast builds: LTO and optimization level 3 in release mode
Typical generation time for 100x100mm lithophane: ~5-15 seconds
# Run all tests (233 tests)
cargo test
# Run with output
cargo test -- --nocapture
# Run specific module
cargo test color::
# Release mode tests (faster)
cargo test --release- Rust 1.75 or later β Install via rustup
- Modern CPU (multi-core recommended)
- ~100 MB RAM for typical images
| Feature | Java | Rust |
|---|---|---|
| Performance | β‘ | β‘β‘β‘ (2-3x faster) |
| Memory Usage | π | π (50% less) |
| Binary Size | 30+ MB | 8 MB |
| Startup Time | ~2s (JVM) | <100ms |
| Dependencies | JRE required | Self-contained |
| Type Safety | Runtime | Compile-time |
Contributions welcome! This is a faithful port of the Java implementation with Rust idioms.
MIT License - See LICENSE file
- Original PIXEstL Java application: gaugo87 β gaugo87/PIXEstL
- Rust Port: feurer98
- Based on CMYK additive color mixing research
- Bambu Lab AMS integration