pub mod layers;
pub mod samples;
pub mod channels;
use crate::meta::Headers;
use crate::error::UnitResult;
use std::io::{Seek, BufWriter};
use crate::io::Write;
use crate::image::{Image, ignore_progress, SpecificChannels, IntoSample};
use crate::image::write::layers::{WritableLayers, LayersWriter};
use crate::math::Vec2;
use crate::block::writer::ChunksWriter;
pub fn write_rgba_file<R,G,B,A>(
path: impl AsRef<std::path::Path>, width: usize, height: usize,
colors: impl Sync + Fn(usize, usize) -> (R, G, B, A)
) -> UnitResult
where R: IntoSample, G: IntoSample, B: IntoSample, A: IntoSample,
{
let channels = SpecificChannels::rgba(|Vec2(x,y)| colors(x,y));
Image::from_channels((width, height), channels).write().to_file(path)
}
pub fn write_rgb_file<R,G,B>(
path: impl AsRef<std::path::Path>, width: usize, height: usize,
colors: impl Sync + Fn(usize, usize) -> (R, G, B)
) -> UnitResult
where R: IntoSample, G: IntoSample, B: IntoSample
{
let channels = SpecificChannels::rgb(|Vec2(x,y)| colors(x,y));
Image::from_channels((width, height), channels).write().to_file(path)
}
pub trait WritableImage<'img, WritableLayers>: Sized {
fn write(self) -> WriteImageWithOptions<'img, WritableLayers, fn(f64)>;
}
impl<'img, WritableLayers> WritableImage<'img, WritableLayers> for &'img Image<WritableLayers> {
fn write(self) -> WriteImageWithOptions<'img, WritableLayers, fn(f64)> {
WriteImageWithOptions {
image: self,
check_compatibility: true,
parallel: true,
on_progress: ignore_progress
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct WriteImageWithOptions<'img, Layers, OnProgress> {
image: &'img Image<Layers>,
on_progress: OnProgress,
check_compatibility: bool,
parallel: bool,
}
impl<'img, L, F> WriteImageWithOptions<'img, L, F>
where L: WritableLayers<'img>, F: FnMut(f64)
{
pub fn infer_meta_data(&self) -> Headers { self.image.layer_data.infer_headers(&self.image.attributes)
}
pub fn non_parallel(self) -> Self { Self { parallel: false, ..self } }
pub fn skip_compatibility_checks(self) -> Self { Self { check_compatibility: false, ..self } }
pub fn on_progress<OnProgress>(self, on_progress: OnProgress) -> WriteImageWithOptions<'img, L, OnProgress>
where OnProgress: FnMut(f64)
{
WriteImageWithOptions {
on_progress,
image: self.image,
check_compatibility: self.check_compatibility,
parallel: self.parallel
}
}
#[inline]
#[must_use]
pub fn to_file(self, path: impl AsRef<std::path::Path>) -> UnitResult {
crate::io::attempt_delete_file_on_write_error(path.as_ref(), move |write|
self.to_unbuffered(write)
)
}
#[inline]
#[must_use]
pub fn to_unbuffered(self, unbuffered: impl Write + Seek) -> UnitResult {
self.to_buffered(BufWriter::new(unbuffered))
}
#[must_use]
pub fn to_buffered(self, write: impl Write + Seek) -> UnitResult {
let headers = self.infer_meta_data();
let layers = self.image.layer_data.create_writer(&headers);
crate::block::write(
write, headers, self.check_compatibility,
move |meta, chunk_writer|{
let blocks = meta.collect_ordered_block_data(|block_index|
layers.extract_uncompressed_block(&meta.headers, block_index)
);
let chunk_writer = chunk_writer.on_progress(self.on_progress);
if self.parallel { chunk_writer.compress_all_blocks_parallel(&meta, blocks)?; }
else { chunk_writer.compress_all_blocks_sequential(&meta, blocks)?; }
Ok(())
}
)
}
}