mod error;
mod format;
#[cfg(feature = "bmp")]
pub mod bmp;
#[cfg(feature = "pnm")]
pub mod pnm;
#[cfg(feature = "png-format")]
pub mod png;
#[cfg(feature = "jpeg")]
pub mod jpeg;
#[cfg(feature = "tiff-format")]
pub mod tiff;
#[cfg(feature = "gif-format")]
pub mod gif;
#[cfg(feature = "webp-format")]
pub mod webp;
#[cfg(feature = "jp2k-format")]
pub mod jp2k;
#[cfg(feature = "pdf-format")]
pub mod pdf;
#[cfg(feature = "ps-format")]
pub mod ps;
pub mod header;
pub mod spix;
pub mod convertfiles;
pub mod partify;
pub use crate::core::{ImageFormat, Pix, PixMut, PixelDepth};
pub use error::{IoError, IoResult};
pub use format::{detect_format, detect_format_from_bytes};
pub use header::{
ImageHeader, choose_output_format, read_image_header, read_image_header_mem, write_image_auto,
};
#[cfg(feature = "pnm")]
pub use pnm::{read_pam, write_pam, write_pnm_ascii};
use std::fs::File;
use std::io::{BufReader, BufWriter, Read, Seek, Write};
use std::path::Path;
pub fn read_image<P: AsRef<Path>>(path: P) -> IoResult<Pix> {
let path = path.as_ref();
let file = File::open(path).map_err(IoError::Io)?;
let mut reader = BufReader::new(file);
let mut header = [0u8; 12];
let bytes_read = reader.read(&mut header).map_err(IoError::Io)?;
let format = detect_format_from_bytes(&header[..bytes_read])?;
reader
.seek(std::io::SeekFrom::Start(0))
.map_err(IoError::Io)?;
read_image_format(reader, format)
}
pub fn read_image_mem(data: &[u8]) -> IoResult<Pix> {
let format = detect_format_from_bytes(data)?;
read_image_format(std::io::Cursor::new(data), format)
}
pub fn read_image_format<R: Read + Seek + std::io::BufRead>(
reader: R,
format: ImageFormat,
) -> IoResult<Pix> {
match format {
#[cfg(feature = "bmp")]
ImageFormat::Bmp => bmp::read_bmp(reader),
#[cfg(feature = "pnm")]
ImageFormat::Pnm => pnm::read_pnm(reader),
#[cfg(feature = "png-format")]
ImageFormat::Png => png::read_png(reader),
#[cfg(feature = "jpeg")]
ImageFormat::Jpeg => jpeg::read_jpeg(reader),
#[cfg(feature = "tiff-format")]
ImageFormat::Tiff
| ImageFormat::TiffG3
| ImageFormat::TiffG4
| ImageFormat::TiffRle
| ImageFormat::TiffPackbits
| ImageFormat::TiffLzw
| ImageFormat::TiffZip
| ImageFormat::TiffJpeg => tiff::read_tiff(reader),
#[cfg(feature = "gif-format")]
ImageFormat::Gif => gif::read_gif(reader),
#[cfg(feature = "webp-format")]
ImageFormat::WebP => webp::read_webp(reader),
#[cfg(feature = "jp2k-format")]
ImageFormat::Jp2 => jp2k::read_jp2k(reader),
ImageFormat::Spix => spix::read_spix(reader),
_ => Err(IoError::UnsupportedFormat(format!("{:?}", format))),
}
}
pub fn write_image<P: AsRef<Path>>(pix: &Pix, path: P, format: ImageFormat) -> IoResult<()> {
let file = File::create(path).map_err(IoError::Io)?;
#[cfg(feature = "tiff-format")]
if let Some(compression) = tiff::TiffCompression::from_image_format(format) {
let writer = BufWriter::new(file);
return tiff::write_tiff(pix, writer, compression);
}
let writer = BufWriter::new(file);
write_image_format(pix, writer, format)
}
pub fn write_image_mem(pix: &Pix, format: ImageFormat) -> IoResult<Vec<u8>> {
#[cfg(feature = "tiff-format")]
if let Some(compression) = tiff::TiffCompression::from_image_format(format) {
let mut cursor = std::io::Cursor::new(Vec::new());
tiff::write_tiff(pix, &mut cursor, compression)?;
return Ok(cursor.into_inner());
}
let mut buffer = Vec::new();
write_image_format(pix, &mut buffer, format)?;
Ok(buffer)
}
pub fn write_image_format<W: Write>(pix: &Pix, writer: W, format: ImageFormat) -> IoResult<()> {
match format {
#[cfg(feature = "bmp")]
ImageFormat::Bmp => bmp::write_bmp(pix, writer),
#[cfg(feature = "pnm")]
ImageFormat::Pnm => pnm::write_pnm(pix, writer),
#[cfg(feature = "png-format")]
ImageFormat::Png => png::write_png(pix, writer),
#[cfg(feature = "jpeg")]
ImageFormat::Jpeg => jpeg::write_jpeg(pix, writer, &jpeg::JpegOptions::default()),
#[cfg(feature = "tiff-format")]
ImageFormat::Tiff
| ImageFormat::TiffG3
| ImageFormat::TiffG4
| ImageFormat::TiffRle
| ImageFormat::TiffPackbits
| ImageFormat::TiffLzw
| ImageFormat::TiffZip
| ImageFormat::TiffJpeg => {
Err(IoError::UnsupportedFormat(
"TIFF requires seekable writer; use write_image or write_image_mem".to_string(),
))
}
#[cfg(feature = "gif-format")]
ImageFormat::Gif => gif::write_gif(pix, writer),
#[cfg(feature = "webp-format")]
ImageFormat::WebP => webp::write_webp(pix, writer),
#[cfg(feature = "jp2k-format")]
ImageFormat::Jp2 => Err(IoError::UnsupportedFormat(
"JP2K writing not yet supported".to_string(),
)),
#[cfg(feature = "pdf-format")]
ImageFormat::Lpdf => pdf::write_pdf(pix, writer, &pdf::PdfOptions::default()),
#[cfg(feature = "ps-format")]
ImageFormat::Ps => ps::write_ps(pix, writer, &ps::PsOptions::default()),
ImageFormat::Spix => spix::write_spix(pix, writer),
_ => Err(IoError::UnsupportedFormat(format!("{:?}", format))),
}
}
pub fn pixa_read_files(dir: impl AsRef<Path>, substr: Option<&str>) -> IoResult<crate::core::Pixa> {
let mut paths: Vec<std::path::PathBuf> = std::fs::read_dir(dir.as_ref())
.map_err(IoError::Io)?
.filter_map(|e| e.ok())
.filter(|e| e.path().is_file())
.filter(|e| {
let name = e.file_name().to_string_lossy().to_string();
match substr {
Some(s) => name.contains(s),
None => true,
}
})
.map(|e| e.path())
.collect();
paths.sort();
let mut pixa = crate::core::Pixa::new();
for path in &paths {
let pix = read_image(path)?;
pixa.push(pix);
}
Ok(pixa)
}
pub fn pixa_write_files(
rootname: &str,
pixa: &crate::core::Pixa,
format: ImageFormat,
) -> IoResult<()> {
let ext = get_format_extension(format);
for i in 0..pixa.len() {
let pix = pixa
.get(i)
.ok_or_else(|| IoError::InvalidData(format!("pixa index {} out of range", i)))?;
let filename = format!("{}{:03}.{}", rootname, i, ext);
write_image(pix, &filename, format)?;
}
Ok(())
}
pub fn get_format_extension(format: ImageFormat) -> &'static str {
match format {
ImageFormat::Bmp => "bmp",
ImageFormat::Jpeg => "jpg",
ImageFormat::Png => "png",
ImageFormat::Tiff
| ImageFormat::TiffG3
| ImageFormat::TiffG4
| ImageFormat::TiffRle
| ImageFormat::TiffPackbits
| ImageFormat::TiffLzw
| ImageFormat::TiffZip
| ImageFormat::TiffJpeg => "tif",
ImageFormat::Pnm => "pnm",
ImageFormat::Ps => "ps",
ImageFormat::Gif => "gif",
ImageFormat::Jp2 => "jp2",
ImageFormat::WebP => "webp",
ImageFormat::Lpdf => "pdf",
ImageFormat::Spix => "spix",
_ => "dat",
}
}