looklook 0.6.0

Descriptive signal synthesiser.
// Copyright 2026 Gabriel Bjørnager Jensen.
//
// This file is part of LOOKLOOK.
//
// LOOKLOOK is free software: you can redistribute
// it and/or modify it under the terms of the GNU
// Affero General Public License as published by
// the Free Software Foundation, either version 3
// of the License, or (at your option) any later
// version.
//
// LOOKLOOK is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Af-
// fero General Public License along with LOOKLOOK.
// If not, see <https://www.gnu.org/licenses/>.

//! The [`Blob::dump`] method.

use crate::signal::Blob;
use crate::config::{Config, Format};

use std::debug_assert_matches;
use std::fs::File;
use std::io::{self, Write};
use std::path::Path;

impl Blob<'_> {
	/// Dumps the blob.
	///
	/// # Errors
	///
	/// Any I/O errors are forwarded.
	pub fn dump<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
		let path = path.as_ref();

		eprintln!("dumping as `{}` at \"{}\"", self.config().format.as_str(), path.display());

		let mut file = File::create_buffered(path)?;

		match self.config().format {
			Format::Png => {
				Self::dump_png_frame(self.config(), self.data(), &mut file)?;
			}

			_ => {
				unimplemented!();
			}
		}

		Ok(())
	}

	/// Dumps the encoded render as video.
	///
	/// # Errors
	///
	/// Any I/O errors are forwarded.
	fn dump_png_frame<W: ?Sized + Write>(config: &Config, data: &[u8], w: &mut W) -> io::Result<()> {
		debug_assert_matches!(config.format, Format::Png);

		let mut encoder = png::Encoder::new(w, config.width.into(), config.height.into());

		let colour_type = match config.channel_count {
			1 => png::ColorType::Grayscale,
			2 => png::ColorType::GrayscaleAlpha,
			3 => png::ColorType::Rgb,
			4 => png::ColorType::Rgba,

			count => {
				unimplemented!("channel count of `{count}` is not supported for PNG");
			}
		};

		let bit_depth = match config.sample_depth {
			1 => png::BitDepth::Eight,
			2 => png::BitDepth::Sixteen,

			depth => {
				unimplemented!("sampling depth of `{depth}B` is not supported for PNG");
			}
		};

		encoder.set_color(colour_type);
		encoder.set_depth(bit_depth);

		let mut w = encoder.write_header()?;
		w.write_image_data(data)?;

		Ok(())
	}
}