我正在使用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等格式并将结果存入内存?
答案 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(())
}