use gift::{Encoder, Step};
use pix::{
Palette, Raster,
gray::{Gray, Gray8},
rgb::{Rgb, SRgb8},
};
use std::error::Error;
use std::fs::File;
use std::io::BufWriter;
fn page1(p: &mut Palette) -> Raster<Gray8> {
let amber = SRgb8::new(255, 208, 0);
let red = SRgb8::new(255, 0, 0);
let mut r = Raster::with_clear(32, 32);
render_circle(&mut r, p, 12.0, 12.0, 3.0, amber);
render_circle(&mut r, p, 20.0, 12.0, 3.0, amber);
render_circle(&mut r, p, 12.0, 20.0, 3.0, amber);
render_circle(&mut r, p, 20.0, 20.0, 3.0, amber);
render_circle(&mut r, p, 16.0, 16.0, 3.5, red);
r
}
fn page2(p: &mut Palette) -> Raster<Gray8> {
let amber = SRgb8::new(255, 208, 0);
let mut r = Raster::with_clear(32, 32);
render_circle(&mut r, p, 12.0, 12.0, 3.0, amber);
render_circle(&mut r, p, 20.0, 12.0, 3.0, amber);
render_circle(&mut r, p, 12.0, 20.0, 3.0, amber);
render_circle(&mut r, p, 20.0, 20.0, 3.0, amber);
r
}
fn render_circle(
raster: &mut Raster<Gray8>,
palette: &mut Palette,
cx: f32,
cy: f32,
r: f32,
clr: SRgb8,
) {
let x0 = (cx - r).floor().max(0.0) as u32;
let x1 = (cx + r).ceil().min(raster.width() as f32) as u32;
let y0 = (cy - r).floor().max(0.0) as u32;
let y1 = (cy + r).ceil().min(raster.height() as f32) as u32;
let rs = r.powi(2);
for y in y0..y1 {
let yd = (cy - y as f32 - 0.5).abs();
let ys = yd.powi(2);
for x in x0..x1 {
let xd = (cx - x as f32 - 0.5).abs();
let xs = xd.powi(2);
let mut ds = xs + ys;
if ds < 1.0 {
ds = ds.powi(2);
}
let drs = ds / rs;
let v = 1.0 - drs.powi(2).min(1.0);
if v > 0.0 {
let i = u8::from(Gray::value(raster.pixel(x as i32, y as i32)));
if let Some(p) = palette.entry(i as usize) {
let red = (Rgb::red(clr) * v).max(Rgb::red(p));
let green = (Rgb::green(clr) * v).max(Rgb::green(p));
let blue = (Rgb::blue(clr) * v).max(Rgb::blue(p));
let rgb = SRgb8::new(red, green, blue);
if let Some(d) = palette.set_entry(rgb) {
*raster.pixel_mut(x as i32, y as i32) =
Gray8::new(d as u8);
}
}
}
}
}
}
fn palette_threshold_rgb8_256(v: usize) -> SRgb8 {
let i = match v as u8 {
0x00..=0x0F => 0,
0x10..=0x1E => 1,
0x1F..=0x2D => 2,
0x2E..=0x3B => 3,
0x3C..=0x49 => 4,
0x4A..=0x56 => 5,
0x57..=0x63 => 6,
0x64..=0x6F => 7,
0x70..=0x7B => 8,
0x7C..=0x86 => 9,
0x87..=0x91 => 10,
0x92..=0x9B => 11,
0x9C..=0xA5 => 12,
0xA6..=0xAE => 13,
0xAF..=0xB7 => 14,
0xB8..=0xBF => 15,
0xC0..=0xC7 => 16,
0xC8..=0xCE => 17,
0xCF..=0xD5 => 18,
0xD6..=0xDB => 19,
0xDC..=0xE1 => 20,
0xE2..=0xE6 => 21,
0xE7..=0xEB => 22,
0xEC..=0xEF => 23,
0xF0..=0xF3 => 24,
0xF4..=0xF6 => 25,
0xF7..=0xF9 => 26,
0xFA..=0xFB => 27,
0xFC..=0xFD => 28,
0xFE..=0xFE => 29,
0xFF..=0xFF => 30,
};
SRgb8::new(i * 4, i * 4, i * 5)
}
fn main() -> Result<(), Box<dyn Error>> {
let mut palette = Palette::new(256);
palette.set_entry(SRgb8::default());
palette.set_threshold_fn(palette_threshold_rgb8_256);
let mut fl = BufWriter::new(File::create("dots.gif")?);
let mut enc = Encoder::new(&mut fl).into_step_enc().with_loop_count(0);
let raster = page1(&mut palette);
let step = Step::with_indexed(raster, palette.clone())
.with_delay_time_cs(Some(200));
enc.encode_step(&step)?;
let raster = page2(&mut palette);
let step = Step::with_indexed(raster, palette.clone())
.with_delay_time_cs(Some(200));
enc.encode_step(&step)?;
Ok(())
}