1 
2 
3 use crate::rustimpl::lodepng_free;
4 use crate::rustimpl::lodepng_malloc;
5 
6 #[allow(non_camel_case_types)]
7 pub mod ffi;
8 
9 mod rustimpl;
10 use crate::rustimpl::*;
11 
12 mod error;
13 pub use crate::error::*;
14 mod huffman;
15 mod iter;
16 use crate::iter::*;
17 
18 pub use rgb::RGB;
19 pub use rgb::RGBA8 as RGBA;
20 
21 use std::os::raw::c_uint;
22 use std::fmt;
23 use std::mem;
24 use std::ptr;
25 use std::slice;
26 use std::cmp;
27 use std::fs::File;
28 use std::io::Write;
29 use std::io::Read;
30 use std::path::Path;
31 use std::marker::PhantomData;
32 use std::os::raw::c_void;
33 
34 pub use crate::ffi::State;
35 pub use crate::ffi::ColorType;
36 pub use crate::ffi::CompressSettings;
37 pub use crate::ffi::DecompressSettings;
38 pub use crate::ffi::Time;
39 pub use crate::ffi::DecoderSettings;
40 pub use crate::ffi::FilterStrategy;
41 pub use crate::ffi::EncoderSettings;
42 pub use crate::ffi::Error;
43 
44 pub use crate::ffi::Info;
45 pub use crate::ffi::ColorMode;
46 
47 #[doc(hidden)] #[deprecated(note="use `ColorType::GREY` instead")] pub const LCT_GREY: ColorType = ColorType::GREY;
48 #[doc(hidden)] #[deprecated(note="use `ColorType::RGB` instead")] pub const LCT_RGB: ColorType = ColorType::RGB;
49 #[doc(hidden)] #[deprecated(note="use `ColorType::PALETTE` instead")] pub const LCT_PALETTE: ColorType = ColorType::PALETTE;
50 #[doc(hidden)] #[deprecated(note="use `ColorType::GREY_ALPHA` instead")] pub const LCT_GREY_ALPHA: ColorType = ColorType::GREY_ALPHA;
51 #[doc(hidden)] #[deprecated(note="use `ColorType::RGBA` instead")] pub const LCT_RGBA: ColorType = ColorType::RGBA;
52 #[doc(hidden)] #[deprecated(note="use `FilterStrategy::ZERO` instead")] pub const LFS_ZERO: FilterStrategy = FilterStrategy::ZERO;
53 #[doc(hidden)] #[deprecated(note="use `FilterStrategy::MINSUM` instead")] pub const LFS_MINSUM: FilterStrategy = FilterStrategy::MINSUM;
54 #[doc(hidden)] #[deprecated(note="use `FilterStrategy::ENTROPY` instead")] pub const LFS_ENTROPY: FilterStrategy = FilterStrategy::ENTROPY;
55 #[doc(hidden)] #[deprecated(note="use `FilterStrategy::BRUTE_FORCE` instead")] pub const LFS_BRUTE_FORCE: FilterStrategy = FilterStrategy::BRUTE_FORCE;
56 
57 impl ColorMode {
new() -> Self58     pub fn new() -> Self {
59         Self::default()
60     }
61 
colortype(&self) -> ColorType62     pub fn colortype(&self) -> ColorType {
63         self.colortype
64     }
65 
66     #[inline]
bitdepth(&self) -> u3267     pub fn bitdepth(&self) -> u32 {
68         self.bitdepth
69     }
70 
set_bitdepth(&mut self, d: u32)71     pub fn set_bitdepth(&mut self, d: u32) {
72         assert!(d >= 1 && d <= 16);
73         self.bitdepth = d;
74     }
75 
palette_clear(&mut self)76     pub fn palette_clear(&mut self) {
77         unsafe {
78             lodepng_free(self.palette as *mut _);
79         }
80         self.palette = ptr::null_mut();
81         self.palettesize = 0;
82     }
83 
84     /// add 1 color to the palette
palette_add(&mut self, p: RGBA) -> Result<(), Error>85     pub fn palette_add(&mut self, p: RGBA) -> Result<(), Error> {
86         unsafe {
87             /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with
88               the max of 256 colors, it'll have the exact alloc size*/
89             if self.palette.is_null() {
90                 /*allocate palette if empty*/
91                 /*room for 256 colors with 4 bytes each*/
92                 self.palette = lodepng_malloc(1024) as *mut _;
93                 if self.palette.is_null() {
94                     return Err(Error(83));
95                 }
96             }
97             if self.palettesize >= 256 {
98                 return Err(Error(38));
99             }
100             *self.palette.offset(self.palettesize as isize) = p;
101             self.palettesize += 1;
102         }
103         Ok(())
104     }
105 
palette(&self) -> &[RGBA]106     pub fn palette(&self) -> &[RGBA] {
107         unsafe {
108             std::slice::from_raw_parts(self.palette, self.palettesize)
109         }
110     }
111 
palette_mut(&mut self) -> &mut [RGBA]112     pub fn palette_mut(&mut self) -> &mut [RGBA] {
113         unsafe {
114             std::slice::from_raw_parts_mut(self.palette as *mut _, self.palettesize)
115         }
116     }
117 
118     /// get the total amount of bits per pixel, based on colortype and bitdepth in the struct
bpp(&self) -> u32119     pub fn bpp(&self) -> u32 {
120         lodepng_get_bpp_lct(self.colortype, self.bitdepth()) /*4 or 6*/
121     }
122 
clear_key(&mut self)123     pub(crate) fn clear_key(&mut self) {
124         self.key_defined = 0;
125     }
126 
set_key(&mut self, r: u16, g: u16, b: u16)127     pub(crate) fn set_key(&mut self, r: u16, g: u16, b: u16) {
128         self.key_defined = 1;
129         self.key_r = c_uint::from(r);
130         self.key_g = c_uint::from(g);
131         self.key_b = c_uint::from(b);
132     }
133 
key(&self) -> Option<(u16, u16, u16)>134     pub(crate) fn key(&self) -> Option<(u16, u16, u16)> {
135         if self.key_defined != 0 {
136             Some((self.key_r as u16, self.key_g as u16, self.key_b as u16))
137         } else {
138             None
139         }
140     }
141 
142     /// get the amount of color channels used, based on colortype in the struct.
143     /// If a palette is used, it counts as 1 channel.
channels(&self) -> u8144     pub fn channels(&self) -> u8 {
145         self.colortype.channels()
146     }
147 
148     /// is it a greyscale type? (only colortype 0 or 4)
is_greyscale_type(&self) -> bool149     pub fn is_greyscale_type(&self) -> bool {
150         self.colortype == ColorType::GREY || self.colortype == ColorType::GREY_ALPHA
151     }
152 
153     /// has it got an alpha channel? (only colortype 2 or 6)
is_alpha_type(&self) -> bool154     pub fn is_alpha_type(&self) -> bool {
155         (self.colortype as u32 & 4) != 0
156     }
157 
158     /// has it got a palette? (only colortype 3)
is_palette_type(&self) -> bool159     pub fn is_palette_type(&self) -> bool {
160         self.colortype == ColorType::PALETTE
161     }
162 
163     /// only returns true if there is a palette and there is a value in the palette with alpha < 255.
164     /// Loops through the palette to check this.
has_palette_alpha(&self) -> bool165     pub fn has_palette_alpha(&self) -> bool {
166         self.palette().iter().any(|p| p.a < 255)
167     }
168 
169     /// Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image.
170     /// Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels).
171     /// Returns false if the image can only have opaque pixels.
172     /// In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values,
173     /// or if "key_defined" is true.
can_have_alpha(&self) -> bool174     pub fn can_have_alpha(&self) -> bool {
175         self.key().is_some() || self.is_alpha_type() || self.has_palette_alpha()
176     }
177 
178     /// Returns the byte size of a raw image buffer with given width, height and color mode
raw_size(&self, w: u32, h: u32) -> usize179     pub fn raw_size(&self, w: u32, h: u32) -> usize {
180         /*will not overflow for any color type if roughly w * h < 268435455*/
181         let bpp = self.bpp() as usize;
182         let n = w as usize * h as usize;
183         ((n / 8) * bpp) + ((n & 7) * bpp + 7) / 8
184     }
185 
186     /*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer*/
raw_size_idat(&self, w: usize, h: usize) -> usize187     pub(crate) fn raw_size_idat(&self, w: usize, h: usize) -> usize {
188         /*will not overflow for any color type if roughly w * h < 268435455*/
189         let bpp = self.bpp() as usize;
190         let line = ((w / 8) * bpp) + ((w & 7) * bpp + 7) / 8;
191         h * line
192     }
193 }
194 
195 impl Drop for ColorMode {
drop(&mut self)196     fn drop(&mut self) {
197         self.palette_clear()
198     }
199 }
200 
201 impl Clone for ColorMode {
clone(&self) -> Self202     fn clone(&self) -> Self {
203         let mut c = Self {
204             colortype: self.colortype,
205             bitdepth: self.bitdepth,
206             palette: ptr::null_mut(),
207             palettesize: 0,
208             key_defined: self.key_defined,
209             key_r: self.key_r,
210             key_g: self.key_g,
211             key_b: self.key_b,
212         };
213         for &p in self.palette() {
214             c.palette_add(p).unwrap();
215         }
216         c
217     }
218 }
219 
220 impl Default for ColorMode {
default() -> Self221     fn default() -> Self {
222         Self {
223             key_defined: 0,
224             key_r: 0,
225             key_g: 0,
226             key_b: 0,
227             colortype: ColorType::RGBA,
228             bitdepth: 8,
229             palette: ptr::null_mut(),
230             palettesize: 0,
231         }
232     }
233 }
234 
235 impl ColorType {
236     /// Create color mode with given type and bitdepth
to_color_mode(&self, bitdepth: c_uint) -> ColorMode237     pub fn to_color_mode(&self, bitdepth: c_uint) -> ColorMode {
238         unsafe {
239             ColorMode {
240                 colortype: *self,
241                 bitdepth,
242                 ..mem::zeroed()
243             }
244         }
245     }
246 
247     /// channels * bytes per channel = bytes per pixel
channels(&self) -> u8248     pub fn channels(&self) -> u8 {
249         match *self {
250             ColorType::GREY | ColorType::PALETTE => 1,
251             ColorType::GREY_ALPHA => 2,
252             ColorType::BGR |
253             ColorType::RGB => 3,
254             ColorType::BGRA |
255             ColorType::BGRX |
256             ColorType::RGBA => 4,
257         }
258     }
259 }
260 
261 impl Time {
new() -> Self262     pub fn new() -> Self {
263         Self::default()
264     }
265 }
266 
267 impl Info {
new() -> Self268     pub fn new() -> Self {
269         Self {
270             color: ColorMode::new(),
271             interlace_method: 0, compression_method: 0, filter_method: 0,
272             background_defined: 0, background_r: 0, background_g: 0, background_b: 0,
273             time_defined: 0, time: Time::new(),
274             unknown_chunks_data: [ptr::null_mut(), ptr::null_mut(), ptr::null_mut()],
275             unknown_chunks_size: [0, 0, 0],
276             text_num: 0, text_keys: ptr::null_mut(), text_strings: ptr::null_mut(),
277             itext_num: 0, itext_keys: ptr::null_mut(), itext_langtags: ptr::null_mut(),
278             itext_transkeys: ptr::null_mut(), itext_strings: ptr::null_mut(),
279             phys_defined: 0, phys_x: 0, phys_y: 0, phys_unit: 0,
280         }
281     }
282 
text_keys_cstr(&self) -> TextKeysCStrIter<'_>283     pub fn text_keys_cstr(&self) -> TextKeysCStrIter<'_> {
284         TextKeysCStrIter {
285             k: self.text_keys,
286             v: self.text_strings,
287             n: self.text_num,
288             _p: PhantomData,
289         }
290     }
291 
itext_keys(&self) -> ITextKeysIter<'_>292     pub fn itext_keys(&self) -> ITextKeysIter<'_> {
293         ITextKeysIter {
294             k: self.itext_keys,
295             l: self.itext_langtags,
296             t: self.itext_transkeys,
297             s: self.itext_strings,
298             n: self.itext_num,
299             _p: PhantomData,
300         }
301     }
302 
303     /// use this to clear the texts again after you filled them in
clear_text(&mut self)304     pub fn clear_text(&mut self) {
305         unsafe {
306             for i in 0..self.text_num as isize {
307                 string_cleanup(&mut *self.text_keys.offset(i));
308                 string_cleanup(&mut *self.text_strings.offset(i));
309             }
310             lodepng_free(self.text_keys as *mut _);
311             lodepng_free(self.text_strings as *mut _);
312             self.text_num = 0;
313         }
314     }
315 
316     /// push back both texts at once
add_text(&mut self, key: &str, str: &str) -> Result<(), Error>317     pub fn add_text(&mut self, key: &str, str: &str) -> Result<(), Error> {
318         self.push_text(key.as_bytes(), str.as_bytes())
319     }
320 
321     /// use this to clear the itexts again after you filled them in
clear_itext(&mut self)322     pub fn clear_itext(&mut self) {
323         unsafe {
324             for i in 0..self.itext_num as isize {
325                 string_cleanup(&mut *self.itext_keys.offset(i));
326                 string_cleanup(&mut *self.itext_langtags.offset(i));
327                 string_cleanup(&mut *self.itext_transkeys.offset(i));
328                 string_cleanup(&mut *self.itext_strings.offset(i));
329             }
330             lodepng_free(self.itext_keys as *mut _);
331             lodepng_free(self.itext_langtags as *mut _);
332             lodepng_free(self.itext_transkeys as *mut _);
333             lodepng_free(self.itext_strings as *mut _);
334         }
335         self.itext_keys = ptr::null_mut();
336         self.itext_langtags = ptr::null_mut();
337         self.itext_transkeys = ptr::null_mut();
338         self.itext_strings = ptr::null_mut();
339         self.itext_num = 0;
340     }
341 
342     /// push back the 4 texts of 1 chunk at once
add_itext(&mut self, key: &str, langtag: &str, transkey: &str, text: &str) -> Result<(), Error>343     pub fn add_itext(&mut self, key: &str, langtag: &str, transkey: &str, text: &str) -> Result<(), Error> {
344         self.push_itext(
345             key.as_bytes(),
346             langtag.as_bytes(),
347             transkey.as_bytes(),
348             text.as_bytes(),
349         )
350     }
351 
append_chunk(&mut self, position: ChunkPosition, chunk: ChunkRef<'_>) -> Result<(), Error>352     pub fn append_chunk(&mut self, position: ChunkPosition, chunk: ChunkRef<'_>) -> Result<(), Error> {
353         let set = position as usize;
354         unsafe {
355             let mut tmp = slice::from_raw_parts_mut(self.unknown_chunks_data[set], self.unknown_chunks_size[set]).to_owned();
356             chunk_append(&mut tmp, chunk.data);
357             let (data, size) = vec_into_raw(tmp)?;
358             self.unknown_chunks_data[set] = data;
359             self.unknown_chunks_size[set] = size;
360         }
361         Ok(())
362     }
363 
create_chunk<C: AsRef<[u8]>>(&mut self, position: ChunkPosition, chtype: C, data: &[u8]) -> Result<(), Error>364     pub fn create_chunk<C: AsRef<[u8]>>(&mut self, position: ChunkPosition, chtype: C, data: &[u8]) -> Result<(), Error> {
365         let chtype = chtype.as_ref();
366         if chtype.len() != 4 {
367             return Err(Error(67));
368         }
369         unsafe {
370             ffi::lodepng_chunk_create(
371                 &mut self.unknown_chunks_data[position as usize],
372                 &mut self.unknown_chunks_size[position as usize],
373                 data.len() as c_uint,
374                 chtype.as_ptr() as *const _,
375                 data.as_ptr(),
376             ).to_result()
377         }
378     }
379 
get<Name: AsRef<[u8]>>(&self, index: Name) -> Option<ChunkRef<'_>>380     pub fn get<Name: AsRef<[u8]>>(&self, index: Name) -> Option<ChunkRef<'_>> {
381         let index = index.as_ref();
382         self.unknown_chunks(ChunkPosition::IHDR)
383             .chain(self.unknown_chunks(ChunkPosition::PLTE))
384             .chain(self.unknown_chunks(ChunkPosition::IDAT))
385             .find(|c| c.is_type(index))
386     }
387 
unknown_chunks(&self, position: ChunkPosition) -> ChunksIter<'_>388     pub fn unknown_chunks(&self, position: ChunkPosition) -> ChunksIter<'_> {
389         ChunksIter {
390             data: unsafe {
391                 slice::from_raw_parts(
392                     self.unknown_chunks_data[position as usize],
393                     self.unknown_chunks_size[position as usize])
394             }
395         }
396     }
397 
398 
set_unknown_chunks(&mut self, src: &Info) -> Result<(), Error>399     fn set_unknown_chunks(&mut self, src: &Info) -> Result<(), Error> {
400         for i in 0..3 {
401             unsafe {
402                 self.unknown_chunks_size[i] = src.unknown_chunks_size[i];
403                 self.unknown_chunks_data[i] = lodepng_malloc(src.unknown_chunks_size[i]) as *mut u8;
404                 if self.unknown_chunks_data[i].is_null() && self.unknown_chunks_size[i] != 0 {
405                     return Err(Error(83));
406                 }
407                 for j in 0..src.unknown_chunks_size[i] {
408                     *self.unknown_chunks_data[i].offset(j as isize) = *src.unknown_chunks_data[i].offset(j as isize);
409                 }
410             }
411         }
412         Ok(())
413     }
414 }
415 
416 impl Clone for Info {
clone(&self) -> Self417     fn clone(&self) -> Self {
418         let mut dest = Self {
419             compression_method: self.compression_method,
420             filter_method: self.filter_method,
421             interlace_method: self.interlace_method,
422             color: self.color.clone(),
423             background_defined: self.background_defined,
424             background_r: self.background_r,
425             background_g: self.background_g,
426             background_b: self.background_b,
427             text_num: 0,
428             text_keys: ptr::null_mut(),
429             text_strings: ptr::null_mut(),
430             itext_num: 0,
431             itext_keys: ptr::null_mut(),
432             itext_langtags: ptr::null_mut(),
433             itext_transkeys: ptr::null_mut(),
434             itext_strings: ptr::null_mut(),
435             time_defined: self.time_defined,
436             time: self.time,
437             phys_defined: self.phys_defined,
438             phys_x: self.phys_x,
439             phys_y: self.phys_y,
440             phys_unit: self.phys_unit,
441             unknown_chunks_data: [ptr::null_mut(), ptr::null_mut(), ptr::null_mut()],
442             unknown_chunks_size: [0, 0, 0],
443         };
444         rustimpl::text_copy(&mut dest, self).unwrap();
445         rustimpl::itext_copy(&mut dest, self).unwrap();
446         dest.set_unknown_chunks(self).unwrap();
447         dest
448     }
449 }
450 
451 #[derive(Clone, Debug, Default)]
452 /// Make an image with custom settings
453 pub struct Encoder {
454     state: State,
455 }
456 
457 impl Encoder {
new() -> Self458     pub fn new() -> Self {
459         Self::default()
460     }
461 
462     #[inline]
set_auto_convert(&mut self, mode: bool)463     pub fn set_auto_convert(&mut self, mode: bool) {
464         self.state.set_auto_convert(mode);
465     }
466 
467     #[inline]
set_filter_strategy(&mut self, mode: FilterStrategy, palette_filter_zero: bool)468     pub fn set_filter_strategy(&mut self, mode: FilterStrategy, palette_filter_zero: bool) {
469         self.state.set_filter_strategy(mode, palette_filter_zero);
470     }
471 
472     #[inline]
473     /// Compress using another zlib implementation. It's gzip header + deflate + adler32 checksum.
474     ///
475     /// The callback returns 0 on success.
476     /// The callback MUST allocate memory using `libc::malloc`
set_custom_zlib(&mut self, callback: ffi::custom_compress_callback, context: *const c_void)477     pub unsafe fn set_custom_zlib(&mut self, callback: ffi::custom_compress_callback, context: *const c_void) {
478         self.state.set_custom_zlib(callback, context);
479     }
480 
481     #[inline]
482     /// Compress using another deflate implementation. It's just deflate, without headers or checksum.
483     ///
484     /// The callback returns 0 on success.
485     /// The callback MUST allocate memory using `libc::malloc`
set_custom_deflate(&mut self, callback: ffi::custom_compress_callback, context: *const c_void)486     pub unsafe fn set_custom_deflate(&mut self, callback: ffi::custom_compress_callback, context: *const c_void) {
487         self.state.set_custom_deflate(callback, context);
488     }
489 
490     #[inline]
info_raw(&self) -> &ColorMode491     pub fn info_raw(&self) -> &ColorMode {
492         self.state.info_raw()
493     }
494 
495     #[inline]
496     /// Color mode of the source bytes to be encoded
info_raw_mut(&mut self) -> &mut ColorMode497     pub fn info_raw_mut(&mut self) -> &mut ColorMode {
498         self.state.info_raw_mut()
499     }
500 
501     #[inline]
info_png(&self) -> &Info502     pub fn info_png(&self) -> &Info {
503         self.state.info_png()
504     }
505 
506     #[inline]
507     /// Color mode of the file to be created
info_png_mut(&mut self) -> &mut Info508     pub fn info_png_mut(&mut self) -> &mut Info {
509         self.state.info_png_mut()
510     }
511 
512     #[inline]
encode<PixelType: Copy + 'static>(&mut self, image: &[PixelType], w: usize, h: usize) -> Result<Vec<u8>, Error>513     pub fn encode<PixelType: Copy + 'static>(&mut self, image: &[PixelType], w: usize, h: usize) -> Result<Vec<u8>, Error> {
514         self.state.encode(image, w, h)
515     }
516 
517     #[inline]
encode_file<PixelType: Copy + 'static, P: AsRef<Path>>(&mut self, filepath: P, image: &[PixelType], w: usize, h: usize) -> Result<(), Error>518     pub fn encode_file<PixelType: Copy + 'static, P: AsRef<Path>>(&mut self, filepath: P, image: &[PixelType], w: usize, h: usize) -> Result<(), Error> {
519         self.state.encode_file(filepath, image, w, h)
520     }
521 }
522 
523 #[derive(Clone, Debug, Default)]
524 /// Read an image with custom settings
525 pub struct Decoder {
526     state: State,
527 }
528 
529 impl Decoder {
new() -> Self530     pub fn new() -> Self {
531         Self::default()
532     }
533 
534     #[inline]
info_raw(&self) -> &ColorMode535     pub fn info_raw(&self) -> &ColorMode {
536         self.state.info_raw()
537     }
538 
539     #[inline]
540     /// Preferred color mode for decoding
info_raw_mut(&mut self) -> &mut ColorMode541     pub fn info_raw_mut(&mut self) -> &mut ColorMode {
542         self.state.info_raw_mut()
543     }
544 
545     #[inline]
546     /// Actual color mode of the decoded image or inspected file
info_png(&self) -> &Info547     pub fn info_png(&self) -> &Info {
548         self.state.info_png()
549     }
550 
551     #[inline]
info_png_mut(&mut self) -> &mut Info552     pub fn info_png_mut(&mut self) -> &mut Info {
553         self.state.info_png_mut()
554     }
555 
556     /// whether to convert the PNG to the color type you want. Default: yes
color_convert(&mut self, true_or_false: bool)557     pub fn color_convert(&mut self, true_or_false: bool) {
558         self.state.color_convert(true_or_false);
559     }
560 
561     /// if false but remember_unknown_chunks is true, they're stored in the unknown chunks.
read_text_chunks(&mut self, true_or_false: bool)562     pub fn read_text_chunks(&mut self, true_or_false: bool) {
563         self.state.read_text_chunks(true_or_false);
564     }
565 
566     /// store all bytes from unknown chunks in the `Info` (off by default, useful for a png editor)
remember_unknown_chunks(&mut self, true_or_false: bool)567     pub fn remember_unknown_chunks(&mut self, true_or_false: bool) {
568         self.state.remember_unknown_chunks(true_or_false);
569     }
570 
571     /// Decompress ICC profile from iCCP chunk
get_icc(&self) -> Result<Vec<u8>, Error>572     pub fn get_icc(&self) -> Result<Vec<u8>, Error> {
573         self.state.get_icc()
574     }
575 
576     /// Load PNG from buffer using State's settings
577     ///
578     ///  ```no_run
579     ///  # use lodepng::*; let mut state = State::new();
580     ///  # let slice = [0u8]; #[allow(unused_variables)] fn do_stuff<T>(_buf: T) {}
581     ///
582     ///  state.info_raw_mut().colortype = ColorType::RGBA;
583     ///  match state.decode(&slice) {
584     ///      Ok(Image::RGBA(with_alpha)) => do_stuff(with_alpha),
585     ///      _ => panic!("¯\\_(ツ)_/¯")
586     ///  }
587     ///  ```
588     #[inline]
decode<Bytes: AsRef<[u8]>>(&mut self, input: Bytes) -> Result<Image, Error>589     pub fn decode<Bytes: AsRef<[u8]>>(&mut self, input: Bytes) -> Result<Image, Error> {
590         self.state.decode(input)
591     }
592 
decode_file<P: AsRef<Path>>(&mut self, filepath: P) -> Result<Image, Error>593     pub fn decode_file<P: AsRef<Path>>(&mut self, filepath: P) -> Result<Image, Error> {
594         self.state.decode_file(filepath)
595     }
596 
597     /// Updates `info_png`. Returns (width, height)
inspect(&mut self, input: &[u8]) -> Result<(usize, usize), Error>598     pub fn inspect(&mut self, input: &[u8]) -> Result<(usize, usize), Error> {
599         self.state.inspect(input)
600     }
601 
set_custom_zlib(&mut self, callback: ffi::custom_decompress_callback, context: *const c_void)602     pub unsafe fn set_custom_zlib(&mut self, callback: ffi::custom_decompress_callback, context: *const c_void) {
603         self.state.decoder.zlibsettings.custom_zlib = callback;
604         self.state.decoder.zlibsettings.custom_context = context;
605     }
606 
set_custom_inflate(&mut self, callback: ffi::custom_decompress_callback, context: *const c_void)607     pub unsafe fn set_custom_inflate(&mut self, callback: ffi::custom_decompress_callback, context: *const c_void) {
608         self.state.decoder.zlibsettings.custom_inflate = callback;
609         self.state.decoder.zlibsettings.custom_context = context;
610     }
611 }
612 
613 impl State {
new() -> Self614     pub fn new() -> Self {
615         Self::default()
616     }
617 
set_auto_convert(&mut self, mode: bool)618     pub fn set_auto_convert(&mut self, mode: bool) {
619         self.encoder.auto_convert = mode as c_uint;
620     }
621 
set_filter_strategy(&mut self, mode: FilterStrategy, palette_filter_zero: bool)622     pub fn set_filter_strategy(&mut self, mode: FilterStrategy, palette_filter_zero: bool) {
623         self.encoder.filter_strategy = mode;
624         self.encoder.filter_palette_zero = if palette_filter_zero {1} else {0};
625     }
626 
627     /// See `Encoder'
set_custom_zlib(&mut self, callback: ffi::custom_compress_callback, context: *const c_void)628     pub unsafe fn set_custom_zlib(&mut self, callback: ffi::custom_compress_callback, context: *const c_void) {
629         self.encoder.zlibsettings.custom_zlib = callback;
630         self.encoder.zlibsettings.custom_context = context;
631     }
632 
633     /// See `Encoder'
set_custom_deflate(&mut self, callback: ffi::custom_compress_callback, context: *const c_void)634     pub unsafe fn set_custom_deflate(&mut self, callback: ffi::custom_compress_callback, context: *const c_void) {
635         self.encoder.zlibsettings.custom_deflate = callback;
636         self.encoder.zlibsettings.custom_context = context;
637     }
638 
info_raw(&self) -> &ColorMode639     pub fn info_raw(&self) -> &ColorMode {
640         &self.info_raw
641     }
642 
info_raw_mut(&mut self) -> &mut ColorMode643     pub fn info_raw_mut(&mut self) -> &mut ColorMode {
644         &mut self.info_raw
645     }
646 
info_png(&self) -> &Info647     pub fn info_png(&self) -> &Info {
648         &self.info_png
649     }
650 
info_png_mut(&mut self) -> &mut Info651     pub fn info_png_mut(&mut self) -> &mut Info {
652         &mut self.info_png
653     }
654 
655     /// whether to convert the PNG to the color type you want. Default: yes
color_convert(&mut self, true_or_false: bool)656     pub fn color_convert(&mut self, true_or_false: bool) {
657         self.decoder.color_convert = if true_or_false { 1 } else { 0 };
658     }
659 
660     /// if false but remember_unknown_chunks is true, they're stored in the unknown chunks.
read_text_chunks(&mut self, true_or_false: bool)661     pub fn read_text_chunks(&mut self, true_or_false: bool) {
662         self.decoder.read_text_chunks = if true_or_false { 1 } else { 0 };
663     }
664 
665     /// store all bytes from unknown chunks in the `Info` (off by default, useful for a png editor)
remember_unknown_chunks(&mut self, true_or_false: bool)666     pub fn remember_unknown_chunks(&mut self, true_or_false: bool) {
667         self.decoder.remember_unknown_chunks = if true_or_false { 1 } else { 0 };
668     }
669 
670     /// Decompress ICC profile from iCCP chunk
get_icc(&self) -> Result<Vec<u8>, Error>671     pub fn get_icc(&self) -> Result<Vec<u8>, Error> {
672         let iccp = self.info_png().get("iCCP");
673         if iccp.is_none() {
674             return Err(Error(89));
675         }
676         let iccp = iccp.as_ref().unwrap().data();
677         if iccp.get(0).cloned().unwrap_or(255) == 0 { // text min length is 1
678             return Err(Error(89));
679         }
680 
681         let name_len = cmp::min(iccp.len(), 80); // skip name
682         for i in 0..name_len {
683             if iccp[i] == 0 { // string terminator
684                 if iccp.get(i+1).cloned().unwrap_or(255) != 0 { // compression type
685                     return Err(Error(72));
686                 }
687                 return zlib_decompress(&iccp[i+2 ..], &self.decoder.zlibsettings);
688             }
689         }
690         Err(Error(75))
691     }
692 
693     /// Load PNG from buffer using State's settings
694     ///
695     ///  ```no_run
696     ///  # use lodepng::*; let mut state = State::new();
697     ///  # let slice = [0u8]; #[allow(unused_variables)] fn do_stuff<T>(_buf: T) {}
698     ///
699     ///  state.info_raw_mut().colortype = ColorType::RGBA;
700     ///  match state.decode(&slice) {
701     ///      Ok(Image::RGBA(with_alpha)) => do_stuff(with_alpha),
702     ///      _ => panic!("¯\\_(ツ)_/¯")
703     ///  }
704     ///  ```
decode<Bytes: AsRef<[u8]>>(&mut self, input: Bytes) -> Result<Image, Error>705     pub fn decode<Bytes: AsRef<[u8]>>(&mut self, input: Bytes) -> Result<Image, Error> {
706         let input = input.as_ref();
707         unsafe {
708             let (v, w, h) = rustimpl::lodepng_decode(self, input)?;
709             let (data, _) = vec_into_raw(v)?;
710             Ok(new_bitmap(data, w, h, self.info_raw.colortype, self.info_raw.bitdepth))
711         }
712     }
713 
decode_file<P: AsRef<Path>>(&mut self, filepath: P) -> Result<Image, Error>714     pub fn decode_file<P: AsRef<Path>>(&mut self, filepath: P) -> Result<Image, Error> {
715         self.decode(&load_file(filepath)?)
716     }
717 
718     /// Updates `info_png`. Returns (width, height)
inspect(&mut self, input: &[u8]) -> Result<(usize, usize), Error>719     pub fn inspect(&mut self, input: &[u8]) -> Result<(usize, usize), Error> {
720         let (info, w, h) = rustimpl::lodepng_inspect(&self.decoder, input)?;
721         self.info_png = info;
722         Ok((w, h))
723     }
724 
encode<PixelType: Copy + 'static>(&mut self, image: &[PixelType], w: usize, h: usize) -> Result<Vec<u8>, Error>725     pub fn encode<PixelType: Copy + 'static>(&mut self, image: &[PixelType], w: usize, h: usize) -> Result<Vec<u8>, Error> {
726         let image = buffer_for_type(image, w, h, self.info_raw.colortype, self.info_raw.bitdepth)?;
727         Ok(rustimpl::lodepng_encode(image, w as c_uint, h as c_uint, self)?)
728     }
729 
encode_file<PixelType: Copy + 'static, P: AsRef<Path>>(&mut self, filepath: P, image: &[PixelType], w: usize, h: usize) -> Result<(), Error>730     pub fn encode_file<PixelType: Copy + 'static, P: AsRef<Path>>(&mut self, filepath: P, image: &[PixelType], w: usize, h: usize) -> Result<(), Error> {
731         let buf = self.encode(image, w, h)?;
732         save_file(filepath, buf.as_ref())
733     }
734 }
735 
736 impl Default for State {
default() -> Self737     fn default() -> Self {
738         Self {
739             decoder: DecoderSettings::new(),
740             encoder: EncoderSettings::new(),
741             info_raw: ColorMode::new(),
742             info_png: Info::new(),
743             error: Error(1),
744         }
745     }
746 }
747 
748 pub use rgb::alt::Gray as Grey;
749 pub use rgb::alt::GrayAlpha as GreyAlpha;
750 
751 /// Bitmap types.
752 ///
753 /// Images with >=8bpp are stored with pixel per vec element.
754 /// Images with <8bpp are represented as a bunch of bytes, with multiple pixels per byte.
755 #[derive(Debug)]
756 pub enum Image {
757     /// Bytes of the image. See bpp how many pixels per element there are
758     RawData(Bitmap<u8>),
759     Grey(Bitmap<Grey<u8>>),
760     Grey16(Bitmap<Grey<u16>>),
761     GreyAlpha(Bitmap<GreyAlpha<u8>>),
762     GreyAlpha16(Bitmap<GreyAlpha<u16>>),
763     RGBA(Bitmap<RGBA>),
764     RGB(Bitmap<RGB<u8>>),
765     RGBA16(Bitmap<rgb::RGBA<u16>>),
766     RGB16(Bitmap<RGB<u16>>),
767 }
768 
769 /// Position in the file section after…
770 #[derive(Copy, Clone, PartialEq, Eq)]
771 pub enum ChunkPosition {
772     IHDR = 0,
773     PLTE = 1,
774     IDAT = 2,
775 }
776 
777 /// Reference to a chunk
778 #[derive(Copy, Clone)]
779 pub struct ChunkRef<'a> {
780     data: &'a [u8],
781 }
782 
783 /// Low-level representation of an image
784 pub struct Bitmap<PixelType: Copy + 'static> {
785     /// Raw bitmap memory. Layout depends on color mode and bitdepth used to create it.
786     ///
787     /// * For RGB/RGBA images one element is one pixel.
788     /// * For <8bpp images pixels are packed, so raw bytes are exposed and you need to do bit-twiddling youself
789     pub buffer: Vec<PixelType>,
790     /// Width in pixels
791     pub width: usize,
792     /// Height in pixels
793     pub height: usize,
794 }
795 
796 impl<T: Copy> Bitmap<T> {
from_buffer(out: *mut u8, w: usize, h: usize) -> Self797     unsafe fn from_buffer(out: *mut u8, w: usize, h: usize) -> Self {
798         Self {
799             buffer: vec_from_malloced(out as *mut _, w * h),
800             width: w,
801             height: h,
802         }
803     }
804 }
805 
806 impl<PixelType: Copy + 'static> fmt::Debug for Bitmap<PixelType> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result807     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
808         write!(f, "{{{} × {} Bitmap}}", self.width, self.height)
809     }
810 }
811 
required_size(w: usize, h: usize, colortype: ColorType, bitdepth: u32) -> usize812 fn required_size(w: usize, h: usize, colortype: ColorType, bitdepth: u32) -> usize {
813     colortype.to_color_mode(bitdepth).raw_size(w as c_uint, h as c_uint)
814 }
815 
vec_from_malloced<T>(ptr: *mut T, elts: usize) -> Vec<T> where T: Copy816 unsafe fn vec_from_malloced<T>(ptr: *mut T, elts: usize) -> Vec<T> where T: Copy {
817     let v = Vec::from(std::slice::from_raw_parts(ptr, elts));
818     libc::free(ptr as *mut _);
819     v
820 }
821 
new_bitmap(out: *mut u8, w: usize, h: usize, colortype: ColorType, bitdepth: c_uint) -> Image822 unsafe fn new_bitmap(out: *mut u8, w: usize, h: usize, colortype: ColorType, bitdepth: c_uint) -> Image {
823     match (colortype, bitdepth) {
824         (ColorType::RGBA, 8) => Image::RGBA(Bitmap::from_buffer(out, w, h)),
825         (ColorType::RGB, 8) => Image::RGB(Bitmap::from_buffer(out, w, h)),
826         (ColorType::RGBA, 16) => Image::RGBA16(Bitmap::from_buffer(out, w, h)),
827         (ColorType::RGB, 16) => Image::RGB16(Bitmap::from_buffer(out, w, h)),
828         (ColorType::GREY, 8) => Image::Grey(Bitmap::from_buffer(out, w, h)),
829         (ColorType::GREY, 16) => Image::Grey16(Bitmap::from_buffer(out, w, h)),
830         (ColorType::GREY_ALPHA, 8) => Image::GreyAlpha(Bitmap::from_buffer(out, w, h)),
831         (ColorType::GREY_ALPHA, 16) => Image::GreyAlpha16(Bitmap::from_buffer(out, w, h)),
832         (_, 0) => panic!("Invalid depth"),
833         (c, b) => Image::RawData(Bitmap {
834             buffer: vec_from_malloced(out, required_size(w, h, c, b)),
835             width: w,
836             height: h,
837         }),
838     }
839 }
840 
save_file<P: AsRef<Path>>(filepath: P, data: &[u8]) -> Result<(), Error>841 fn save_file<P: AsRef<Path>>(filepath: P, data: &[u8]) -> Result<(), Error> {
842     let mut file = File::create(filepath)?;
843     file.write_all(data)?;
844     Ok(())
845 }
846 
load_file<P: AsRef<Path>>(filepath: P) -> Result<Vec<u8>, Error>847 fn load_file<P: AsRef<Path>>(filepath: P) -> Result<Vec<u8>, Error> {
848     let mut file = File::open(filepath)?;
849     let mut data = Vec::new();
850     file.read_to_end(&mut data)?;
851     Ok(data)
852 }
853 
854 /// Converts PNG data in memory to raw pixel data.
855 ///
856 /// `decode32` and `decode24` are more convenient if you want specific image format.
857 ///
858 /// See `State::decode()` for advanced decoding.
859 ///
860 /// * `in`: Memory buffer with the PNG file.
861 /// * `colortype`: the desired color type for the raw output image. See `ColorType`.
862 /// * `bitdepth`: the desired bit depth for the raw output image. 1, 2, 4, 8 or 16. Typically 8.
decode_memory<Bytes: AsRef<[u8]>>(input: Bytes, colortype: ColorType, bitdepth: c_uint) -> Result<Image, Error>863 pub fn decode_memory<Bytes: AsRef<[u8]>>(input: Bytes, colortype: ColorType, bitdepth: c_uint) -> Result<Image, Error> {
864     let input = input.as_ref();
865     unsafe {
866         assert!(bitdepth > 0 && bitdepth <= 16);
867         let (v, w, h) = rustimpl::lodepng_decode_memory(input, colortype, bitdepth)?;
868         let (data, _) = vec_into_raw(v)?;
869         Ok(new_bitmap(data, w, h, colortype, bitdepth))
870     }
871 }
872 
873 /// Same as `decode_memory`, but always decodes to 32-bit RGBA raw image
decode32<Bytes: AsRef<[u8]>>(input: Bytes) -> Result<Bitmap<RGBA>, Error>874 pub fn decode32<Bytes: AsRef<[u8]>>(input: Bytes) -> Result<Bitmap<RGBA>, Error> {
875     match decode_memory(input, ColorType::RGBA, 8)? {
876         Image::RGBA(img) => Ok(img),
877         _ => Err(Error(56)), // given output image colortype or bitdepth not supported for color conversion
878     }
879 }
880 
881 /// Same as `decode_memory`, but always decodes to 24-bit RGB raw image
decode24<Bytes: AsRef<[u8]>>(input: Bytes) -> Result<Bitmap<RGB<u8>>, Error>882 pub fn decode24<Bytes: AsRef<[u8]>>(input: Bytes) -> Result<Bitmap<RGB<u8>>, Error> {
883     match decode_memory(input, ColorType::RGB, 8)? {
884         Image::RGB(img) => Ok(img),
885         _ => Err(Error(56)),
886     }
887 }
888 
889 /// Load PNG from disk, from file with given name.
890 /// Same as the other decode functions, but instead takes a file path as input.
891 ///
892 /// `decode32_file` and `decode24_file` are more convenient if you want specific image format.
893 ///
894 /// There's also `State::decode()` if you'd like to set more settings.
895 ///
896 ///  ```no_run
897 ///  # use lodepng::*; let filepath = std::path::Path::new("");
898 ///  # fn do_stuff<T>(_buf: T) {}
899 ///
900 ///  match decode_file(filepath, ColorType::RGBA, 8) {
901 ///      Ok(Image::RGBA(with_alpha)) => do_stuff(with_alpha),
902 ///      Ok(Image::RGB(without_alpha)) => do_stuff(without_alpha),
903 ///      _ => panic!("¯\\_(ツ)_/¯")
904 ///  }
905 ///  ```
decode_file<P: AsRef<Path>>(filepath: P, colortype: ColorType, bitdepth: c_uint) -> Result<Image, Error>906 pub fn decode_file<P: AsRef<Path>>(filepath: P, colortype: ColorType, bitdepth: c_uint) -> Result<Image, Error> {
907     decode_memory(&load_file(filepath)?, colortype, bitdepth)
908 }
909 
910 /// Same as `decode_file`, but always decodes to 32-bit RGBA raw image
decode32_file<P: AsRef<Path>>(filepath: P) -> Result<Bitmap<RGBA>, Error>911 pub fn decode32_file<P: AsRef<Path>>(filepath: P) -> Result<Bitmap<RGBA>, Error> {
912     match decode_file(filepath, ColorType::RGBA, 8)? {
913         Image::RGBA(img) => Ok(img),
914         _ => Err(Error(56)),
915     }
916 }
917 
918 /// Same as `decode_file`, but always decodes to 24-bit RGB raw image
decode24_file<P: AsRef<Path>>(filepath: P) -> Result<Bitmap<RGB<u8>>, Error>919 pub fn decode24_file<P: AsRef<Path>>(filepath: P) -> Result<Bitmap<RGB<u8>>, Error> {
920     match decode_file(filepath, ColorType::RGB, 8)? {
921         Image::RGB(img) => Ok(img),
922         _ => Err(Error(56)),
923     }
924 }
925 
buffer_for_type<PixelType: Copy + 'static>(image: &[PixelType], w: usize, h: usize, colortype: ColorType, bitdepth: u32) -> Result<&[u8], Error>926 fn buffer_for_type<PixelType: Copy + 'static>(image: &[PixelType], w: usize, h: usize, colortype: ColorType, bitdepth: u32) -> Result<&[u8], Error> {
927     let bytes_per_pixel = bitdepth as usize/8;
928     assert!(mem::size_of::<PixelType>() <= 4*bytes_per_pixel, "Implausibly large {}-byte pixel data type", mem::size_of::<PixelType>());
929 
930     let px_bytes = mem::size_of::<PixelType>();
931     let image_bytes = image.len() * px_bytes;
932     let required_bytes = required_size(w, h, colortype, bitdepth);
933 
934     if image_bytes != required_bytes {
935         debug_assert_eq!(image_bytes, required_bytes, "Image is {} bytes large ({}x{}x{}), but needs to be {} ({:?}, {})",
936             image_bytes, w,h,px_bytes, required_bytes, colortype, bitdepth);
937         return Err(Error(84));
938     }
939 
940     unsafe {
941         Ok(slice::from_raw_parts(image.as_ptr() as *const _, image_bytes))
942     }
943 }
944 
945 /// Converts raw pixel data into a PNG image in memory. The colortype and bitdepth
946 /// of the output PNG image cannot be chosen, they are automatically determined
947 /// by the colortype, bitdepth and content of the input pixel data.
948 ///
949 /// Note: for 16-bit per channel colors, needs big endian format like PNG does.
950 ///
951 /// * `image`: The raw pixel data to encode. The size of this buffer should be `w` * `h` * (bytes per pixel), bytes per pixel depends on colortype and bitdepth.
952 /// * `w`: width of the raw pixel data in pixels.
953 /// * `h`: height of the raw pixel data in pixels.
954 /// * `colortype`: the color type of the raw input image. See `ColorType`.
955 /// * `bitdepth`: the bit depth of the raw input image. 1, 2, 4, 8 or 16. Typically 8.
encode_memory<PixelType: Copy + 'static>(image: &[PixelType], w: usize, h: usize, colortype: ColorType, bitdepth: c_uint) -> Result<Vec<u8>, Error>956 pub fn encode_memory<PixelType: Copy + 'static>(image: &[PixelType], w: usize, h: usize, colortype: ColorType, bitdepth: c_uint) -> Result<Vec<u8>, Error> {
957     let image = buffer_for_type(image, w, h, colortype, bitdepth)?;
958     Ok(rustimpl::lodepng_encode_memory(image, w as u32, h as u32, colortype, bitdepth)?)
959 }
960 
961 /// Same as `encode_memory`, but always encodes from 32-bit RGBA raw image
encode32<PixelType: Copy + 'static>(image: &[PixelType], w: usize, h: usize) -> Result<Vec<u8>, Error>962 pub fn encode32<PixelType: Copy + 'static>(image: &[PixelType], w: usize, h: usize) -> Result<Vec<u8>, Error> {
963     encode_memory(image, w, h, ColorType::RGBA, 8)
964 }
965 
966 /// Same as `encode_memory`, but always encodes from 24-bit RGB raw image
encode24<PixelType: Copy + 'static>(image: &[PixelType], w: usize, h: usize) -> Result<Vec<u8>, Error>967 pub fn encode24<PixelType: Copy + 'static>(image: &[PixelType], w: usize, h: usize) -> Result<Vec<u8>, Error> {
968     encode_memory(image, w, h, ColorType::RGB, 8)
969 }
970 
971 /// Converts raw pixel data into a PNG file on disk.
972 /// Same as the other encode functions, but instead takes a file path as output.
973 ///
974 /// NOTE: This overwrites existing files without warning!
encode_file<PixelType: Copy + 'static, P: AsRef<Path>>(filepath: P, image: &[PixelType], w: usize, h: usize, colortype: ColorType, bitdepth: c_uint) -> Result<(), Error>975 pub fn encode_file<PixelType: Copy + 'static, P: AsRef<Path>>(filepath: P, image: &[PixelType], w: usize, h: usize, colortype: ColorType, bitdepth: c_uint) -> Result<(), Error> {
976     let encoded = encode_memory(image, w, h, colortype, bitdepth)?;
977     save_file(filepath, encoded.as_ref())
978 }
979 
980 /// Same as `encode_file`, but always encodes from 32-bit RGBA raw image
encode32_file<PixelType: Copy + 'static, P: AsRef<Path>>(filepath: P, image: &[PixelType], w: usize, h: usize) -> Result<(), Error>981 pub fn encode32_file<PixelType: Copy + 'static, P: AsRef<Path>>(filepath: P, image: &[PixelType], w: usize, h: usize) -> Result<(), Error> {
982     encode_file(filepath, image, w, h, ColorType::RGBA, 8)
983 }
984 
985 /// Same as `encode_file`, but always encodes from 24-bit RGB raw image
encode24_file<PixelType: Copy + 'static, P: AsRef<Path>>(filepath: P, image: &[PixelType], w: usize, h: usize) -> Result<(), Error>986 pub fn encode24_file<PixelType: Copy + 'static, P: AsRef<Path>>(filepath: P, image: &[PixelType], w: usize, h: usize) -> Result<(), Error> {
987     encode_file(filepath, image, w, h, ColorType::RGB, 8)
988 }
989 
990 /// Automatically chooses color type that gives smallest amount of bits in the
991 /// output image, e.g. grey if there are only greyscale pixels, palette if there
992 /// are less than 256 colors, ...
993 ///
994 /// The auto_convert parameter is not supported any more.
995 ///
996 /// updates values of mode with a potentially smaller color model. mode_out should
997 /// contain the user chosen color model, but will be overwritten with the new chosen one.
998 #[doc(hidden)]
999 #[deprecated]
auto_choose_color(mode_out: &mut ColorMode, image: &[u8], w: usize, h: usize, mode_in: &ColorMode) -> Result<(), Error>1000 pub fn auto_choose_color(mode_out: &mut ColorMode, image: &[u8], w: usize, h: usize, mode_in: &ColorMode) -> Result<(), Error> {
1001     *mode_out = rustimpl::auto_choose_color(image, w, h, mode_in)?;
1002     Ok(())
1003 }
1004 
1005 impl<'a> ChunkRef<'a> {
new(data: &'a [u8]) -> Self1006     pub(crate) fn new(data: &'a [u8]) -> Self {
1007         Self {data}
1008     }
1009 
len(&self) -> usize1010     pub fn len(&self) -> usize {
1011         rustimpl::lodepng_chunk_length(self.data)
1012     }
1013 
name(&self) -> [u8; 4]1014     pub fn name(&self) -> [u8; 4] {
1015         let mut tmp = [0; 4];
1016         tmp.copy_from_slice(rustimpl::lodepng_chunk_type(self.data));
1017         tmp
1018     }
1019 
is_type<C: AsRef<[u8]>>(&self, name: C) -> bool1020     pub fn is_type<C: AsRef<[u8]>>(&self, name: C) -> bool {
1021         rustimpl::lodepng_chunk_type(self.data) == name.as_ref()
1022     }
1023 
is_ancillary(&self) -> bool1024     pub fn is_ancillary(&self) -> bool {
1025         rustimpl::lodepng_chunk_ancillary(self.data)
1026     }
1027 
is_private(&self) -> bool1028     pub fn is_private(&self) -> bool {
1029         rustimpl::lodepng_chunk_private(self.data)
1030     }
1031 
is_safe_to_copy(&self) -> bool1032     pub fn is_safe_to_copy(&self) -> bool {
1033         rustimpl::lodepng_chunk_safetocopy(self.data)
1034     }
1035 
data(&self) -> &[u8]1036     pub fn data(&self) -> &[u8] {
1037         rustimpl::lodepng_chunk_data(self.data).unwrap()
1038     }
1039 
check_crc(&self) -> bool1040     pub fn check_crc(&self) -> bool {
1041         rustimpl::lodepng_chunk_check_crc(&*self.data)
1042     }
1043 }
1044 
1045 pub struct ChunkRefMut<'a> {
1046     data: &'a mut [u8],
1047 }
1048 
1049 impl<'a> ChunkRefMut<'a> {
data_mut(&mut self) -> &mut [u8]1050     pub fn data_mut(&mut self) -> &mut [u8] {
1051         rustimpl::lodepng_chunk_data_mut(self.data).unwrap()
1052     }
1053 
generate_crc(&mut self)1054     pub fn generate_crc(&mut self) {
1055         rustimpl::lodepng_chunk_generate_crc(self.data)
1056     }
1057 }
1058 
1059 /// Compresses data with Zlib.
1060 /// Zlib adds a small header and trailer around the deflate data.
1061 /// The data is output in the format of the zlib specification.
1062 #[doc(hidden)]
zlib_compress(input: &[u8], settings: &CompressSettings) -> Result<Vec<u8>, Error>1063 pub fn zlib_compress(input: &[u8], settings: &CompressSettings) -> Result<Vec<u8>, Error> {
1064     let mut v = Vec::new();
1065     rustimpl::lodepng_zlib_compress(&mut v, input, settings)?;
1066     Ok(v)
1067 }
1068 
zlib_decompress(input: &[u8], settings: &DecompressSettings) -> Result<Vec<u8>, Error>1069 fn zlib_decompress(input: &[u8], settings: &DecompressSettings) -> Result<Vec<u8>, Error> {
1070     Ok(rustimpl::lodepng_zlib_decompress(input, settings)?)
1071 }
1072 
1073 /// Compress a buffer with deflate. See RFC 1951.
1074 #[doc(hidden)]
deflate(input: &[u8], settings: &CompressSettings) -> Result<Vec<u8>, Error>1075 pub fn deflate(input: &[u8], settings: &CompressSettings) -> Result<Vec<u8>, Error> {
1076     Ok(rustimpl::lodepng_deflatev(input, settings)?)
1077 }
1078 
1079 impl CompressSettings {
1080     /// Default compression settings
new() -> CompressSettings1081     pub fn new() -> CompressSettings {
1082         Self::default()
1083     }
1084 }
1085 
1086 impl Default for CompressSettings {
default() -> Self1087     fn default() -> Self {
1088         Self {
1089             btype: 2,
1090             use_lz77: 1,
1091             windowsize: DEFAULT_WINDOWSIZE as u32,
1092             minmatch: 3,
1093             nicematch: 128,
1094             lazymatching: 1,
1095             custom_zlib: None,
1096             custom_deflate: None,
1097             custom_context: ptr::null_mut(),
1098         }
1099     }
1100 }
1101 
1102 impl DecompressSettings {
new() -> Self1103     pub fn new() -> Self {
1104         Self::default()
1105     }
1106 }
1107 
1108 impl Default for DecompressSettings {
default() -> Self1109     fn default() -> Self {
1110         Self {
1111             ignore_adler32: 0,
1112             custom_zlib: None,
1113             custom_inflate: None,
1114             custom_context: ptr::null_mut(),
1115         }
1116     }
1117 }
1118 
1119 impl DecoderSettings {
new() -> Self1120     pub fn new() -> Self {
1121         Self::default()
1122     }
1123 }
1124 
1125 impl Default for DecoderSettings {
default() -> Self1126     fn default() -> Self {
1127         Self {
1128             color_convert: 1,
1129             read_text_chunks: 1,
1130             remember_unknown_chunks: 0,
1131             ignore_crc: 0,
1132             zlibsettings: DecompressSettings::new(),
1133         }
1134     }
1135 }
1136 
1137 impl EncoderSettings {
new() -> Self1138     pub fn new() -> Self {
1139         Self::default()
1140     }
1141 }
1142 
1143 impl Default for EncoderSettings {
default() -> Self1144     fn default() -> Self {
1145         Self {
1146             zlibsettings: CompressSettings::new(),
1147             filter_palette_zero: 1,
1148             filter_strategy: FilterStrategy::MINSUM,
1149             auto_convert: 1,
1150             force_palette: 0,
1151             predefined_filters: ptr::null_mut(),
1152             add_id: 0,
1153             text_compression: 1,
1154         }
1155     }
1156 }
1157 
1158 #[cfg(test)]
1159 mod test {
1160     use std::mem;
1161     use super::*;
1162 
1163     #[test]
pixel_sizes()1164     fn pixel_sizes() {
1165         assert_eq!(4, mem::size_of::<RGBA>());
1166         assert_eq!(3, mem::size_of::<RGB<u8>>());
1167         assert_eq!(2, mem::size_of::<GreyAlpha<u8>>());
1168         assert_eq!(1, mem::size_of::<Grey<u8>>());
1169     }
1170 
1171     #[test]
create_and_destroy1()1172     fn create_and_destroy1() {
1173         DecoderSettings::new();
1174         EncoderSettings::new();
1175         CompressSettings::new();
1176     }
1177 
1178     #[test]
create_and_destroy2()1179     fn create_and_destroy2() {
1180         State::new().info_png();
1181         State::new().info_png_mut();
1182         State::new().clone().info_raw();
1183         State::new().clone().info_raw_mut();
1184     }
1185 
1186     #[test]
test_pal()1187     fn test_pal() {
1188         let mut state = State::new();
1189         state.info_raw_mut().colortype = ColorType::PALETTE;
1190         assert_eq!(state.info_raw().colortype(), ColorType::PALETTE);
1191         state.info_raw_mut().palette_add(RGBA::new(1,2,3,4)).unwrap();
1192         state.info_raw_mut().palette_add(RGBA::new(5,6,7,255)).unwrap();
1193         assert_eq!(&[RGBA{r:1u8,g:2,b:3,a:4},RGBA{r:5u8,g:6,b:7,a:255}], state.info_raw().palette());
1194         state.info_raw_mut().palette_clear();
1195         assert_eq!(0, state.info_raw().palette().len());
1196     }
1197 
1198     #[test]
chunks()1199     fn chunks() {
1200         let mut state = State::new();
1201         {
1202             let info = state.info_png_mut();
1203             for _ in info.unknown_chunks(ChunkPosition::IHDR) {
1204                 panic!("no chunks yet");
1205             }
1206 
1207             let testdata = &[1,2,3];
1208             info.create_chunk(ChunkPosition::PLTE, &[255,0,100,32], testdata).unwrap();
1209             assert_eq!(1, info.unknown_chunks(ChunkPosition::PLTE).count());
1210 
1211             info.create_chunk(ChunkPosition::IHDR, "foob", testdata).unwrap();
1212             assert_eq!(1, info.unknown_chunks(ChunkPosition::IHDR).count());
1213             info.create_chunk(ChunkPosition::IHDR, "foob", testdata).unwrap();
1214             assert_eq!(2, info.unknown_chunks(ChunkPosition::IHDR).count());
1215 
1216             for _ in info.unknown_chunks(ChunkPosition::IDAT) {}
1217             let chunk = info.unknown_chunks(ChunkPosition::IHDR).next().unwrap();
1218             assert_eq!("foob".as_bytes(), chunk.name());
1219             assert!(chunk.is_type("foob"));
1220             assert!(!chunk.is_type("foobar"));
1221             assert!(!chunk.is_type("foo"));
1222             assert!(!chunk.is_type("FOOB"));
1223             assert!(chunk.check_crc());
1224             assert_eq!(testdata, chunk.data());
1225             info.get("foob").unwrap();
1226         }
1227 
1228         let img = state.encode(&[0u32], 1, 1).unwrap();
1229         let mut dec = State::new();
1230         dec.remember_unknown_chunks(true);
1231         dec.decode(img).unwrap();
1232         let chunk = dec.info_png().unknown_chunks(ChunkPosition::IHDR).next().unwrap();
1233         assert_eq!("foob".as_bytes(), chunk.name());
1234         dec.info_png().get("foob").unwrap();
1235     }
1236 
1237     #[test]
read_icc()1238     fn read_icc() {
1239         let mut s = State::new();
1240         s.remember_unknown_chunks(true);
1241         let f = s.decode_file("tests/profile.png");
1242         f.unwrap();
1243         let icc = s.info_png().get("iCCP").unwrap();
1244         assert_eq!(275, icc.len());
1245         assert_eq!("ICC Pro".as_bytes(), &icc.data()[0..7]);
1246 
1247         let data = s.get_icc().unwrap();
1248         assert_eq!("appl".as_bytes(), &data[4..8]);
1249     }
1250 }
1251