image-rs / image-png

PNG decoding and encoding library in pure Rust
https://docs.rs/png
Apache License 2.0
361 stars 142 forks source link

Write new image using chunks from `StreamingDecoder`? #253

Open 0x6273 opened 4 years ago

0x6273 commented 4 years ago

I'm trying to modify an image's iTXt metadata. I'm using StreamingDecoder to read the chunks from the original image, and Writer::write_chunk to create a new image with modified metadata. But the API to construct the Writer needs information such as the image dimensions and color palette, for writing the header.

StreamingDecoder seems to have all this information internally after passing the IHDR chunk, but it is in a private field with no public getter.

My current solution is to read the entire image into memory, and then use Decoder, which I can then turn into a Reader and then get the header info from Reader::info(). But I'm wondering if there is a better way to do this using only StreamDecoder, so I don't have to make two decoding passes?

HeroicKatora commented 4 years ago

When you call read_info, constructing the reader, you get an OutputInfo struct as byproduct. Is there any information missing from that struct?

0x6273 commented 4 years ago

The compression method, filter method, and interlace method are missing from OutputInfo.

HeroicKatora commented 4 years ago

In png those are per-frame and thus availabe in Reader::info. It seems the opposite is the case, the encoder doesn't offer a way to transfer that information per frame. (But then, it doesn't support apng so a single frame is all you can do anyways. See #93 which sadly stalled a bit :/).

0x6273 commented 4 years ago

For my use case, I only need the encoder to get the IHDR correct (identical to the png I'm decoding) since I'm writing everything else with Writer::write_chunk. I tested my code with an animated png and it handled it correctly (output identical to input, except for an added iTXt chunk).

My problem is that I don't want to process the png twice with both Decoder and StreamingDecoder. If there was a way to access the input field on StreamingDecoder, or a way to make the encoder not write the IHDR chunk in the first place so I could write_chunk it myself, it would solve my problem.

mainrs commented 3 years ago

I have the same use-case, writing the same image back but removing or altering already existing iTXT chunks. Did you get around using the double decoding @0x6273?

Has there been any work on this? If not, would it be (good) enough to just make the fields public inside of StreamingDecoder? I'd be happy to contribute back as I make use of the library myself @HeroicKatora :)

HeroicKatora commented 3 years ago

A getter fn (&self) -> Option<&Info> would be cleaner, I think. But sure, I'd be happy to accept a PR for that. Be sure to target the version-0.16 branch if you need a backport for it, otherwise it's going into the progress to 0.17.