open_texture_packer 0.2.5

Open source and free Texture Packer tool written in rust.
Documentation
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::sprite::{Sprite, JsonSprite};
use crate::constant::DEFAULT_FPS;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct JsonSpriteSheet {
    pub sprites: Vec<JsonSprite>,
    pub sheet_width: u32,
    pub sheet_height: u32,
}

#[derive(Debug, Clone)]
pub struct SpriteSheet {
    pub sprites: Vec<Sprite>,
    pub total_width: u32,
    pub total_height: u32,
    pub fps: u32,
}

impl SpriteSheet {
    pub fn new(sprites: Vec<Sprite>, total_width: u32, total_height: u32,) -> Self {
        SpriteSheet {
            sprites,
            total_width,
            total_height,
            fps: DEFAULT_FPS,
        }
    }

    pub fn to_json(&self) -> JsonSpriteSheet {
        let mut sprites = Vec::new();
        for (_i, sprite) in self.sprites.iter().enumerate() {
            sprites.push(sprite.to_json())
        }
        JsonSpriteSheet {
            sprites,
            sheet_width: self.total_width,
            sheet_height: self.total_height,
        }
    }

    pub fn change_fps(&mut self, fps: u32) {
        self.fps = fps;
    }

    pub fn total_frames(&self) -> usize {
        self.sprites.len()
    }

    pub fn to_css_animation(&self, image_path: PathBuf) -> String {
        let mut css = self.generate_animation_css();
        css.push_str("\n");

        css.push_str(&self.generate_css(&image_path.to_str().unwrap()));
        css
    }

    pub fn generate_css(&self, url: &str) -> String {
        let first_sprites = &self.sprites[0];
        let animation_duration = self.total_frames() as f64 / self.fps as f64;
        let animation = format!("animation: spriteAnimation {:.2}s steps(1) infinite;", animation_duration);

        format!(
            ".pic {{\n    width: {}px;\n    height: {}px;\n    background-image: url('{}');\n    background-size: {}px auto;\n    {}\n}}\n",
            first_sprites.width, first_sprites.height, url, self.total_width, animation
        )
    }

    pub fn generate_animation_css(&self) -> String {
        let mut css_animation = String::new();
        css_animation.push_str("@keyframes spriteAnimation {\n");

        for sprite in &self.sprites {
            css_animation.push_str(&sprite.get_css_animation_frame_property(self.total_frames() as u32));
        }

        css_animation.push_str("}\n");
        css_animation
    }
}

pub fn calculate_sheet_dimensions(
    sprites: &mut [Sprite],
    max_sheet_width: u32,
    max_sheet_height: u32,
) -> Vec<SpriteSheet> {
    let mut sheets = Vec::new();
    let mut current_sprites = Vec::new();
    let mut sprite_index = 0;
    let mut x_offset = 0;
    let mut y_offset = 0;
    let mut row_height = 0;
    let mut total_height = 0;
    let mut current_max_width = 0;
    let mut sheet_count = 0;

    for sprite in sprites.iter_mut() {
        let img_width = sprite.width;
        let img_height = sprite.height;

        if x_offset + img_width > max_sheet_width {
            x_offset = 0;
            y_offset += row_height;
            total_height += row_height;
            row_height = 0;
        }

        if y_offset + img_height > max_sheet_height {
            sheets.push(SpriteSheet::new(
                current_sprites.clone(),
                current_max_width,
                total_height + row_height,
            ));
            current_sprites.clear();
            x_offset = 0;
            y_offset = 0;
            total_height = 0;
            row_height = 0;
            current_max_width = 0;
            sheet_count += 1;
            sprite_index = 0;
        }

        sprite.update(x_offset, y_offset, sprite_index, sheet_count);
        current_sprites.push(sprite.clone());

        x_offset += img_width;
        row_height = row_height.max(img_height);
        current_max_width = current_max_width.max(x_offset);
        sprite_index += 1;
    }

    total_height += row_height;
    sheets.push(SpriteSheet::new(
        current_sprites,
        current_max_width,
        total_height,
    ));

    sheets
}