///|
/// Convert `mizchi/image` RGBA ImageData into the animation engine's Canvas.
///
/// `mizchi/image` normalizes decoded PNG/BMP/JPEG data to four bytes per pixel.
/// This adapter keeps that representation at the package boundary and lets
/// the animation core own frame timing, disposal, and GIF indexing.
pub fn canvas_from_image_data(
image : @image.ImageData,
) -> Canvas raise GifError {
canvas_from_rgba_bytes(width=image.width, height=image.height, image.data)
}
///|
/// Convert a Canvas back to `mizchi/image` RGBA ImageData.
pub fn Canvas::to_image_data(self : Canvas) -> @image.ImageData {
@image.ImageData::{
width: self.width,
height: self.height,
data: self.to_rgba_bytes(),
}
}
///|
/// Build a frame from one `mizchi/image` image.
pub fn frame_from_image_data(
image : @image.ImageData,
delay_cs? : Int = 0,
) -> Frame raise GifError {
Frame::new(canvas=canvas_from_image_data(image), delay_cs~)
}
///|
/// Build an animation from RGBA images decoded or resized by `mizchi/image`.
pub fn animation_from_image_data(
images : ArrayView[@image.ImageData],
delay_cs? : Int = 5,
loop_count? : Int,
) -> Animation raise GifError {
if images.length() == 0 {
raise InvalidDimensions
}
let first = images[0]
let mut animation = Animation::new(width=first.width, height=first.height)
match loop_count {
None => ()
Some(value) => animation = animation.with_loop_count(loop_count=Some(value))
}
for image in images {
if image.width != first.width || image.height != first.height {
raise InvalidDimensions
}
animation = animation.add_frame(frame_from_image_data(image, delay_cs~))
}
animation
}
///|
/// Encode one `mizchi/image` ImageData using the extended GIF engine.
pub fn encode_image_data(
image : @image.ImageData,
delay_cs? : Int = 0,
) -> Bytes raise GifError {
encode(animation_from_image_data([image], delay_cs~))
}
///|
/// Decode the first composited frame into the upstream ImageData shape.
pub fn decode_first_image_data(data : Bytes) -> @image.ImageData raise GifError {
let animation = decode(data)
let snapshots = compose(animation)
if snapshots.length() == 0 {
raise InvalidBlock(context="GIF has no composited frames")
}
snapshots[0].to_image_data()
}
///|
/// Encode a sequence of upstream ImageData values as a dynamic GIF.
pub fn encode_image_sequence(
images : ArrayView[@image.ImageData],
delay_cs? : Int = 5,
loop_count? : Int,
) -> Bytes raise GifError {
let loop_value = match loop_count {
None => 0
Some(value) => value
}
encode(animation_from_image_data(images, delay_cs~, loop_count=loop_value))
}