4 use std
::borrow
::BorrowMut
;
5 use std
::sync
::{Arc
, Mutex
};
7 use num_traits
::cast
::AsPrimitive
;
8 use percent_encoding
::percent_decode_str
;
9 use actix_web
::{get
, web
, App
, HttpServer
, HttpRequest
, HttpResponse
, Responder
, ResponseError
, Result
};
10 use actix_web
::body
::BoxBody
;
11 use actix_web
::http
::StatusCode
;
12 use image
::{ImageBuffer
, ColorType
, Rgb
, RgbImage
, write_buffer_with_format
};
13 use image
::ImageOutputFormat
::Png
;
14 use image
::imageops
::{FilterType
, resize
};
15 use image
::error
::{LimitError
, LimitErrorKind
};
19 struct ImageError(image
::ImageError
);
22 fn dimension_error() -> ImageError
{
23 ImageError(image
::ImageError
::Limits(LimitError
::from_kind(LimitErrorKind
::DimensionError
)))
27 impl Display
for ImageError
{
28 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
29 write
!(f
, "{}", &self.0)
33 impl ResponseError
for ImageError
{
34 fn status_code(&self) -> StatusCode
{
35 StatusCode
::INTERNAL_SERVER_ERROR
38 fn error_response(&self) -> HttpResponse
<BoxBody
> {
39 HttpResponse
::InternalServerError().body(format
!("{}\n", &self))
49 impl Display
for CanvasError
{
50 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
51 write
!(f
, "Canvas Error: see error_response() for more details")
55 impl ResponseError
for CanvasError
{
56 fn status_code(&self) -> StatusCode
{
58 CanvasError
::NotExists
=> StatusCode
::NOT_FOUND
,
59 CanvasError
::DimensionMismatch
=> StatusCode
::BAD_REQUEST
63 fn error_response(&self) -> HttpResponse
<BoxBody
> {
65 CanvasError
::NotExists
=> HttpResponse
::NotFound().body("Canvas does not exist."),
66 CanvasError
::DimensionMismatch
=> HttpResponse
::BadRequest().body("Supplied dimensions don't much the dimensions of existing canvas.")
71 struct ToRgbIter
<'a
, T
> where T
: AsPrimitive
<u8> {
72 iter
: Box
<&'a
mut dyn Iterator
<Item
= T
>>
75 impl<'a
, T
: AsPrimitive
<u8>> ToRgbIter
<'a
, T
> {
76 fn new(data
: &'a
mut (dyn Iterator
<Item
= T
>)) -> ToRgbIter
<T
> {
77 ToRgbIter
{ iter
: Box
::new(data
) }
81 impl<T
: AsPrimitive
<u8> + Zero
> Iterator
for ToRgbIter
<'_
, T
> {
83 fn next(&mut self) -> Option
<Rgb
<u8>> {
84 if let Some(r
) = self.iter
.next() {
85 let g
= self.iter
.next().unwrap
_or
(T
::zero());
86 let b
= self.iter
.next().unwrap
_or
(T
::zero());
87 Some(Rgb([r
.as_(), g
.as_(), b
.as_()]))
95 fn to_imageresult
<T
> (result
: Result
<T
, image
::ImageError
>) -> Result
<T
, ImageError
> {
98 Err(e
) => Err(ImageError(e
))
108 fn new(width
: u32, height
: u32) -> Canvas
{
109 Canvas
{ pen
: 0, img
: ImageBuffer
::new(width
, height
) }
112 fn from_image(img
: RgbImage
) -> Canvas
{
113 Canvas
{ pen
: 0, img
}
116 /*fn replace(&self, img: RgbImage, pen: usize) -> Canvas {
122 fn advance_pen(mut self, offset
: usize) -> Canvas
{
123 //Canvas { pen: self.pen + offset, img: self.img }
125 self.pen
%= self.img
.width() as usize * self.img
.height() as usize;
130 #[get("/hello/{name}")]
131 async
fn greet(name
: web
::Path
<String
>, req
: HttpRequest
) -> impl Responder
{
132 println
!("{:?}", req
);
133 format
!("Hello {name}!")
136 fn rgb_encode_to_canvas(mut canvas
: Canvas
, data
: &mut dyn Iterator
<Item
= u8>) -> Result
<Canvas
, ImageError
> {
137 let mut pixels
= canvas
.img
.pixels_mut().skip(canvas
.pen
);
140 for sp
in ToRgbIter
::new(data
) {
141 let mut dp
= match pixels
.next() {
142 Some(pixel
) => pixel
,
144 pixels
= canvas
.img
.pixels_mut().skip(0);
145 pixels
.next().ok_or(ImageError
::dimension_error())?
148 println
!("{:?}", sp
);
153 Ok(canvas
.advance_pen(counter
))
156 fn rgb_encode(img
: RgbImage
, data
: &mut dyn Iterator
<Item
= u8>) -> Result
<RgbImage
, ImageError
> {
157 Ok(rgb_encode_to_canvas(Canvas
::from_image(img
), data
)?
.img
)
160 fn make_png(dim_x
: u32, dim_y
: u32, scale
: u32, data
: &mut dyn Iterator
<Item
= u8>) -> Result
<Cursor
<Vec
<u8>>, ImageError
> {
161 // Image must not be larger than 1 megapixel
162 if dim_x
* dim_y
* scale
> 1048576 {
163 return Err(ImageError
::dimension_error())
166 let img
: RgbImage
= rgb_encode(ImageBuffer
::new(dim_x
, dim_y
), data
)?
;
168 let tdim_x
= dim_x
* scale
;
169 let tdim_y
= dim_y
* scale
;
170 let img
= resize(&img
, tdim_x
, tdim_y
, FilterType
::Nearest
);
171 let mut cursor
= Cursor
::new(Vec
::new());
172 to_imageresult(write_buffer_with_format(&mut cursor
, &img
, tdim_x
, tdim_y
, ColorType
::Rgb8
, Png
))?
;
176 #[get("/gen/0/{data}")]
177 async
fn img_gen0(req
: HttpRequest
) -> Result
<impl Responder
> {
178 let data
= req
.ur
i().path().split("/").skip(3).next().unwrap
();
179 let cursor
= make_png(32, 32, 16, percent_decode_str(&data
).into
_iter
().borrow_mut())?
;
180 Ok(HttpResponse
::build(StatusCode
::OK
)
181 .content_type("image/png")
182 .body(cursor
.into
_inner
()))
185 #[get("/gen/1/{dim_x}/{dim_y}/{scale}/{data}")]
186 async
fn img_gen1(req
: HttpRequest
, path
: web
::Path
<(u32, u32, u32)>) -> Result
<impl Responder
> {
187 let (dim_x
, dim_y
, scale
) = path
.into
_inner
();
188 let data
= req
.ur
i().path().split("/").skip(6).next().unwrap
();
189 let cursor
= make_png(dim_x
, dim_y
, scale
, percent_decode_str(&data
).into
_iter
().borrow_mut())?
;
190 Ok(HttpResponse
::build(StatusCode
::OK
)
191 .content_type("image/png")
192 .body(cursor
.into
_inner
()))
195 #[get("/pgen/0/{data}")]
196 async
fn img_pgen0(req
: HttpRequest
, canvas0
: web
::Data
<Arc
<Mutex
<Option
<Canvas
>>>>) -> Result
<impl Responder
> {
197 let data
= req
.ur
i().path().split("/").skip(3).next().unwrap
();
198 let mut cursor
= Cursor
::new(Vec
::new());
200 let img
: RgbImage
= {
201 let canvas_option
= &mut *canvas0
.lock().unwrap
();
202 let canvas
= canvas_option
.take().ok_or(CanvasError
::NotExists
)?
;
203 let canvas
= rgb_encode_to_canvas(canvas
, percent_decode_str(&data
).into
_iter
().borrow_mut())?
;
204 canvas_option
.insert
(canvas
).img
.clone()
206 let (tdim_x
, tdim_y
) = img
.dimensions();
207 let (tdim_x
, tdim_y
) = (tdim_x
* scale
, tdim_y
* scale
);
208 let img
= resize(&img
, tdim_x
, tdim_y
, FilterType
::Nearest
);
209 to_imageresult(write_buffer_with_format(&mut cursor
, &img
, tdim_x
, tdim_y
, ColorType
::Rgb8
, Png
))?
;
210 Ok(HttpResponse
::build(StatusCode
::OK
)
211 .content_type("image/png")
212 .body(cursor
.into
_inner
()))
215 #[get("/pgen/1/{dim_x}/{dim_y}/{scale}/{data}")]
216 async
fn img_pgen1(req
: HttpRequest
, path
: web
::Path
<(u32, u32, u32)>, canvas1
: web
::Data
<Arc
<Mutex
<Option
<Canvas
>>>>) -> Result
<impl Responder
> {
217 let (dim_x
, dim_y
, scale
) = path
.into
_inner
();
218 let data
= req
.ur
i().path().split("/").skip(6).next().unwrap
();
219 let img
: RgbImage
= {
220 let canvas_option
= &mut *canvas1
.lock().unwrap
();
221 let canvas
= canvas_option
.take().unwrap
_or
_else
( || Canvas
::new(dim_x
, dim_y
) );
222 if (dim_x
, dim_y
) == canvas
.img
.dimensions() {
223 let canvas
= rgb_encode_to_canvas(canvas
, percent_decode_str(&data
).into
_iter
().borrow_mut())?
;
224 Ok(canvas_option
.insert
(canvas
).img
.clone())
227 _
= canvas_option
.insert
(canvas
);
228 Err(CanvasError
::DimensionMismatch
)
231 let (tdim_x
, tdim_y
) = img
.dimensions();
232 let (tdim_x
, tdim_y
) = (tdim_x
* scale
, tdim_y
* scale
);
233 let img
= resize(&img
, tdim_x
, tdim_y
, FilterType
::Nearest
);
234 let mut cursor
= Cursor
::new(Vec
::new());
235 to_imageresult(write_buffer_with_format(&mut cursor
, &img
, tdim_x
, tdim_y
, ColorType
::Rgb8
, Png
))?
;
236 Ok(HttpResponse
::build(StatusCode
::OK
)
237 .content_type("image/png")
238 .body(cursor
.into
_inner
()))
242 #[actix_web::main] // or #[tokio::main]
243 async
fn main() -> std
::io
::Result
<()> {
245 let canvas0
= Arc
::new(Mutex
::new(Some(Canvas
::new(32, 32))));
246 let canvas1
= Arc
::new(Mutex
::new(None
as Option
<Canvas
>));
247 HttpServer
::new(move || {
254 .app_data(web
::Data
::new(canvas0
.clone()))
255 .app_data(web
::Data
::new(canvas1
.clone()))
257 .bind(("127.0.0.1", 8080))?