1use std::fs::File;
2use std::io::{BufRead, BufWriter, Seek};
3use std::path::Path;
4
5use crate::{codecs::*, ExtendedColorType, ImageReader};
6
7use crate::dynimage::DynamicImage;
8use crate::error::{ImageError, ImageFormatHint, ImageResult};
9use crate::error::{UnsupportedError, UnsupportedErrorKind};
10use crate::image::ImageFormat;
11#[allow(unused_imports)] use crate::image::{ImageDecoder, ImageEncoder};
13
14pub fn load<R: BufRead + Seek>(r: R, format: ImageFormat) -> ImageResult<DynamicImage> {
21 let mut reader = ImageReader::new(r);
22 reader.set_format(format);
23 reader.decode()
24}
25
26#[allow(unused_variables)]
27pub(crate) fn save_buffer_impl(
29 path: &Path,
30 buf: &[u8],
31 width: u32,
32 height: u32,
33 color: ExtendedColorType,
34) -> ImageResult<()> {
35 let format = ImageFormat::from_path(path)?;
36 save_buffer_with_format_impl(path, buf, width, height, color, format)
37}
38
39#[allow(unused_variables)]
40pub(crate) fn save_buffer_with_format_impl(
42 path: &Path,
43 buf: &[u8],
44 width: u32,
45 height: u32,
46 color: ExtendedColorType,
47 format: ImageFormat,
48) -> ImageResult<()> {
49 let buffered_file_write = &mut BufWriter::new(File::create(path)?); write_buffer_impl(buffered_file_write, buf, width, height, color, format)
51}
52
53#[allow(unused_variables)]
54pub(crate) fn write_buffer_impl<W: std::io::Write + Seek>(
56 buffered_write: &mut W,
57 buf: &[u8],
58 width: u32,
59 height: u32,
60 color: ExtendedColorType,
61 format: ImageFormat,
62) -> ImageResult<()> {
63 match format {
64 #[cfg(feature = "png")]
65 ImageFormat::Png => {
66 png::PngEncoder::new(buffered_write).write_image(buf, width, height, color)
67 }
68 #[cfg(feature = "jpeg")]
69 ImageFormat::Jpeg => {
70 jpeg::JpegEncoder::new(buffered_write).write_image(buf, width, height, color)
71 }
72 #[cfg(feature = "pnm")]
73 ImageFormat::Pnm => {
74 pnm::PnmEncoder::new(buffered_write).write_image(buf, width, height, color)
75 }
76 #[cfg(feature = "gif")]
77 ImageFormat::Gif => gif::GifEncoder::new(buffered_write).encode(buf, width, height, color),
78 #[cfg(feature = "ico")]
79 ImageFormat::Ico => {
80 ico::IcoEncoder::new(buffered_write).write_image(buf, width, height, color)
81 }
82 #[cfg(feature = "bmp")]
83 ImageFormat::Bmp => {
84 bmp::BmpEncoder::new(buffered_write).write_image(buf, width, height, color)
85 }
86 #[cfg(feature = "ff")]
87 ImageFormat::Farbfeld => {
88 farbfeld::FarbfeldEncoder::new(buffered_write).write_image(buf, width, height, color)
89 }
90 #[cfg(feature = "tga")]
91 ImageFormat::Tga => {
92 tga::TgaEncoder::new(buffered_write).write_image(buf, width, height, color)
93 }
94 #[cfg(feature = "exr")]
95 ImageFormat::OpenExr => {
96 openexr::OpenExrEncoder::new(buffered_write).write_image(buf, width, height, color)
97 }
98 #[cfg(feature = "tiff")]
99 ImageFormat::Tiff => {
100 tiff::TiffEncoder::new(buffered_write).write_image(buf, width, height, color)
101 }
102 #[cfg(feature = "avif")]
103 ImageFormat::Avif => {
104 avif::AvifEncoder::new(buffered_write).write_image(buf, width, height, color)
105 }
106 #[cfg(feature = "qoi")]
107 ImageFormat::Qoi => {
108 qoi::QoiEncoder::new(buffered_write).write_image(buf, width, height, color)
109 }
110 #[cfg(feature = "webp")]
111 ImageFormat::WebP => {
112 webp::WebPEncoder::new_lossless(buffered_write).write_image(buf, width, height, color)
113 }
114 #[cfg(feature = "hdr")]
115 ImageFormat::Hdr => {
116 hdr::HdrEncoder::new(buffered_write).write_image(buf, width, height, color)
117 }
118 _ => Err(ImageError::Unsupported(
119 UnsupportedError::from_format_and_kind(
120 ImageFormatHint::Unknown,
121 UnsupportedErrorKind::Format(ImageFormatHint::Name(format!("{format:?}"))),
122 ),
123 )),
124 }
125}
126
127static MAGIC_BYTES: [(&[u8], ImageFormat); 25] = [
128 (b"\x89PNG\r\n\x1a\n", ImageFormat::Png),
129 (&[0xff, 0xd8, 0xff], ImageFormat::Jpeg),
130 (b"GIF89a", ImageFormat::Gif),
131 (b"GIF87a", ImageFormat::Gif),
132 (b"RIFF", ImageFormat::WebP), (b"MM\x00*", ImageFormat::Tiff),
134 (b"II*\x00", ImageFormat::Tiff),
135 (b"DDS ", ImageFormat::Dds),
136 (b"BM", ImageFormat::Bmp),
137 (&[0, 0, 1, 0], ImageFormat::Ico),
138 (b"#?RADIANCE", ImageFormat::Hdr),
139 (b"P1", ImageFormat::Pnm),
140 (b"P2", ImageFormat::Pnm),
141 (b"P3", ImageFormat::Pnm),
142 (b"P4", ImageFormat::Pnm),
143 (b"P5", ImageFormat::Pnm),
144 (b"P6", ImageFormat::Pnm),
145 (b"P7", ImageFormat::Pnm),
146 (b"farbfeld", ImageFormat::Farbfeld),
147 (b"\0\0\0 ftypavif", ImageFormat::Avif),
148 (b"\0\0\0\x1cftypavif", ImageFormat::Avif),
149 (&[0x76, 0x2f, 0x31, 0x01], ImageFormat::OpenExr), (b"qoif", ImageFormat::Qoi),
151 (&[0x0a, 0x02], ImageFormat::Pcx),
152 (&[0x0a, 0x05], ImageFormat::Pcx),
153];
154
155pub fn guess_format(buffer: &[u8]) -> ImageResult<ImageFormat> {
161 match guess_format_impl(buffer) {
162 Some(format) => Ok(format),
163 None => Err(ImageError::Unsupported(ImageFormatHint::Unknown.into())),
164 }
165}
166
167pub(crate) fn guess_format_impl(buffer: &[u8]) -> Option<ImageFormat> {
168 for &(signature, format) in &MAGIC_BYTES {
169 if buffer.starts_with(signature) {
170 return Some(format);
171 }
172 }
173
174 None
175}