fastpack_core/imaging/
scale.rs1use anyhow::{Result, bail};
2use image::{GenericImageView, imageops::FilterType};
3
4use crate::types::{
5 config::ScaleMode,
6 rect::{Point, Size, SourceRect},
7 sprite::{NinePatch, Sprite},
8};
9
10pub fn scale_sprite(sprite: &Sprite, factor: f32, mode: ScaleMode) -> Result<Sprite> {
18 if (factor - 1.0).abs() < f32::EPSILON {
19 return Ok(sprite.clone());
20 }
21
22 match mode {
23 ScaleMode::Scale2x | ScaleMode::Scale3x | ScaleMode::Hq2x | ScaleMode::Eagle => {
24 bail!(
25 "pixel art scale modes (scale2x/scale3x/hq2x/eagle) are not yet implemented; \
26 use smooth or fast"
27 );
28 }
29 ScaleMode::Smooth | ScaleMode::Fast => {}
30 }
31
32 let filter = match mode {
33 ScaleMode::Smooth => FilterType::Lanczos3,
34 ScaleMode::Fast => FilterType::Nearest,
35 _ => unreachable!(),
36 };
37
38 let (w, h) = sprite.image.dimensions();
39 let new_w = ((w as f32 * factor).round() as u32).max(1);
40 let new_h = ((h as f32 * factor).round() as u32).max(1);
41 let scaled_image = sprite.image.resize_exact(new_w, new_h, filter);
42
43 let original_size = Size {
44 w: ((sprite.original_size.w as f32 * factor).round() as u32).max(1),
45 h: ((sprite.original_size.h as f32 * factor).round() as u32).max(1),
46 };
47
48 let trim_rect = sprite.trim_rect.as_ref().map(|tr| SourceRect {
49 x: (tr.x as f32 * factor).round() as i32,
50 y: (tr.y as f32 * factor).round() as i32,
51 w: ((tr.w as f32 * factor).round() as u32).max(1),
52 h: ((tr.h as f32 * factor).round() as u32).max(1),
53 });
54
55 let nine_patch = sprite.nine_patch.map(|np| NinePatch {
56 top: (np.top as f32 * factor).round() as u32,
57 right: (np.right as f32 * factor).round() as u32,
58 bottom: (np.bottom as f32 * factor).round() as u32,
59 left: (np.left as f32 * factor).round() as u32,
60 });
61
62 let polygon = sprite.polygon.as_ref().map(|pts| {
63 pts.iter()
64 .map(|p| Point {
65 x: p.x * factor,
66 y: p.y * factor,
67 })
68 .collect()
69 });
70
71 Ok(Sprite {
72 id: sprite.id.clone(),
73 source_path: sprite.source_path.clone(),
74 image: scaled_image,
75 trim_rect,
76 original_size,
77 polygon,
78 nine_patch,
79 pivot: sprite.pivot,
80 content_hash: sprite.content_hash,
81 extrude: (sprite.extrude as f32 * factor).round() as u32,
82 alias_of: sprite.alias_of.clone(),
83 })
84}