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