@@ -11,7 +11,12 @@ use axum::{
1111 response:: { IntoResponse , Response } ,
1212} ;
1313
14+ use rand:: { Rng , SeedableRng , rngs:: SmallRng , seq:: IndexedRandom } ;
1415use reqwest:: header:: CONTENT_TYPE ;
16+ use svg:: {
17+ Document ,
18+ node:: element:: { Definitions , Group , Mask , Polygon , Polyline , Rectangle , Use , tag:: Rectangle } ,
19+ } ;
1520use tokio:: { fs:: File , process:: Command , task:: JoinSet } ;
1621use tokio_util:: io:: ReaderStream ;
1722
@@ -35,7 +40,7 @@ pub struct DataImage {
3540
3641pub enum ResponseImage {
3742 File ( File ) ,
38- Placeholder ,
43+ Placeholder ( u32 ) ,
3944}
4045
4146impl ProfileImage {
@@ -70,7 +75,7 @@ impl ProfileImage {
7075
7176 pub async fn get_with_placeholder ( & self , size : u32 ) -> Result < ResponseImage , AppError > {
7277 match self . get ( size) . await {
73- Err ( AppError :: ImageNotFound ) => Ok ( ResponseImage :: Placeholder ) ,
78+ Err ( AppError :: ImageNotFound ) => Ok ( ResponseImage :: Placeholder ( self . user_id ) ) ,
7479 other => other,
7580 }
7681 }
@@ -158,17 +163,108 @@ impl DataImage {
158163
159164impl IntoResponse for ResponseImage {
160165 fn into_response ( self ) -> Response {
161- let mut resp = match self {
162- Self :: Placeholder => Body :: from ( PLACEHOLDER ) ,
163- Self :: File ( file) => Body :: from_stream ( ReaderStream :: new ( file) ) ,
166+ match self {
167+ Self :: Placeholder ( user_id) => {
168+ let mut body = Body :: from ( make_placeholder ( user_id) ) . into_response ( ) ;
169+ body. headers_mut ( )
170+ . insert ( CONTENT_TYPE , HeaderValue :: from_static ( "image/svg+xml" ) ) ;
171+ body
172+ }
173+ Self :: File ( file) => {
174+ let mut body = Body :: from_stream ( ReaderStream :: new ( file) ) . into_response ( ) ;
175+ body. headers_mut ( ) . insert (
176+ CONTENT_TYPE ,
177+ HeaderValue :: from_static ( IMAGE_SAVE_TYPE . mime_type ( ) ) ,
178+ ) ;
179+ body
180+ }
164181 }
165- . into_response ( ) ;
182+ }
183+ }
166184
167- resp. headers_mut ( ) . insert (
168- CONTENT_TYPE ,
169- HeaderValue :: from_static ( IMAGE_SAVE_TYPE . mime_type ( ) ) ,
170- ) ;
185+ fn make_placeholder ( user_id : u32 ) -> Vec < u8 > {
186+ let mut rand_gen = SmallRng :: seed_from_u64 ( user_id as u64 ) ;
187+ let polygon_points = "9.0,0.0 4.5,7.794 -4.5,7.794 -9.0,0 -4.5,-7.794 4.5,-7.794" ;
188+
189+ let mask_polygon = Polygon :: new ( )
190+ . set ( "points" , polygon_points)
191+ . set ( "fill" , "white" ) ;
192+
193+ let mask = Mask :: new ( )
194+ . set ( "id" , "poly" )
195+ . set ( "mask-type" , "luminance" )
196+ . set ( "x" , -100 )
197+ . set ( "y" , -100 )
198+ . set ( "width" , 200 )
199+ . set ( "height" , 200 )
200+ . set ( "maskUnits" , "userSpaceOnUse" )
201+ . add ( mask_polygon) ;
202+
203+ let cube_polygon = Polygon :: new ( ) . set ( "points" , polygon_points) ;
204+
205+ let cube_polyline = Polyline :: new ( )
206+ . set ( "mask" , "url(#poly)" )
207+ . set ( "points" , "9,0 0,0 -4.5,7.794 0,0 -4.5,-7.794" )
208+ . set ( "style" , "fill:none;stroke:#02020244;stroke-width:.6" ) ;
209+
210+ let cube_group = Group :: new ( )
211+ . set ( "id" , "cube" )
212+ . add ( cube_polygon)
213+ . add ( cube_polyline) ;
171214
172- resp
215+ let defs = Definitions :: new ( ) . add ( cube_group) ;
216+
217+ // TODO randomize rotation
218+ let mut main_group = Group :: new ( ) . set ( "transform" , "rotate(0 32 32)" ) ;
219+
220+ let use_data = vec ! [
221+ ( 22.0 , 14.68 ) ,
222+ ( 42.0 , 14.68 ) ,
223+ ( 12.0 , 32.0 ) ,
224+ ( 52.0 , 32.0 ) ,
225+ ( 22.0 , 49.32 ) ,
226+ ( 42.0 , 49.32 ) ,
227+ ] ;
228+
229+ let colors = [ "#FFBE0B" , "#FF4037" , "#FF006E" , "#8338EC" , "#3A86FF" ] ;
230+
231+ for ( x, y) in use_data {
232+ let use_element = Use :: new ( )
233+ . set ( "xlink:href" , "#cube" )
234+ . set ( "x" , x)
235+ . set ( "y" , y)
236+ . set ( "fill" , * colors. choose ( & mut rand_gen) . unwrap ( ) ) ;
237+ main_group = main_group. add ( use_element) ;
173238 }
239+
240+ // make the middle one zeus orange
241+ let use_element = Use :: new ( )
242+ . set ( "xlink:href" , "#cube" )
243+ . set ( "x" , 32 )
244+ . set ( "y" , 32 )
245+ . set ( "fill" , "#FF7F00" ) ;
246+ main_group = main_group. add ( use_element) ;
247+
248+ let background = Rectangle :: new ( )
249+ . set ( "width" , "64" )
250+ . set ( "height" , "64" )
251+ . set ( "x" , "0" )
252+ . set ( "y" , "0" )
253+ . set ( "fill" , "#EEE" ) ;
254+
255+ let document = Document :: new ( )
256+ . set ( "width" , 64 )
257+ . set ( "height" , 64 )
258+ . set ( "fill" , "#ff7f00" )
259+ . set ( "xmlns:xlink" , "http://www.w3.org/1999/xlink" )
260+ . set ( "id" , "flynn" )
261+ . add ( background)
262+ . add ( mask)
263+ . add ( defs)
264+ . add ( main_group) ;
265+
266+ let mut buffer = Vec :: new ( ) ;
267+ svg:: write ( & mut buffer, & document) . unwrap ( ) ;
268+
269+ buffer
174270}
0 commit comments