简体   繁体   English

如何编码 Rust Piston 图像并在内存中获取结果?

[英]How do I encode a Rust Piston image and get the result in memory?

I am using the Piston image package to generate images.我正在使用Piston image来生成图像。

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

I have a hyper web server , from which I would like to serve dynamically-generated images.我有一个hyper网络服务器,我想从中提供动态生成的图像。

Based on the answer to How to create an in-memory object that can be used as a Reader or Writer in Rust?基于如何在 Rust 中创建可用作读取器或写入器的内存中对象的答案 , I thought I might be able to use a Cursor<Vec<u8>> as the destination. ,我想我可以使用Cursor<Vec<u8>>作为目的地。 However, image only seems to provide a method to write to a filename, not a Writer like my cursor.但是, image似乎只提供了一种写入文件名的方法,而不是像我的光标这样的Writer

After looking through image 's documentation, I hoped there might be some way to use the image::png::PNGEncoder struct directly.在查看了image的文档后,我希望可能有某种方法可以直接使用image::png::PNGEncoder结构 It provides a public method encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> Result<()> .它提供了一个公共方法encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> Result<()> However, I wasn't sure what the data argument is supposed to be, and I couldn't find any public declarations of the ColorType s used by ImageBuffer .但是,我不确定data参数应该是什么,并且找不到ImageBuffer使用的ColorType的任何公共声明。

(&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()),
    ))
}

How do I encode a Piston GenericImage to a format like PNG and get the result in memory?如何将 Piston GenericImage编码PNG 等格式并在内存中获取结果?

fn getImage() -> image::DynamicImage

You have a DynamicImage .你有一个DynamicImage

image only seems to provide a method to write to a filename图像似乎只提供了一种写入文件名的方法

I assume you mean DynamicImage::save .我假设你的意思是DynamicImage::save

The method immediately before save is write_to : save之前的方法是write_to

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

This accepts any generic writer:这接受任何通用编写器:

let mut buf = Vec::new();

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

There's no need for a Cursor .不需要Cursor


How do I encode a Piston GenericImage to a format like PNG?如何将 Piston GenericImage编码为 PNG 等格式?

I have no idea the best way to do this.我不知道这样做的最佳方法。 I'd probably copy the generic image into a DynamicImage and then follow the above instructions.我可能DynamicImage通用图像复制到DynamicImage ,然后按照上述说明进行操作。

I've adapted OP's code based on the image crate docs.我已经根据image箱文档改编了 OP 的代码。 It looks possible to make the original code to work.看起来可以使原始代码工作。 There is no need for Cursor but one needs to create a "by reference" adaptor for the instance of Write implemented by Vec .不需要Cursor但需要为Vec实现的Write实例创建一个“按引用”适配器。

// 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
};

Here is the code I actually used in my project.这是我在项目中实际使用的代码。 I get a reference to the raw pixels passed in as an &[u8] slice.我得到了对作为&[u8]切片传入的原始像素的引用。 Each pixel represents an 8 bit grayscale value.每个像素代表一个 8 位灰度值。 Here is a function that encodes the pixels into an in memory PNG image.这是一个将像素编码为内存中的 PNG 图像的函数。

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)
}

Rather than returning a DynamicImage from get_image , it would be easier to return a specific image type, for example a colour RGBA image:与从get_image返回DynamicImage相比,返回特定图像类型会更容易,例如彩色 RGBA 图像:

use image::RgbaImage;

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

The RgbaImage implements Deref<[u8]> , which means that the image can be directly dereferenced as a slice of bytes, so &img can be used as the first argument to encode . RgbaImage实现了Deref<[u8]> ,这意味着图像可以直接解引用为字节切片,因此&img可以用作encode的第一个参数。 The height and width are easy, just access img.height() and img.width() .高度和宽度很容易,只需访问img.height()img.width() The final argument to encode is the colour type, which is more fiddly as it is stored as an associated constant of the Pixel type parameter on the ImageBuffer . encode的最后一个参数是颜色类型,它更复杂,因为它存储为ImageBufferPixel类型参数的关联常量。 From the generic type it can be accessed as P::COLOR_TYPE , so instead of making encode_png specific to one type of image, I've written it as accepting any ImageBuffer type.从泛型类型中,它可以作为P::COLOR_TYPE访问,因此我将其编写为接受任何ImageBuffer类型,而不是使encode_png特定于一种类型的图像。

The full example is then:完整的例子是:

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(())
}

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM