Giter VIP home page Giter VIP logo

lodepng-rust's Introduction

Rust rewrite of LodePNG

This is a pure Rust PNG image decoder and encoder. Allows easy reading and writing of PNG files without any system dependencies.

To use the lodepng crate, add to your Cargo.toml:

[dependencies]
lodepng = "3.8"

See the API reference for details. Requires Rust 1.64 or later.

Loading image example

There are more examples in the examples/ dir.

let image = lodepng::decode32_file("in.png")?;

returns image of type lodepng::Bitmap<lodepng::RGBA<u8>> with fields .width, .height, and .buffer (the buffer is a Vec).

The RGB/RGBA pixel types are from the RGB crate, which you can import separately to use the same pixel struct throughout the program, without casting. But if you want to read the image buffer as bunch of raw bytes, ignoring the RGB(A) pixel structure, use:

[dependencies]
rgb = "0.8"
use rgb::*;let bytes: &[u8] = image.buffer.as_bytes();

Saving image example

lodepng::encode32_file("out.png", &buffer, width, height)?

The RGBA buffer can be a slice of any type, as long as it has 4 bytes per element (e.g. struct RGBA or [u8; 4]) and implements the Pod trait.

Advanced

let mut state = lodepng::Decoder::new();
state.remember_unknown_chunks(true);

match state.decode_file("in.png") {
    Ok(lodepng::Image::RGB(image)) => {}
    Ok(lodepng::Image::RGBA(image)) => {}
    Ok(lodepng::Image::RGBA16(image)) => {}
    Ok(lodepng::Image::Grey(image)) => {}
    Ok(_) => {}
    Err(err) => {}
}

for chunk in state.info_png().unknown_chunks(ChunkPosition::IHDR) {
    println!("{:?} = {:?}", chunk.name(), chunk.data());
}

// Color profile (to be used with e.g. LCMS2)
let icc_data = state.get_icc();

See load_image crate for an example how to use lodepng with color profiles.

Upgrading from 2.x

  • C FFI still exists, but is no longer ABI-compatible with the original C lodepng due to layout changes in structs.
  • Structs use bool where appropriate instead of 0/1 int.
  • Custom zlib callbacks use io::Write instead of malloc-ed buffers (remember to use write_all, not write!)
  • ffi::Error has been renamed to ffi::ErrorCode.
  • Compression level is set via set_level() function instead of individual CompressConfig fields.

Upgrading from 1.x

  • CVec has been replaced with a regular Vec. Delete extra .as_ref() that the compiler may complain about.
  • LCT_* constants have been changed to ColorType::*.
  • Chunk/Chunks renamed to ChunkRef/ChunksIter.
  • auto_convert is a boolean.
  • bitdepth has a getter/setter.
  • There is no C any more!

It's a ship of Theseus

This codebase has been derived from the C LodePNG by Lode Vandevenne. It has been converted to Rust using Citrus C to Rust converter, and then significanlty refactored to be more idiomatic Rust. As a result, it's now a different library, with some of the original API.

lodepng-rust's People

Contributors

alyoshavasilieva avatar caspark avatar dependabot-preview[bot] avatar dependabot-support avatar durka avatar eddyb avatar ideasman42 avatar kornelski avatar lseelenbinder avatar madewithlinux avatar markoflark avatar nmattia avatar nukep avatar petevine avatar porglezomp avatar rex4539 avatar ruuda avatar shnatsel avatar sssooonnnggg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

lodepng-rust's Issues

Memory leak on malformed input

lodepng-rust leaks memory when given malicious input. This issue has been discovered via fuzzing with cargo-fuzz.

Steps to reproduce:

git clone https://github.com/Shnatsel/lodepng-leak.git
cd lodepng-leak
RUSTFLAGS='--cfg fuzzing' cargo run

PNG and deflate checksums make fuzzing impossible, so I have modified lodepng-fuzz to disable checksum verification during fuzzing via conditional compilation. lodepng-leak repo currently links against my modified version, which can be found here along with the fuzzing setup. The code right now is rather messy, but it would be nice to get something similar in your repo as well.

Index out of bounds when windowsize set to 32768

I was trying to recreate the example_optimize_png in rust from the lodepng lib, but when setting my windowsize to 32768 on the encoders zlibsettings it panics with an index out of bounds error.

rustc 1.34.0 (91856ed52 2019-04-10)
macos 10.14.4

thread 'main' panicked at 'index out of bounds: the len is 30 but the index is 30'

stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:39
   1: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:70
   2: std::panicking::default_hook::{{closure}}
             at src/libstd/sys_common/backtrace.rs:58
             at src/libstd/panicking.rs:200
   3: std::panicking::default_hook
             at src/libstd/panicking.rs:215
   4: <std::panicking::begin_panic::PanicPayload<A> as core::panic::BoxMeUp>::get
             at src/libstd/panicking.rs:478
   5: std::panicking::continue_panic_fmt
             at src/libstd/panicking.rs:385
   6: std::panicking::try::do_call
             at src/libstd/panicking.rs:312
   7: <T as core::any::Any>::type_id
             at src/libcore/panicking.rs:85
   8: <T as core::any::Any>::type_id
             at src/libcore/panicking.rs:61
   9: lodepng::rustimpl::search_code_index
             at /.../lodepng-2.4.2/src/rustimpl.rs:2105
  10: lodepng::rustimpl::add_length_distance
             at /.../lodepng-2.4.2/src/rustimpl.rs:2121
  11: lodepng::rustimpl::encode_lz77
             at /.../lodepng-2.4.2/src/rustimpl.rs:3819
  12: lodepng::rustimpl::deflate_dynamic
             at /.../lodepng-2.4.2/src/rustimpl.rs:2278
  13: lodepng::rustimpl::lodepng_deflatev
             at /.../lodepng-2.4.2/src/rustimpl.rs:2521
  14: lodepng::rustimpl::deflate
             at /.../lodepng-2.4.2/src/rustimpl.rs:2536
  15: lodepng::rustimpl::lodepng_zlib_compress
             at /.../lodepng-2.4.2/src/rustimpl.rs:2628
  16: lodepng::rustimpl::zlib_compress
             at /.../lodepng-2.4.2/src/rustimpl.rs:2646
  17: lodepng::rustimpl::add_chunk_idat
             at /.../lodepng-2.4.2/src/rustimpl.rs:1321
  18: lodepng::rustimpl::add_unknown_chunks
             at /.../lodepng-2.4.2/src/rustimpl.rs:3350
  19: lodepng::<impl lodepng::ffi::State>::encode
             at /.../lodepng-2.4.2/src/lib.rs:729
  20: lodepng::<impl lodepng::ffi::State>::encode_file
             at /.../lodepng-2.4.2/src/lib.rs:733
  21: kompres::main
             at src/main.rs:64
  22: std::rt::lang_start::{{closure}}
             at /rustc/.../src/libstd/rt.rs:64
  23: std::panicking::try::do_call
             at src/libstd/rt.rs:49
             at src/libstd/panicking.rs:297
  24: panic_unwind::dwarf::eh::read_encoded_pointer
             at src/libpanic_unwind/lib.rs:87
  25: <std::panicking::begin_panic::PanicPayload<A> as core::panic::BoxMeUp>::get
             at src/libstd/panicking.rs:276
             at src/libstd/panic.rs:388
             at src/libstd/rt.rs:48
  26: std::rt::lang_start
             at /rustc/../src/libstd/rt.rs:64
  27: png_compress::main

Problems reading 16-bit PNG?

I'm trying to read a 16-bit PNG file and print out the RGB values in the first pixel. They consistently differ from the output of Matlab or an image viewer. I cannot figure out why... If I open the image in Rust, then save it to a new file, and then open that file in Matlab or an image viewer, the resulting values are as expected, so I am not sure what is going on here.

For example, Rust gives the following:

RGB { r: 20877, g: 42635, b: 33940 }

whereas Matlab gives this:

[36177, 35750, 38020]

Matlab is also correct, whereas Rust is wrong.

I ran this Rust code:

extern crate lodepng;

use std::path::Path;

fn main() {
    let fin = std::env::args().nth(1).unwrap();
    let img = lodepng::decode_file(&Path::new(&fin), lodepng::LCT_RGB, 16).unwrap();

    let bitmap = match img {
        lodepng::Image::RGB16(ref bitmap) => bitmap,
        _ => panic!("??"),
    };
    let (w, h) = (bitmap.width, bitmap.height);
    let bitmapbuf = bitmap.buffer.as_ref();

    let p = bitmapbuf.iter().nth(0).unwrap();

    println!("{:?}", p);
}

Best,
Rob

Custom zlib hook seems to leak memory

Given the following code

fn encode(){
//....
    lode.encoder.zlibsettings.custom_zlib = Some(zlib_compress_adapter);
}

extern "C" {
    /// zlib
    fn compress2(dest: *mut u8, dest_len: &mut c_ulong, source: *const u8, source_len: c_ulong, level: c_int) -> c_int;
}

unsafe extern "C" fn zlib_compress_adapter(dest: &mut *mut u8, dest_size: &mut usize, source: *const u8, source_size: usize, info: *const lodepng::CompressSettings) -> c_uint {
    assert!(dest.is_null());
    let dest_buf_size = source_size * 1001/1000 + 12;
    *dest = libc::malloc(dest_buf_size) as *mut u8;
    let mut compressed_size = dest_buf_size as c_ulong;
    compress2(*dest, &mut compressed_size, source, source_size as c_ulong, 6);
    *dest_size = compressed_size as usize;
    0
}

Valgrind reports that the memory allocated by libc::malloc is never freed.

Is lodepng supposed to be freeing the memory behind the dest pointer?

Links to libc in Documentation

links in the documentation to libc end up in a 404 page.

This is not a major problem but is quite irritating when browsing or looking something up, as I am quite new to rust.

Is there a reason not to have them?

How do I convert CVec<Rgba<u8>> into a CVec<u8>?

The docs mention using mem::transmute, but I can't figure it out. 😞

Additionally, the README says:

and the buffer has .as_bytes() method if you need a plain [u8]

but nothing like that method seems to exist on anything except the RGBA type itself.

Alternatively is there some way I can get a CVec<u8> out of lodepng::decode32?

Decoding and Re-encoding PNG shifts colors

Summary

Firstly, I assume this is either an upstream issue with the original lodepng or I am doing something really stupid 😅

I was trying to decode some MacOS screenshot png files but I am noticing a colour shift in the decoded pixel data.

Is there some flag I need to set or colour channel I need to detect first before decoding (or when encoding)?

Original PNG Re-Encoded PNG
test2 test2

Test Code

Mostly taken from your lovely examples 😁

let path = &Path::new("write_test.png");

// test.png being the original PNG in https://github.com/kornelski/lodepng-rust/issues/52
match lodepng::decode32_file("test.png") {
    Ok(image) => {
        if let Err(e) = lodepng::encode_file(path, &image.buffer, image.width, image.height, lodepng::ColorType::RGBA, 8) {
            panic!("failed to write png: {:?}", e);
        }

        println!("Written to {}", path.display());
    },
    Err(reason) => println!("Could not load, because: {}", reason),
}

Unable to build on wasm32-unknown-unknown due to libc malloc

Creating a project with lodepng as a dependency and building with --target wasm32-unknown-unknown yields the following errors:

   Compiling lodepng v2.5.0
error[E0425]: cannot find function `malloc` in crate `libc`
  --> /home/carado/.cargo/registry/src/github.com-1ecc6299db9ec823/lodepng-2.5.0/src/rustimpl.rs:53:15
   |
53 |         libc::malloc(size) as *mut _
   |               ^^^^^^ not found in `libc`

error[E0425]: cannot find function `realloc` in crate `libc`
  --> /home/carado/.cargo/registry/src/github.com-1ecc6299db9ec823/lodepng-2.5.0/src/rustimpl.rs:58:11
   |
58 |     libc::realloc(ptr as *mut _, size) as *mut _
   |           ^^^^^^^ not found in `libc`
   |
help: possible candidate is found in another module, you can import it into scope
   |
16 | use std::alloc::realloc;
   |

error[E0425]: cannot find function `free` in crate `libc`
  --> /home/carado/.cargo/registry/src/github.com-1ecc6299db9ec823/lodepng-2.5.0/src/rustimpl.rs:62:11
   |
62 |     libc::free(ptr as *mut _)
   |           ^^^^ not found in `libc`

error[E0425]: cannot find function `free` in crate `libc`
   --> /home/carado/.cargo/registry/src/github.com-1ecc6299db9ec823/lodepng-2.5.0/src/lib.rs:818:11
    |
818 |     libc::free(ptr as *mut _);
    |           ^^^^ not found in `libc`

error: aborting due to 4 previous errors

Is using the system's malloc and free really necessary ?

Using any (impl Copy) type as pixel buffer is unspecified behaviour

The encoder API encourages to use "any type as long as it has 4 bytes per element", and does fn buffer_for_type(){ ... unsafe { pointer cast }}. It has the following problem

  • Casting the pointer to a different type and then deference it is probably undefined behaviour. I haven't verified this yet.
  • even if this is defined behaviour, it is still unspecified: rust doesn't guarantee any layout on struct or tuple (unless you decorate it with #[repr()] ). In other words, when the user supply a buffer with [(R, G, B, A)] type, the compiler can freely reorder the members and gives unexpected [(G, R, B, A)] layout.

Better examples

I can see that you link to the original .h, but if you want a reason for me to pick your library over some other library, you need to make it easy for me to get started using it. At least add examples for doing basic things like writing images, and doing things with loaded images.

Fuzz for memory disclosure vulnerabilities

The current fuzzing harness allows detecting out of bounds memory access as well as panics and any kind of crashes. It will not detect memory disclosure vulnerabilities, which can be devastating in image libraries (example).

I have dissected such a vulnerability in DEFLATE decoder used in png crate in my recent Reddit post and outlined the ways it could be discovered via fuzzing. Sadly I do not have the time to set it up such a fuzzing harness for lodepng myself.

3.7.0 -> 3.7.1 breaks my build

here's my Cargo.lock diff:

diff --git a/Cargo.lock b/Cargo.lock
index ec6941a17..1c940f84b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4157,12 +4157,11 @@ dependencies = [

 [[package]]
 name = "lodepng"
-version = "3.7.0"
+version = "3.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff45534ec797452c044fcd47861059eddb501e30a8fd9fdadea7957cdff3ebc7"
+checksum = "aa4b80e174ce53624cd2b764aa4fcb8fd1ce78f1f17a6d85a3fcada4328acfe8"
 dependencies = [
  "crc32fast",
- "fallible_collections",
  "flate2",
  "libc",
  "rgb",

here's the error:

error[E0277]: `?` couldn't convert the error to `lodepng::Error`
  --> C:\Users\GRD-User\.cargo\registry\src\github.com-1ecc6299db9ec823\load_image-2.16.4\src\loader.rs:62:79
   |
62 |             fallible_collections::FallibleVec::try_reserve(&mut data, 1 << 16)?; // arbitrary, better than 0
   |                                                                               ^ the trait `From<fallible_collections::TryReserveError>` is not implemented for `lodepng::Error`
   |
   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
   = help: the following other types implement trait `From<T>`:
             <lodepng::Error as From<std::collections::TryReserveError>>
             <lodepng::Error as From<std::io::Error>>
   = note: required for `Result<image::Image, lodepng::Error>` to implement `FromResidual<Result<Infallible, fallible_collections::TryReserveError>>`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `load_image` due to previous error
warning: build failed, waiting for other jobs to finish...

Can't encode bitdepth lower than 8?

Unless I've missed something, it seems that attempts to encode an image of 1/2/4-bitdepth will fail.
buffer_for_type checks the data size as such:

let bytes_per_pixel = bitdepth as usize/8;
assert!(mem::size_of::<PixelType>() <= 4*bytes_per_pixel, "Implausibly large {}-byte pixel data type", mem::size_of::<PixelType>());

For an input bitdepth of less than 8, bytes_per_pixel will be 0, and then the assert cannot possibly pass unless PixelType is somehow a zero-size type.

Speed and binary size of this library?

Hi thanks for this wonderful lib! I wonder (1) how fast is it, and (2) how big is the generated binary executable, compared with traditional libpng? Thank you!

build fails due to mismatched types

error[E0308]: mismatched types
   --> C:\Users\Mus\.cargo\registry\src\github.com-1ecc6299db9ec823\lodepng-2.1.4\src\ffi.rs:388:47
    |
388 |     lode_error!(rustimpl::lodepng_encode_file(c_path(filename), slice::from_raw_parts(image, 0x1FFFFFFF), w, h, colortype, bitdepth))
    |                                               ^^^^^^^^^^^^^^^^
    |                                               |
    |                                               expected reference, found struct `std::path::PathBuf`
    |                                               help: consider borrowing here: `&c_path(filename)`
    |
    = note: expected type `&std::path::Path`
               found type `std::path::PathBuf`

error[E0308]: mismatched types
   --> C:\Users\Mus\.cargo\registry\src\github.com-1ecc6299db9ec823\lodepng-2.1.4\src\ffi.rs:393:47
    |
393 |     lode_error!(rustimpl::lodepng_encode_file(c_path(filename), slice::from_raw_parts(image, 0x1FFFFFFF), w, h, ColorType::RGBA, 8))
    |                                               ^^^^^^^^^^^^^^^^
    |                                               |
    |                                               expected reference, found struct `std::path::PathBuf`
    |                                               help: consider borrowing here: `&c_path(filename)`
    |
    = note: expected type `&std::path::Path`
               found type `std::path::PathBuf`

error[E0308]: mismatched types
   --> C:\Users\Mus\.cargo\registry\src\github.com-1ecc6299db9ec823\lodepng-2.1.4\src\ffi.rs:398:47
    |
398 |     lode_error!(rustimpl::lodepng_encode_file(c_path(filename), slice::from_raw_parts(image, 0x1FFFFFFF), w, h, ColorType::RGB, 8))
    |                                               ^^^^^^^^^^^^^^^^
    |                                               |
    |                                               expected reference, found struct `std::path::PathBuf`
    |                                               help: consider borrowing here: `&c_path(filename)`
    |
    = note: expected type `&std::path::Path`
               found type `std::path::PathBuf`

error[E0308]: mismatched types
   --> C:\Users\Mus\.cargo\registry\src\github.com-1ecc6299db9ec823\lodepng-2.1.4\src\ffi.rs:388:47
    |
388 |     lode_error!(rustimpl::lodepng_encode_file(c_path(filename), slice::from_raw_parts(image, 0x1FFFFFFF), w, h, colortype, bitdepth))
    |                                               ^^^^^^^^^^^^^^^^
    |                                               |
    |                                               expected reference, found struct `std::path::PathBuf`
    |                                               help: consider borrowing here: `&c_path(filename)`
    |
    = note: expected type `&std::path::Path`
               found type `std::path::PathBuf`

error[E0308]: mismatched types
   --> C:\Users\Mus\.cargo\registry\src\github.com-1ecc6299db9ec823\lodepng-2.1.4\src\ffi.rs:393:47
    |
393 |     lode_error!(rustimpl::lodepng_encode_file(c_path(filename), slice::from_raw_parts(image, 0x1FFFFFFF), w, h, ColorType::RGBA, 8))
    |                                               ^^^^^^^^^^^^^^^^
    |                                               |
    |                                               expected reference, found struct `std::path::PathBuf`
    |                                               help: consider borrowing here: `&c_path(filename)`
    |
    = note: expected type `&std::path::Path`
               found type `std::path::PathBuf`

error[E0308]: mismatched types
   --> C:\Users\Mus\.cargo\registry\src\github.com-1ecc6299db9ec823\lodepng-2.1.4\src\ffi.rs:398:47
    |
398 |     lode_error!(rustimpl::lodepng_encode_file(c_path(filename), slice::from_raw_parts(image, 0x1FFFFFFF), w, h, ColorType::RGB, 8))
    |                                               ^^^^^^^^^^^^^^^^
    |                                               |
    |                                               expected reference, found struct `std::path::PathBuf`
    |                                               help: consider borrowing here: `&c_path(filename)`
    |
    = note: expected type `&std::path::Path`
               found type `std::path::PathBuf`

error[E0308]: mismatched types
   --> C:\Users\Mus\.cargo\registry\src\github.com-1ecc6299db9ec823\lodepng-2.1.4\src\ffi.rs:732:61
    |
732 |     let (v, w, h) = lode_try!(rustimpl::lodepng_decode_file(c_path(filename), colortype, bitdepth));
   Compiling kernel32-sys v    0.2.2
|                                                             ^^^^^^^^^^^^^^^^
    |                                                             |
    |                                                             expected reference, found struct `std::path::PathBuf`
    |                                                             help: consider borrowing here: `&c_path(filename)`
    |
    = note: expected type `&std::path::Path`

rustc 1.24.1 (d3ae9a9e0 2018-02-27)
stable-x86_64-pc-windows-msvc (default)

CSlice seems to be horribly unsafe?

Pretty sure that CSlice leads to a use-after-free in entirely safe code. It should be bound to the lifetime of the CVec, but honestly I'm not sure why it exists when CVec::as_ref exists.

fn use_after_free() {
    // Calls to as_ref are just for formatting purposes.
    let x = make_a_vec();
    let y = x.as_cslice();
    println!("{:?}", x.as_ref());
    println!("{:?}", y.as_ref());
    drop(x);
    println!("{:?}", y.as_ref());

    fn make_a_vec() -> CVec<u8> {
        unsafe {
            let mut vec = vec![0, 1, 2].into_boxed_slice();
            let start = vec.as_mut_ptr();
            let raw = Box::into_raw(vec);

            CVec::new_with_dtor(
                start,
                3,
                move |_| {
                    println!("FREED.");
                    drop(Box::from_raw(start))
                }
            )
        }
    }
}

Build Dependencies not documented

When trying to build this on a minimal environment, it fails without a C compiler or make.

While this may seem obvious, the error message when it fails to build is:

--- stderr
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 2, message: "No such file or directory" } }', src/libcore/result.rs:788

Reporting this because the error message didn't make it very clear what the cause of the problem was.

Probably the build script should check that make command can run before unwrapping?
Or at least include GCC/Clang and GMake as build dependencies.

3.1.0 broke semver

Commit d18dde7 changed the return type of Info::text_keys_cstr() to something different than before without bumping the major version number, breaking builds and interfering with debugging for some users SpaiR/StrongDMM#63 (comment).

Example code:

    for (key, value) in decoder.info_png().text_keys_cstr() {
        if key.to_str() == Ok("Description") {
            if let Ok(value) = value.to_str() {
                return Ok(value.to_owned());
            }
        }
    }

I can work around this on my end but it caused problems for me so I wanted to complain about it.

Wrong encoding of text keys

Problem: png's encoded by lodepng seem to lack text_keys, as seen by the png crate and a certain non-rust closed-source application that i care about.
Given png's very strongly worded claims of standard compliance (and that png-produced images are recognized by the aforementioned non-rust application, whereas the lodepng ones are not), i assume the fault lies with lodepng.
Sadly i have not delved deep enough into the standard to provide any more specifics.

Code demonstrating the issue:
extern crate lodepng;
extern crate png;

fn main() {
    let image = vec![255u8, 0, 0, 255]; // single red pixel
    let mut encoder = lodepng::Encoder::new();
    encoder.info_png_mut().add_text("hello", "world").unwrap();
    let encoded_image = encoder.encode(&image, 1, 1).unwrap();

    // parse it back
    {
        println!("\n -- lodepng view of the metadata:");
        let mut decoder = lodepng::Decoder::new();
        let decoded = decoder.decode(&encoded_image).unwrap();
        // displays keys properly
        println!("the following text keys are present:");
        for (k, v) in decoder.info_png().text_keys() {
            println!(
                "{:?} - {:?}",
                std::str::from_utf8(k),
                std::str::from_utf8(v),
            )
        }
    }

    {
        println!("\n -- png view of the metadata:");
        let decoder = png::Decoder::new(encoded_image.as_slice());
        let mut r = decoder.read_info().unwrap();
        println!("{:?}", r.info());
        // displays nothing
        println!(
            " compressed text: {:?}\n uncompressed text: {:?}",
            r.info().compressed_latin1_text,
            r.info().uncompressed_latin1_text
        );
    }
}

Output:

 -- lodepng view of the metadata:
the following text keys are present:
Ok("hello") - Ok("world")

 -- png view of the metadata:
Info { width: 1, height: 1, bit_depth: Eight, color_type: Rgb, interlaced: false, trns: None, pixel_dims: None, palette: None, gama_chunk: None, chrm_chunk: None, frame_control: None, animation_control: None, compression: Fast, source_gamma: None, source_chromaticities: None, srgb: None, icc_profile: None, uncompressed_latin1_text: [], compressed_latin1_text: [], utf8_text: [] }
 compressed text: []
 uncompressed text: []

Build fails, due to wrong number of arguments given to debug_assert_eq

/home/me/.multirust/toolchains/stable/cargo/registry/src/github.com-1ecc6299db9ec823/lodepng-0.12.3/src/lib.rs:603:53: 603:54 error: no rules expected the token `,`
/home/me/.multirust/toolchains/stable/cargo/registry/src/github.com-1ecc6299db9ec823/lodepng-0.12.3/src/lib.rs:603         debug_assert_eq!(image_bytes, required_bytes, "Image is {} bytes large ({}x{}x{}), but needs to be {} ({:?}, {})",
                                                                                                                                                                       ^
Build failed, waiting for other jobs to finish...
error: Could not compile `lodepng`.

Should be just two arguments.

Support decoding into preallocated memory

This is useful for skipping a potentially large copy when e.g. uploading texture data to a GPU, by decoding directly into a driver-allocated staging buffer or mapped memory. It would make sense for higher-level, more magical owned-memory decoders to be defined in terms of such a primitive. Compare the png crate's next_frame method.

Licensing question

On GitHub it says that this code is licensed under the "zlib" license, but in Cargo.toml the "BSD-3-Clause" license is defined.

Which one is correct?

lodepng is 20x slower than the png crate

I've been using lodepng to generate some schematic images for a project, and when I generate larger PNGs (2k x 1.5k), lodepng in release mode is taking over 1s to generate the png (or over a minute when compiled in debug mode!). In comparison, the png crate takes 50ms to encode the same image:

$ cargo run --release
   Compiling rustpng v0.1.0 (file:///Users/josephg/src/r/rustpng)
    Finished release [optimized] target(s) in 1.76s
     Running `target/release/rustpng`
encoded data. Generating png
lodepng generated a 95817 byte PNG in 1.103346s
png generated a 61206 byte PNG in 43.949ms
Wrote "./foo.png" at size 2048 x 1568

(The resulting images look the same despite the size difference. pngcrush brings either image down to 20k).

The code is a bit of a mess - I haven't completely isolated the benchmark. But you can run it yourself here: https://github.com/josephg/bp-to-png/tree/a9fd048a67961b35e88308b907143fdacb1f6870

Tests fail on 32 bit linux

Tests are failing on debian 32 bit using Rust 1.7

From what I can tell the issue seems to crop up when calling into C.

16 bit grayscale png wrong byte endianness

Hi!

I was loading a 16bit integer grayscale image, and I got very confusing results, so I debugged for a good few hours and found that the byte array is correct, but it decodes it as Least Significant Byte first, when it should be Most Significant Byte first.

Of course I can decode from the bytes for myself correctly, but I hope this can get fixed, so others don't bump into the same issue. Or at least they find this issue, and can spend less time wondering what's the problem :)

Thanks

Memory leaks

Hi,

I'm not sure that this is really a problem, but maybe you'll want to investigate further and user cargo-fuzz to fuzz your crate. :)

cargo-fuzz output:
Fresh rgb v0.5.5 Fresh libc v0.2.21 Fresh gcc v0.3.43 Fresh c_vec v1.2.0 Fresh lodepng v0.13.2 (file:///home/ner0x652/Comp/GitHub/lodepng-rust) Fresh libfuzzer-sys v0.1.0 (https://github.com/rust-fuzz/libfuzzer-sys.git#9d00b47e) Fresh lodepng-fuzz v0.0.1 (file:///home/ner0x652/Comp/GitHub/lodepng-rust/fuzz) Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs Runningtarget/x86_64-unknown-linux-gnu/debug/lodepng -artifact_prefix=artifacts/ corpusINFO: Seed: 2476720331 INFO: Loaded 0 modules (0 guards): Loading corpus dir: corpus INFO: -max_len is not provided, using 64 INFO: A corpus is not provided, starting from an empty corpus #0 READ units: 1 thread '<unnamed>' panicked at 'assertion failed:(left == right)(left:1, right: 0): Image is 1 bytes large (0x0x1), but needs to be 0 (LCT_RGBA, 10)', /home/ner0x652/Comp/GitHub/lodepng-rust/src/lib.rs:610 note: Run with RUST_BACKTRACE=1` for a backtrace.
==18380== ERROR: libFuzzer: deadly signal
#0 0x7faf003f5e09 (/home/ner0x652/Comp/GitHub/lodepng-rust/fuzz/target/x86_64-unknown-linux-gnu/debug/lodepng+0x156e09)
#1 0x7faf002f1b4d (/home/ner0x652/Comp/GitHub/lodepng-rust/fuzz/target/x86_64-unknown-linux-gnu/debug/lodepng+0x52b4d)
#2 0x7faf002f1a9b (/home/ner0x652/Comp/GitHub/lodepng-rust/fuzz/target/x86_64-unknown-linux-gnu/debug/lodepng+0x52a9b)
#3 0x7faf002e71ce (/home/ner0x652/Comp/GitHub/lodepng-rust/fuzz/target/x86_64-unknown-linux-gnu/debug/lodepng+0x481ce)
#4 0x7faeff75788f (/lib/x86_64-linux-gnu/libpthread.so.0+0xf88f)
#5 0x7faeff1bc066 (/lib/x86_64-linux-gnu/libc.so.6+0x35066)
#6 0x7faeff1bd447 (/lib/x86_64-linux-gnu/libc.so.6+0x36447)
#7 0x7faf0032a4a8 (/home/ner0x652/Comp/GitHub/lodepng-rust/fuzz/target/x86_64-unknown-linux-gnu/debug/lodepng+0x8b4a8)

NOTE: libFuzzer has rudimentary signal handlers.
Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
MS: 0 ; base unit: 0000000000000000000000000000000000000000
0xa,
\x0a
artifact_prefix='artifacts/'; Test unit written to artifacts/crash-adc83b19e793491b1c6ea0fd8b46cd9f32e592fc
Base64: Cg==

=================================================================
==18380==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 3 byte(s) in 3 object(s) allocated from:
#0 0x7faf003e8fbf (/home/ner0x652/Comp/GitHub/lodepng-rust/fuzz/target/x86_64-unknown-linux-gnu/debug/lodepng+0x149fbf)
#1 0x7faf0031622c (/home/ner0x652/Comp/GitHub/lodepng-rust/fuzz/target/x86_64-unknown-linux-gnu/debug/lodepng+0x7722c)

SUMMARY: AddressSanitizer: 3 byte(s) leaked in 3 allocation(s).
MS: 0 ; base unit: 0000000000000000000000000000000000000000
0xa,
\x0a
artifact_prefix='artifacts/'; Test unit written to artifacts/crash-adc83b19e793491b1c6ea0fd8b46cd9f32e592fc
Base64: Cg==`

Started with this:
`#![no_main]
extern crate libfuzzer_sys;
extern crate lodepng;

#[export_name="rust_fuzzer_test_input"]
pub extern fn go(data: &[u8]) {
let _ = lodepng::encode_memory(data, 0, 0, lodepng::ffi::ColorType::LCT_RGBA, 10);
}`

16 bit depth images are saved using host endian

Test program that writes a 16-bit-depth RGBA image containing a gradient:

extern crate lodepng;
extern crate rgb;
use std::iter::repeat;
use rgb::RGBA;

fn main() {
	let height = 500;
	let row = (0..u16::max_value()).map(|i| RGBA{r: u16::max_value(), g: 0, b: 0, a: u16::max_value()-i}).collect::<Vec<_>>();
	let color_buffer: Vec<RGBA<u16>> = repeat(&row).take(height).flat_map(|row| row).map(|pixel| *pixel).collect::<Vec<_>>();
	let _ = lodepng::encode_file("test.png", color_buffer.as_slice(), u16::max_value() as usize, height, lodepng::ColorType::RGBA, 16);
}

This produces the following image on my x86-64 laptop, which is not a single solid gradient as expected:
several gradients
If I flip the endianness of the image, I get the correct result:

gm convert test.png -endian LSB -depth 16 RGBA:test.raw
gm convert -endian MSB -depth 16 -size 65535x500 RGBA:test.raw test-flipped.png

test-flipped

This is likely because encode_file doesn't actually use the type of the array its passed; it just converts it to a u8 array and feeds it straight into the encoder. While that seems like a good idea for making the encoder type agnostic, issues like this combined with the fact that rust doesn't guarentee that fields are stored in the order that they are specified make this a bad idea. Since you depend on the rgb crate anyway, you may as well take pixels using the rgb crate's structures.

Memory leak on decoding a malformed image

lodepng-rust leaks memory when given malicious input. This issue has been discovered via fuzzing with afl and libdiffuzz, later confirmed with address sanitizer.

Steps to reproduce:

  1. Download and unpack lodepng-repr-diff.tar.gz - this is a Rust project with Cargo
  2. cd lodepng-repr-diff
  3. cargo build --release
  4. run target/release/target/release/lodepng-afl-fuzz-differential < memory_leaking_files/id:000000,sig:06,src:000389,op:havoc,rep:2 and observe memory consumption of the process steadily increase. This should be the case for any file from memory_leaking_files/

This issue has been discovered in version 2.3.0, so it is distinct from #28

examples provided in crate lodepng fail greatly underestimate its abilities. Here's just one example.

#![allow(non_snake_case)]

use lodepng::* ;
use std::process::Command; // used to execute OS commands that calls a PNG image viewer

fn main() {

  // PNG encode a simple tri-color image

  const W: usize = 300;  const H: usize = 600;
  let mut img = [[0_u8; 4]; W*H ];

  for frame in 1..6
  { let f8 : u8 = 30*frame as u8;
    for h in 0..H
    { for w in 0..W
      {  img[h*W +w ] =
            match h/200
              {   0  => [   f8, 0_u8, 0_u8, 255_u8],
                  1  => [ 0_u8,   f8, 0_u8, 255_u8],
                  _  => [ 0_u8, 0_u8,   f8, 255_u8],
              } ;
    }  }
    //Save image:  the buffer can be a slice of any type that has 4 bytes per element e.g. struct RGBA or [u8; 4]
    let _result =encode32_file("out.png", &img, W, H) ;
    // set up  cmd that calls The OS  PNG viewer...below the Linux feh viewer is called
    // let result =
    Command:: new("feh")
        .arg("out.png")
        .status() //.output()
        .expect("failed to execute command") ;
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.