如何对 Rust 活塞图像进行编码并在内存中获取结果?
How do I encode a Rust Piston image and get the result in memory?
我正在使用 the Piston image
package 生成图像。
fn get_image() -> image::DynamicImage {
image::DynamicImage::ImageRgba8(image::ImageBuffer::new(512, 512))
}
我有一个 hyper
web server,我想从中提供动态生成的图像。
根据对 的回答,我认为我可以使用 Cursor<Vec<u8>>
作为目的地。但是,image
似乎只提供了一种写入文件名的方法,而不是像我的光标那样的 Writer
。
看了image
的文档后,希望有什么方法可以直接使用the image::png::PNGEncoder
struct。它提供了一个public方法encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> Result<()>
。但是,我不确定 data
参数应该是什么,而且我找不到 ImageBuffer
使用的 ColorType
的任何 public 声明。
(&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 等格式并在内存中获取结果?
fn getImage() -> image::DynamicImage
你有一个DynamicImage
。
image only seems to provide a method to write to a filename
我假设你的意思是 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
。
How do I encode a Piston GenericImage
to a format like PNG?
我不知道最好的方法。我可能会将通用图像复制到 DynamicImage
中,然后按照上述说明进行操作。
我已经根据 image
crate 文档改编了 OP 的代码。看起来可以使原始代码工作。不需要 Cursor
,但需要为 Vec
实现的 Write
实例创建一个 "by reference" 适配器。
// 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)
}
而不是 return从 get_image
生成 DynamicImage
,return 特定的图像类型会更容易,例如彩色 RGBA 图像:
use image::RgbaImage;
fn get_image() -> RgbaImage {
RgbaImage::new(512, 512)
}
RgbaImage
实现了Deref<[u8]>
,也就是说图像可以直接解引用为一个字节片,所以&img
可以作为[=17]的第一个参数=].高度和宽度很容易,只需访问 img.height()
和 img.width()
。 encode
的最后一个参数是颜色类型,它更巧妙地存储为 ImageBuffer
上 Pixel
类型参数的关联常量。从通用类型中,它可以作为 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(())
}
我正在使用 the Piston image
package 生成图像。
fn get_image() -> image::DynamicImage {
image::DynamicImage::ImageRgba8(image::ImageBuffer::new(512, 512))
}
我有一个 hyper
web server,我想从中提供动态生成的图像。
根据对 Cursor<Vec<u8>>
作为目的地。但是,image
似乎只提供了一种写入文件名的方法,而不是像我的光标那样的 Writer
。
看了image
的文档后,希望有什么方法可以直接使用the image::png::PNGEncoder
struct。它提供了一个public方法encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> Result<()>
。但是,我不确定 data
参数应该是什么,而且我找不到 ImageBuffer
使用的 ColorType
的任何 public 声明。
(&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 等格式并在内存中获取结果?
fn getImage() -> image::DynamicImage
你有一个DynamicImage
。
image only seems to provide a method to write to a filename
我假设你的意思是 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
。
How do I encode a Piston
GenericImage
to a format like PNG?
我不知道最好的方法。我可能会将通用图像复制到 DynamicImage
中,然后按照上述说明进行操作。
我已经根据 image
crate 文档改编了 OP 的代码。看起来可以使原始代码工作。不需要 Cursor
,但需要为 Vec
实现的 Write
实例创建一个 "by reference" 适配器。
// 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)
}
而不是 return从 get_image
生成 DynamicImage
,return 特定的图像类型会更容易,例如彩色 RGBA 图像:
use image::RgbaImage;
fn get_image() -> RgbaImage {
RgbaImage::new(512, 512)
}
RgbaImage
实现了Deref<[u8]>
,也就是说图像可以直接解引用为一个字节片,所以&img
可以作为[=17]的第一个参数=].高度和宽度很容易,只需访问 img.height()
和 img.width()
。 encode
的最后一个参数是颜色类型,它更巧妙地存储为 ImageBuffer
上 Pixel
类型参数的关联常量。从通用类型中,它可以作为 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(())
}