Как мне кодировать изображение Rust Piston и получить результат в памяти? - PullRequest
0 голосов
/ 07 июня 2018

Я использую пакет Piston image для генерации изображений.

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

У меня есть hyper веб-сервер , с которого я бынравится обслуживать динамически генерируемые изображения.

Основано на ответе на Как создать объект в памяти, который можно использовать для чтения или записи в Rust? , Я думал, что смогу использовать Cursor<Vec<u8>> в качестве пункта назначения.Однако image, по-видимому, предоставляет только способ записи в имя файла, а не Writer, как мой курсор.

После просмотра документации image я надеялся, что может быть какой-то способиспользуйте image::png::PNGEncoder struct напрямую.Предоставляет публичный метод encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> Result<()>.Однако я не был уверен, каким должен быть аргумент data, и я не смог найти никаких публичных объявлений ColorType, используемых ImageBuffer.

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

КакЯ кодирую поршень GenericImage в формат, подобный PNG, и получаю результат в памяти?

Ответы [ 2 ]

0 голосов
/ 04 ноября 2018

Я адаптировал код OP на основе документов image ящиков.Похоже, можно заставить оригинальный код работать.Нет необходимости в Cursor, но нужно создать адаптер «по ссылке» для экземпляра 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
};

Вот код, который я фактически использовал в своем проекте.Я получаю ссылку на необработанные пиксели, переданные как срез &[u8].Каждый пиксель представляет 8-битное значение оттенков серого.Вот функция, которая кодирует пиксели в изображение 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)
}
0 голосов
/ 07 июня 2018
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 и затем следовал бы инструкциям выше.

...