### Working with Tilesets Source: https://context7.com/alpine-alpaca/asefile/llms.txt Provides code for accessing tilesets within an Aseprite file, including iterating through them, getting tile counts and sizes, exporting the entire tileset as a strip, and exporting individual tiles. ```rust use asefile::AsepriteFile; use image::ImageFormat; use std::path::Path; fn main() { let ase = AsepriteFile::read_file(Path::new("tileset.aseprite")).unwrap(); // Access tilesets let tilesets = ase.tilesets(); println!("Number of tilesets: {}", tilesets.len()); for tileset in tilesets.iter() { println!("Tileset '{}' (id: {})", tileset.name(), tileset.id()); println!(" Tile count: {}", tileset.tile_count()); println!(" Tile size: {}xவைக்{}", tileset.tile_size().width(), tileset.tile_size().height() ); // Export entire tileset as vertical strip (one tile wide) let all_tiles = tileset.image(); all_tiles.save_with_format("tileset_strip.png", ImageFormat::Png).unwrap(); // Export individual tiles (tile 0 is the empty tile) for tile_idx in 1..tileset.tile_count() { let tile_img = tileset.tile_image(tile_idx); let filename = format!("tile_{}.png", tile_idx); tile_img.save_with_format(&filename, ImageFormat::Png).unwrap(); } } } ``` -------------------------------- ### Load Aseprite File from Disk or Buffer Source: https://context7.com/alpine-alpaca/asefile/llms.txt Demonstrates loading an Aseprite file using `AsepriteFile::read_file()` for file paths or `AsepriteFile::read()` for in-memory buffers. Ensure the file exists at the specified path. ```rust use std::path::Path; use asefile::AsepriteFile; fn main() -> Result<(), asefile::AsepriteParseError> { // Load from file path let path = Path::new("sprite.aseprite"); let ase = AsepriteFile::read_file(&path)?; // Access basic file properties println!("Dimensions: {}x{}", ase.width(), ase.height()); println!("Number of frames: {}", ase.num_frames()); println!("Number of layers: {}", ase.num_layers()); println!("Pixel format: {:?}", ase.pixel_format()); // Load from in-memory buffer let buffer: Vec = std::fs::read("sprite.aseprite")?; let ase_from_memory = AsepriteFile::read(&buffer[..])?; Ok(()) } ``` -------------------------------- ### Work with Layers in Aseprite Files Source: https://context7.com/alpine-alpaca/asefile/llms.txt Demonstrates accessing and inspecting individual layers within an Aseprite file by index or name. It also shows how to iterate through all layers and identify their types and parent groups. ```rust use asefile::{AsepriteFile, BlendMode, LayerType}; use std::path::Path; fn main() { let ase = AsepriteFile::read_file(Path::new("layered.aseprite")).unwrap(); // Access layer by index let layer = ase.layer(0); println!("Layer name: {}", layer.name()); println!("Is visible: {}", layer.is_visible()); println!("Blend mode: {:?}", layer.blend_mode()); println!("Opacity: {}", layer.opacity()); // Access layer by name if let Some(layer) = ase.layer_by_name("Background") { println!("Found background layer at index {}", layer.id()); } // Iterate all layers for layer in ase.layers() { match layer.layer_type() { LayerType::Image => println!("{}: Regular image layer", layer.name()), LayerType::Group => println!("{}: Group layer", layer.name()), LayerType::Tilemap(tileset_id) => { println!("{}: Tilemap layer using tileset {}", layer.name(), tileset_id) } } // Check if layer has a parent (part of a group) if let Some(parent) = layer.parent() { println!(" Parent: {}", parent.name()); } } } ``` -------------------------------- ### Load and Export Aseprite Frames Source: https://github.com/alpine-alpaca/asefile/blob/main/README.md Reads an Aseprite file from disk and saves each frame as an individual PNG image. ```rust use std::path::Path; use asefile::AsepriteFile; use image::{self, ImageFormat}; fn main() { let file = Path::new("input.aseprite"); // Read file into memory let ase = AsepriteFile::read_file(&file).unwrap(); // Write one output image for each frame in the Aseprite file. for frame in 0..ase.num_frames() { let output = format!("output_{}.png", frame); // Create image in memory, then write it to disk as PNG. let img = ase.frame(frame).image(); img.save_with_format(output, ImageFormat::Png).unwrap(); } } ``` -------------------------------- ### Accessing Tilemap Data Source: https://context7.com/alpine-alpaca/asefile/llms.txt Demonstrates how to retrieve tilemap layers, dimensions, rendered images, and individual tile indices from an Aseprite file. ```rust use asefile::AsepriteFile; use std::path::Path; fn main() { let ase = AsepriteFile::read_file(Path::new("level.aseprite")).unwrap(); // Find tilemap layer if let Some(layer) = ase.layer_by_name("Tilemap 1") { let layer_id = layer.id(); // Get tilemap for frame 0 if let Some(tilemap) = ase.tilemap(layer_id, 0) { // Tilemap dimensions in tiles println!("Tilemap size: {}x{} tiles", tilemap.width(), tilemap.height()); // Tile dimensions in pixels let (tile_w, tile_h) = tilemap.tile_size(); println!("Tile size: {}x{} pixels", tile_w, tile_h); // Get rendered tilemap image let tilemap_image = tilemap.image(); // Access individual tiles for custom processing for y in 0..tilemap.height() { for x in 0..tilemap.width() { let tile = tilemap.tile(x, y); if tile.id() != 0 { // 0 is empty tile println!("Tile at ({}, {}): tileset index {}", x, y, tile.id()); } } } // Access the tileset used by this tilemap let tileset = tilemap.tileset(); println!("Uses tileset: {}", tileset.name()); } } } ``` -------------------------------- ### Working with Animation Tags Source: https://context7.com/alpine-alpaca/asefile/llms.txt Shows how to access animation tags by index or name, retrieve frame ranges, animation direction, and repeat counts. It also demonstrates iterating through frames within a specific tag. ```rust use asefile::{AsepriteFile, AnimationDirection}; use std::path::Path; fn main() { let ase = AsepriteFile::read_file(Path::new("character.aseprite")).unwrap(); println!("Total tags: {}", ase.num_tags()); // Access tag by index let tag = ase.tag(0); println!("Tag: {}", tag.name()); println!("Frame range: {} to {}", tag.from_frame(), tag.to_frame()); // Access tag by name if let Some(walk_tag) = ase.tag_by_name("walk") { // Get animation direction match walk_tag.animation_direction() { AnimationDirection::Forward => println!("Play forwards"), AnimationDirection::Reverse => println!("Play backwards"), AnimationDirection::PingPong => println!("Play back and forth"), } // Get repeat count (None means infinite) match walk_tag.repeat() { Some(count) => println!("Repeat {} times", count), None => println!("Loop infinitely"), } // Iterate frames in this tag for frame_idx in walk_tag.from_frame()..=walk_tag.to_frame() { let frame = ase.frame(frame_idx); let duration = frame.duration(); println!("Frame {}: {}ms", frame_idx, duration); } } } ``` -------------------------------- ### Custom Error Handling with `AsepriteParseError` Source: https://context7.com/alpine-alpaca/asefile/llms.txt Demonstrates custom error handling for file loading operations. Maps `AsepriteParseError` variants to user-friendly string messages for better error reporting. Returns a `Result` with either a loaded `AsepriteFile` or a formatted error string. ```rust use asefile::{AsepriteFile, AsepriteParseError}; use std::path::Path; fn load_sprite(path: &Path) -> Result { AsepriteFile::read_file(path).map_err(|e| { match e { AsepriteParseError::InvalidInput(msg) => { format!("Invalid Aseprite file: {}", msg) } AsepriteParseError::UnsupportedFeature(msg) => { format!("Unsupported feature: {}", msg) } AsepriteParseError::InternalError(msg) => { format!("Internal error: {}", msg) } AsepriteParseError::IoError(io_err) => { format!("Failed to read file: {}", io_err) } } }) } fn main() { match load_sprite(Path::new("sprite.aseprite")) { Ok(ase) => println!("Loaded sprite: {}x{}", ase.width(), ase.height()), Err(msg) => eprintln!("Error: {}", msg), } } ``` -------------------------------- ### Image Processing Utilities with `utils` Feature Source: https://context7.com/alpine-alpaca/asefile/llms.txt Enables `utils` feature for image processing. Use `extrude_border` to add a 1-pixel border and `to_indexed_image` to convert RGBA to indexed format using a provided palette. Requires `utils` feature enabled in `Cargo.toml`. ```rust // In Cargo.toml: // asefile = { version = "0.3", features = ["utils"] } use asefile::{AsepriteFile, util::{extrude_border, PaletteMapper, MappingOptions, to_indexed_image}}; use std::path::Path; fn main() { let ase = AsepriteFile::read_file(Path::new("tiles.aseprite")).unwrap(); let frame_img = ase.frame(0).image(); // Extrude border by 1 pixel to prevent tile gaps at certain zoom levels let extruded = extrude_border(frame_img.clone()); println!("Original: {}x{}, Extruded: {}x{}", frame_img.width(), frame_img.height(), extruded.width(), extruded.height() ); // Convert RGBA image back to indexed format if let Some(palette) = ase.palette() { let mapper = PaletteMapper::new( palette, MappingOptions { transparent: ase.transparent_color_index(), failure: 0, // Fallback index for unmapped colors } ); let ((width, height), indexed_data) = to_indexed_image(frame_img, &mapper); println!("Indexed image: {}x{}, {} bytes", width, height, indexed_data.len()); // indexed_data is now Vec with palette indices } } ``` -------------------------------- ### Accessing Cels in Aseprite Files Source: https://context7.com/alpine-alpaca/asefile/llms.txt Demonstrates multiple ways to access a cel (image data at a frame-layer intersection) and retrieve its properties like position, image data, and user data. Ensure the AsepriteFile is loaded before accessing cels. ```rust use asefile::AsepriteFile; use std::path::Path; fn main() { let ase = AsepriteFile::read_file(Path::new("sprite.aseprite")).unwrap(); // Multiple ways to access the same cel let cel_via_layer = ase.layer(0).frame(1); let cel_via_frame = ase.frame(1).layer(0); let cel_direct = ase.cel(1, 0); // (frame, layer) // Check if cel has content if !cel_direct.is_empty() { // Get the cel's image (same dimensions as the sprite) let img = cel_direct.image(); // Get cel position (can be negative if dragged off-canvas) let (x, y) = cel_direct.top_left(); println!("Cel position: ({}, {})", x, y); // Access user data attached to the cel if let Some(user_data) = cel_direct.user_data() { if let Some(text) = &user_data.text { println!("Cel annotation: {}", text); } if let Some(color) = &user_data.color { println!("Cel color marker: {:?}", color); } } } } ``` -------------------------------- ### Building a Texture Atlas with `rect_packer` Source: https://context7.com/alpine-alpaca/asefile/llms.txt Combines multiple Aseprite files or frames into a single texture atlas. Configures `rect_packer` for layout, loads sprite files, packs frames into the atlas, and saves the final atlas image. Outputs sprite metadata for game engine integration. ```rust use asefile::AsepriteFile; use image::{ImageFormat, RgbaImage}; use rect_packer::{Config, Packer}; use std::path::Path; fn main() { // Configure the atlas packer let config = Config { width: 256, height: 256, border_padding: 0, rectangle_padding: 1, // 1px gap between sprites }; let mut packer = Packer::new(config); // Track placed sprites and their images let mut placements: Vec<(String, i32, i32, u32, u32)> = Vec::new(); let mut images: Vec<(i32, i32, RgbaImage)> = Vec::new(); // Load and pack multiple sprite files for filename in &["hero.aseprite", "enemy.aseprite", "items.aseprite"] { let ase = AsepriteFile::read_file(Path::new(filename)).unwrap(); let (w, h) = ase.size(); for frame in 0..ase.num_frames() { if let Some(rect) = packer.pack(w as i32, h as i32, false) { let name = format!("{}_{}", filename.replace(".aseprite", ""), frame); placements.push((name, rect.x, rect.y, rect.width as u32, rect.height as u32)); images.push((rect.x, rect.y, ase.frame(frame).image())); } } } // Build final atlas image let (atlas_w, atlas_h) = images.iter() .fold((1i32, 1i32), |(w, h), (x, y, img)| { (w.max(x + img.width() as i32), h.max(y + img.height() as i32)) }); let mut atlas = RgbaImage::new(atlas_w as u32, atlas_h as u32); for (x, y, img) in &images { image::imageops::replace(&mut atlas, img, *x as i64, *y as i64); } atlas.save_with_format("atlas.png", ImageFormat::Png).unwrap(); // Output sprite metadata for game engine for (name, x, y, w, h) in placements { println!("{}: x={}, y={}, w={}, h={}", name, x, y, w, h); } } ``` -------------------------------- ### Processing Sprite Slices Source: https://context7.com/alpine-alpaca/asefile/llms.txt Shows how to iterate through named slices, including their animation keys, 9-slice data, pivot points, and user-defined metadata. ```rust use asefile::AsepriteFile; use std::path::Path; fn main() { let ase = AsepriteFile::read_file(Path::new("ui_button.aseprite")).unwrap(); for slice in ase.slices() { println!("Slice: {}", slice.name); // Slices can be animated with keys at different frames for key in &slice.keys { println!(" From frame {}: origin=({}, {}), size=({}, {})", key.from_frame, key.origin.0, key.origin.1, key.size.0, key.size.1 ); // 9-slice data for scalable UI elements if let Some(slice9) = &key.slice9 { println!(" 9-slice center: ({}, {}) size {}x{}", slice9.center_x, slice9.center_y, slice9.center_width, slice9.center_height ); } // Pivot point for rotation/attachment if let Some((px, py)) = key.pivot { println!(" Pivot: ({}, {})", px, py); } } // User data on slices if let Some(user_data) = &slice.user_data { if let Some(text) = &user_data.text { println!(" Annotation: {}", text); } } } } ``` -------------------------------- ### Reading Color Palettes Source: https://context7.com/alpine-alpaca/asefile/llms.txt Retrieves the color palette from indexed Aseprite files, including individual RGBA channel access and palette entry metadata. ```rust use asefile::AsepriteFile; use std::path::Path; fn main() { let ase = AsepriteFile::read_file(Path::new("indexed.aseprite")).unwrap(); // Check pixel format if ase.is_indexed_color() { println!("Transparent color index: {:?}", ase.transparent_color_index()); } // Access palette if let Some(palette) = ase.palette() { println!("Palette has {} colors", palette.num_colors()); for idx in 0..palette.num_colors() { if let Some(entry) = palette.color(idx) { let [r, g, b, a] = entry.raw_rgba8(); println!("Color {}: rgba({}, {}, {}, {})", idx, r, g, b, a); // Individual channels println!(" Red: {}, Green: {}, Blue: {}, Alpha: {}", entry.red(), entry.green(), entry.blue(), entry.alpha() ); // Color name (usually empty) if let Some(name) = entry.name() { println!(" Name: {}", name); } } } } } ``` -------------------------------- ### Extract and Save Frame Images Source: https://context7.com/alpine-alpaca/asefile/llms.txt Iterates through all frames of an Aseprite file, extracts each frame's image by combining visible layers, and saves them as PNG files. Frame duration is also accessible. ```rust use std::path::Path; use asefile::AsepriteFile; use image::ImageFormat; fn main() { let path = Path::new("animation.aseprite"); let ase = AsepriteFile::read_file(&path).unwrap(); // Export all frames as PNG files for frame_index in 0..ase.num_frames() { let frame = ase.frame(frame_index); let img = frame.image(); // Returns RgbaImage with all visible layers blended let output_path = format!("frame_{}.png", frame_index); img.save_with_format(&output_path, ImageFormat::Png).unwrap(); // Get frame duration for animation timing println!("Frame {} duration: {}ms", frame_index, frame.duration()); } } ``` -------------------------------- ### Debug Log for Proportional Scaling Source: https://github.com/alpine-alpaca/asefile/blob/main/doc/Transparency.md Diagnostic output showing pixel color differences during a proportional scaling operation. ```text ======> Writing cel: x:3..8, y:4..11 **** src=Rgba([0, 52685, 63993, 65535]), pixel=Rgba([60909, 30326, 5140, 32896]), a=255, opacity=128, new=Rgba([30573, 41461, 34451, 65534]) Pixel difference in tests\data\transparency_01.actual.png: 5,8 expected: Rgba([118, 162, 135, 255]) actual: Rgba([119, 161, 134, 255]) ``` -------------------------------- ### Debug Log for Chop Scaling Source: https://github.com/alpine-alpaca/asefile/blob/main/doc/Transparency.md Diagnostic output showing pixel color differences during a chop scaling operation. ```text ======> Writing cel: x:3..8, y:4..11 **** src=Rgba([0, 52685, 63993, 65535]), pixel=Rgba([60909, 30326, 5140, 32896]), a=255, opacity=128, new=Rgba([30573, 41461, 34451, 65534]) Pixel difference in tests\data\transparency_01.actual.png: 5,8 expected: Rgba([118, 162, 135, 255]) actual: Rgba([119, 161, 134, 255]) ``` -------------------------------- ### Debug Log for Blend Function Source: https://github.com/alpine-alpaca/asefile/blob/main/doc/Transparency.md Diagnostic output comparing expected and actual pixel values for a blend function. ```text **** src=Rgba([0, 205, 249, 255]), pixel=Rgba([237, 118, 20, 255]), opacity=128, new=Rgba([119, 161, 134, 255]) expected=Rgba([118, 162, 135, 255]) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.