use std::num::{NonZeroI32, NonZeroU32};
mod support;
use img_gen::{
Background, Border, ColorGradient, Debug, Font, Generator, Layer, LayerOffset, Layout, Line,
LineHeight, LinearGradient, PreserveAspect, Presets, Size, SolidColor, Spread, Typography,
TypographyAlign, Weight,
};
fn basic_layout(
canvas_w: u32,
canvas_h: u32,
layer_w: u32,
layer_h: u32,
typography: Typography,
) -> Layout {
let layer_offset = LayerOffset {
x: (canvas_w as i32 - layer_w as i32) / 2,
y: (canvas_h as i32 - layer_h as i32) / 2,
};
let bg_layer = Layer {
background: Some(Background {
color: Some(SolidColor::default().into()),
image: None,
preserve_aspect: PreserveAspect::Off,
}),
..Default::default()
};
let layer = Layer {
size: Some(Size {
width: NonZeroU32::new(layer_w),
height: NonZeroU32::new(layer_h),
}),
offset: layer_offset,
typography: Some(typography),
..Default::default()
};
Layout {
size: Size {
width: NonZeroU32::new(canvas_w),
height: NonZeroU32::new(canvas_h),
},
layers: vec![bg_layer, layer],
debug: Some(Debug {
enable: true,
grid: false,
..Default::default()
}),
}
}
#[tokio::test]
async fn render_shrink_to_fit() {
let layer_w = 200u32;
let layer_h = 60u32;
let canvas_w = 400u32;
let canvas_h = 200u32;
let typography = Typography {
content: "All of this text must fit inside the small layer without being cut off."
.to_string(),
line: Line {
amount: NonZeroI32::new(3).unwrap(),
height: LineHeight::new(1.0).unwrap(),
},
overflow: true, color: SolidColor::from_string("white").unwrap().into(),
..Default::default()
};
let layout = basic_layout(canvas_w, canvas_h, layer_w, layer_h, typography);
let generator = Generator::new(vec![], Some(support::typography_font_cache_root())).unwrap();
let img = generator.render(layout).await.unwrap();
img.save("tests/out/test_typography_shrink_to_fit.png")
.unwrap();
}
#[tokio::test]
async fn render_wrap_with_ellipsis() {
let layer_w: u32 = 550;
let layer_h: u32 = 350;
let gradient_start = LayerOffset {
x: 0,
y: layer_h as i32 / 2,
};
let gradient_end = LayerOffset {
x: layer_w as i32 / 2,
y: layer_h as i32 / 2,
};
let typography = Typography {
content:
"This sentence is intentionally very long so that it definitely overflows the small \
layer height and must be truncated with an ellipsis at the end."
.to_string(),
line: Line {
amount: NonZeroI32::new(5).unwrap(),
height: LineHeight::new(1.2).unwrap(),
},
overflow: false, font: Font {
family: "Playfair Display".to_string(),
weight: Weight::Regular,
style: "normal".to_string(),
subset: "latin".to_string(),
path: None,
},
border: Some(Border {
width: NonZeroU32::new(2).unwrap(),
color: LinearGradient::new(
ColorGradient::new(None, Some(Presets::FabledSunset)).unwrap(),
gradient_start,
gradient_end,
Some(Spread::Reflect),
)
.into(),
}),
color: LinearGradient::new(
ColorGradient::new(None, Some(Presets::MillenniumPine)).unwrap(),
gradient_start,
gradient_end,
Some(Spread::Reflect),
)
.into(),
..Default::default()
};
let layout = basic_layout(600, 400, layer_w, layer_h, typography);
let generator = Generator::new(vec![], Some(support::typography_font_cache_root())).unwrap();
let img = generator.render(layout).await.unwrap();
img.save("tests/out/test_typography_wrap_ellipsis.png")
.unwrap();
}
#[tokio::test]
async fn render_center() {
let layer_w = 200u32;
let layer_h = 100u32;
let canvas_w = 400u32;
let canvas_h = 200u32;
let typography = Typography {
content: "Center\nthis\ntext.".to_string(),
align: TypographyAlign::CenterCenter,
line: Line {
amount: NonZeroI32::new(3).unwrap(),
height: LineHeight::new(1.0).unwrap(),
},
overflow: true, color: SolidColor::from_string("white").unwrap().into(),
..Default::default()
};
let layout = basic_layout(canvas_w, canvas_h, layer_w, layer_h, typography);
let generator = Generator::new(vec![], Some(support::typography_font_cache_root())).unwrap();
let img = generator.render(layout).await.unwrap();
img.save("tests/out/test_typography_center.png").unwrap();
}
#[tokio::test]
async fn render_end_bottom() {
let layer_w = 200u32;
let layer_h = 100u32;
let canvas_w = 400u32;
let canvas_h = 200u32;
let typography = Typography {
content: "This\nstarts at the `EndBottom`.".to_string(),
align: TypographyAlign::EndBottom,
line: Line {
amount: NonZeroI32::new(3).unwrap(),
height: LineHeight::new(1.0).unwrap(),
},
overflow: true, color: SolidColor::from_string("white").unwrap().into(),
..Default::default()
};
let layout = basic_layout(canvas_w, canvas_h, layer_w, layer_h, typography);
let generator = Generator::new(vec![], Some(support::typography_font_cache_root())).unwrap();
let img = generator.render(layout).await.unwrap();
img.save("tests/out/test_typography_end_bottom.png")
.unwrap();
}
#[tokio::test]
async fn render_local_font_path() {
let typography = Typography {
content: "Loaded from local file".to_string(),
font: Font {
family: "Noto Sans".to_string(),
path: Some("noto-sans-latin-400-normal.ttf".to_string()),
..Font::default()
},
line: Line {
amount: NonZeroI32::new(1).unwrap(),
height: LineHeight::new(1.0).unwrap(),
},
overflow: true,
color: SolidColor::from_string("black").unwrap().into(),
..Default::default()
};
let layout = basic_layout(300, 60, 280, 40, typography);
let generator = Generator::new(
vec![std::path::PathBuf::from("tests")],
Some(support::typography_font_cache_root()),
)
.unwrap();
let img = generator.render(layout).await.unwrap();
img.save("tests/out/test_typography_local_font.png")
.unwrap();
}