112 lines
2.7 KiB
Rust
112 lines
2.7 KiB
Rust
use ril::prelude::*;
|
|
|
|
pub fn produce(base: &Vec<u8>, elements: Vec<Element>) -> Result<Vec<u8>, CowError> {
|
|
let base = Image::<Rgba>::from_bytes_inferred(base)?;
|
|
let size = base.dimensions();
|
|
let mut base_image = base.with_overlay_mode(OverlayMode::Merge);
|
|
for element in elements {
|
|
let mut pos = element.position;
|
|
let mut img: Image = element.into_image()?;
|
|
if pos.0 < 0 {
|
|
img.crop(-pos.0 as u32, 0, size.0, size.1);
|
|
pos.0 = 0;
|
|
}
|
|
if pos.1 < 0 {
|
|
img.crop(0, -pos.1 as u32, size.0, size.1);
|
|
pos.1 = 0;
|
|
}
|
|
|
|
base_image.draw(&Paste::new(&img.convert()).with_position(pos.0 as u32, pos.1 as u32));
|
|
}
|
|
let mut buf = Vec::<u8>::new();
|
|
base_image.encode(ImageFormat::Png, &mut buf).unwrap();
|
|
|
|
Ok(buf)
|
|
}
|
|
|
|
pub struct Element {
|
|
position: (i32, i32),
|
|
dimensions: (u32, u32),
|
|
media: Media,
|
|
}
|
|
|
|
impl Element {
|
|
pub fn new(media: Media, position: (i32, i32), dimensions: (u32, u32)) -> Self {
|
|
Self {
|
|
position,
|
|
dimensions,
|
|
media,
|
|
}
|
|
}
|
|
|
|
fn into_image(self) -> Result<Image, CowError> {
|
|
match self.media {
|
|
// TODO: allow changing treatment of image
|
|
Media::Image((image, _)) => Ok(Image::from_bytes_inferred(*image)?.resized(
|
|
self.dimensions.0,
|
|
self.dimensions.1,
|
|
ResizeAlgorithm::Bicubic,
|
|
)),
|
|
Media::Text(text) => Ok(Image::new(
|
|
self.dimensions.0,
|
|
self.dimensions.1,
|
|
Dynamic::Rgba(Rgba::transparent()),
|
|
)
|
|
.with(
|
|
&TextSegment::new(
|
|
&Font::from_bytes(&text.font, 12.0).unwrap(),
|
|
text.text,
|
|
Dynamic::Rgba(Rgba::new(
|
|
text.fill.0,
|
|
text.fill.1,
|
|
text.fill.2,
|
|
text.fill.3,
|
|
)),
|
|
)
|
|
.with_size(text.size),
|
|
)),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub enum Media {
|
|
Text(Text),
|
|
Image((Box<Vec<u8>>, ImageMode)),
|
|
}
|
|
|
|
pub struct Text {
|
|
text: String,
|
|
font: Box<Vec<u8>>,
|
|
size: f32,
|
|
fill: (u8, u8, u8, u8),
|
|
}
|
|
|
|
pub enum ImageMode {
|
|
Stretch,
|
|
Fill,
|
|
Crop,
|
|
}
|
|
|
|
impl Text {
|
|
pub fn new(text: String, font: Box<Vec<u8>>, size: f32, fill: (u8, u8, u8, u8)) -> Self {
|
|
Self {
|
|
text,
|
|
font,
|
|
size,
|
|
fill,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum CowError {
|
|
Magick(String),
|
|
Other(String),
|
|
}
|
|
|
|
impl From<ril::Error> for CowError {
|
|
fn from(r: ril::Error) -> Self {
|
|
CowError::Other(r.to_string())
|
|
}
|
|
}
|