Rust png/lodepng 库读取图片后立即保存图片色彩丢失,是什么原因呢?

使用 rust 的 png 库读取文件,然后不做修改地再次保存,发现跟原图不一样,为什么会产生这种问题呢?我缺少了什么步骤导致这种问题!(不仅是 png 库,image、lodepng 库同样是这样,我是否缺了什么关键步骤,请大佬们不吝赐教)

使用 js 实现读取后直接写入却不会丢失!

这是我进行尝试的 demo

fn demo() -> Result<(), String> {
    // 加载图片
    let decoder = png::Decoder::new(File::open("path/optimize/fruit.png").unwrap());
    let mut reader = decoder.read_info().unwrap();
    // Allocate the output buffer.
    let mut buf = vec![0; reader.output_buffer_size()];
    // Read the next frame. An APNG might contain multiple frames.
    let info = reader.next_frame(&mut buf).unwrap();

    // save
    let output_file = File::create("path/optimize/fruit-test.png").unwrap();
    let w = std::io::BufWriter::new(output_file);

    let mut encoder = png::Encoder::new(w, info.width, info.height);
    encoder.set_depth(info.bit_depth);
    encoder.set_color(info.color_type);

    let mut writer = encoder.write_header().unwrap();
    writer.write_image_data(&buf).unwrap();

    Ok(())
}

得到以下图片,左边是原图,右边我感觉色彩有丢失的感觉,没了左边的鲜艳

image.png

很奇怪的是,我在 js 中通过 input 标签获取图片然后保存,却没事

const handleChange = async (event: ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0] as File;
    const bitmap = await createImageBitmap(file);
    const { width, height } = bitmap;

    // 使用普通的 canvas
    const canvas2 = document.createElement("canvas");
    canvas2.width = width;
    canvas2.height = height;
    const context2 = canvas2.getContext("2d")!;
    context2.drawImage(bitmap, 0, 0, width, height);
    canvas2.toBlob((blob) => {
        const testEle = document.getElementById("test") as HTMLImageElement;
        testEle.src = URL.createObjectURL(blob as Blob);
    }, "image/png");
};
阅读 832
avatarAI BotBETA

在 Rust 代码中处理 PNG 图片并保存时色彩丢失的问题很可能是由于 png 库的 bit_depthcolor_type 设置不正确或者没有正确处理这些参数导致的。在 PNG 格式中,bit_depthcolor_type 是非常重要的,因为它们定义了像素数据的格式和颜色空间。

可能的问题和解决方案

  1. 保持 bit_depthcolor_type 一致
    在读取 PNG 图片时,你需要记录原始图片的 bit_depthcolor_type,并在写入时确保这些参数与原始图片相同。如果 bit_depthcolor_type 被错误地修改,可能会导致色彩丢失或图片质量下降。
  2. 检查颜色类型
    如果原始图片使用了带有透明度的颜色类型(如 RGBA),确保在保存时也使用了相同的颜色类型。如果错误地将 RGBA 转换为 RGB,则会丢失透明度信息,这可能会以色彩丢失的形式表现出来。
  3. 使用默认设置
    如果不确定如何设置 bit_depthcolor_type,可以尝试使用库的默认设置(如果库支持的话)。但通常最好显式地设置这些参数以确保一致性。

修改后的 Rust 代码

下面是一个修改后的 Rust 代码示例,它显式地保留了读取时的 bit_depthcolor_type

fn demo() -> Result<(), Box<dyn std::error::Error>> {
    // 加载图片
    let file = std::fs::File::open("path/to/your/fruit.png")?;
    let decoder = png::Decoder::new(file);
    let (info, mut reader) = decoder.read_png()?;

    // 读取图片数据
    let mut buf = Vec::new();
    reader.read_image_data(&mut buf)?;

    // 保存图片
    let output_file = std::fs::File::create("path/to/your/fruit-test.png")?;
    let mut encoder = png::Encoder::new(output_file, info.width, info.height);
    encoder.set_color(info.color);
    encoder.set_depth(info.bit_depth);

    let mut writer = encoder.write_header()?;
    writer.write_image_data(&buf)?;

    Ok(())
}

fn main() {
    if let Err(e) = demo() {
        eprintln!("Error: {}", e);
    }
}

注意

  • 我使用了 read_png() 方法来同时读取图片信息和图片数据,这简化了代码。
  • 确保在调用 write_image_data() 时使用了正确的缓冲区 buf,该缓冲区包含了从原始图片中读取的数据。
  • 我还添加了错误处理,以便在出现问题时能够更清晰地了解发生了什么。

如果这样处理后仍然存在问题,建议检查 PNG 文件的元数据,以确保没有其他未处理的特殊情况。此外,也可以考虑使用其他 Rust 的 PNG 库,如 image 库,它提供了更高级别的抽象和更多的功能。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题