如何编码Rust Piston图像并将结果存入内存?

时间:2018-06-07 01:09:50

标签: image rust rust-piston

我正在使用the Piston image package生成图片。

fn get_image() -> image::DynamicImage {
    image::DynamicImage::ImageRgba8(image::ImageBuffer::new(512, 512))
}

我有hyper web server,我想从中提供动态生成的图片。

根据对 How to create an in-memory object that can be used as a Reader or Writer in Rust? 的回答,我想我可以使用Cursor<Vec<u8>>作为目的地。但是,image似乎只提供了一种写入文件名的方法,而不是像我的光标一样Writer

查看image的文档后,我希望可能有某种方法可以直接使用the image::png::PNGEncoder struct。它提供了一个公共方法encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> Result<()>。但是,我不确定data参数应该是什么,我无法找到ColorType所使用的ImageBuffer的公开声明。< / p>

(&Get, "/image.png") => {
    let v = {
        let generated = get_image();
        let mut encoded_image = Cursor::new(Vec::new());
        let (width, heigth) = generated.dimensions();
        {
            let encoder = image::png::PNGEncoder::new(&encoded_image);
            encoder.encode(unimplemented!("what goes here?"));
        }
        encoded_image.get_mut()
    };

    Box::new(futures::future::ok(
        Response::new()
            .with_header(ContentLength(v.len() as u64))
            .with_body(v.clone()),
    ))
}

如何将a Piston GenericImage编码为PNG等格式并将结果存入内存?

3 个答案:

答案 0 :(得分:1)

fn getImage() -> image::DynamicImage 

你有DynamicImage

  

图像似乎只提供了一种写入文件名的方法

我认为你的意思是DynamicImage::save

save之前的方法是write_to

pub fn write_to<W: Write, F: Into<ImageOutputFormat>>(
    &self, 
    w: &mut W, 
    format: F
) -> ImageResult<()>

这接受任何通用作家:

let mut buf = Vec::new();

get_image()
    .write_to(&mut buf, image::ImageOutputFormat::PNG)
    .expect("Unable to write");

不需要Cursor

  

如何将活塞GenericImage编码为PNG等格式?

我不知道最好的方法。我可能会将通用图片复制到DynamicImage,然后按照上述说明操作。

答案 1 :(得分:1)

我已根据Cursor板条箱文档改编了OP的代码。看起来有可能使原始代码正常工作。不需要Write,但是需要为Vec实现的// This code have not been tested or even compiled let v = { let generated = get_image(); let mut encoded_image = Vec::new(); let (width, height) = generated.dimensions(); { image::png::PNGEncoder::new(encoded_image.by_ref()) .encode( generated.raw_pixels(), width, height, generated.color() ).expected("error encoding pixels as PNG"); } encoded_image }; 实例创建一个“ by reference”适配器。

&[u8]

这是我在项目中实际使用的代码。我得到了对作为pub fn create_png(pixels: &[u8], dimensions: (usize, usize)) -> Result<Vec<u8>> { let mut png_buffer = Vec::new(); PNGEncoder::new(png_buffer.by_ref()) .encode( pixels, dimensions.0 as u32, dimensions.1 as u32, ColorType::Gray(8), ).expect("error encoding pixels as PNG"); Ok(png_buffer) } 切片传入的原始像素的引用。每个像素代表一个8位灰度值。这是一个将像素编码为内存中PNG图像的函数。

df1
              2010  2020  2030  2040  2050  
Country  Fuel
A        Gas   100   110   120   130   140
         Coal  100   110   120   130   140 
df2
              2010  2020  2030  2040  2050  
Country  Fuel
A        Gas   100   110   120   130   140
         Coal  100   110   120   130   140 

答案 2 :(得分:0)

与从DynamicImage返回get_image相比,返回特定图像类型(例如彩色RGBA图像)更容易:

use image::RgbaImage;

fn get_image() -> RgbaImage {
    RgbaImage::new(512, 512)
}

RgbaImage实现了Deref<[u8]>,这意味着可以将图像直接作为字节的片段进行取消引用,因此&img可以用作encode的第一个参数。高度和宽度很容易,只需访问img.height()img.width()encode的最后一个参数是颜色类型,因为它被存储为Pixel上的ImageBuffer类型参数的关联常量,所以颜色更复杂。从通用类型可以将其作为P::COLOR_TYPE进行访问,因此,我没有将encode_png特定于一种图像,而是将其编写为接受任何ImageBuffer类型。

完整的示例如下:

use std::error::Error;
use std::ops::Deref;
use image::{png::PNGEncoder, ImageBuffer, ImageError, Pixel, RgbaImage, Rgba};

fn encode_png<P, Container>(img: &ImageBuffer<P, Container>) -> Result<Vec<u8>, ImageError>
where
    P: Pixel<Subpixel = u8> + 'static,
    Container: Deref<Target = [P::Subpixel]>,
{
    let mut buf = Vec::new();
    let encoder = PNGEncoder::new(&mut buf);
    encoder.encode(img, img.width(), img.height(), P::COLOR_TYPE)?;
    Ok(buf)
}

fn get_image() -> RgbaImage {
    let mut img = RgbaImage::new(32, 32);

    // Draw something to show in the final image
    for i in 0..32 {
        img.put_pixel(i, i, Rgba([255, 0, 0, 255]));
    }
    img
}

fn main() -> Result<(), Box<dyn Error>> {
    let img = get_image();
    let buf = encode_png(&img)?;

    // write out the image using the base64 crate as a data
    // URL so that it can be copy-pasted into a web browser
    println!("data:image/png;base64,{}", base64::encode(&buf));
    Ok(())
}

游乐场:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e2611c5ef248667bf984a8dd3cedfec8