1
1
use ahash:: HashMap ;
2
2
use egui:: {
3
3
decode_animated_image_uri,
4
- load:: { BytesPoll , ImageLoadResult , ImageLoader , ImagePoll , LoadError , SizeHint } ,
4
+ load:: { Bytes , BytesPoll , ImageLoadResult , ImageLoader , ImagePoll , LoadError , SizeHint } ,
5
5
mutex:: Mutex ,
6
6
ColorImage ,
7
7
} ;
8
8
use image:: ImageFormat ;
9
- use std:: { mem:: size_of, path:: Path , sync:: Arc } ;
9
+ use std:: { mem:: size_of, path:: Path , sync:: Arc , task :: Poll } ;
10
10
11
- type Entry = Result < Arc < ColorImage > , LoadError > ;
11
+ #[ cfg( not( target_arch = "wasm32" ) ) ]
12
+ use std:: thread;
13
+
14
+ type Entry = Poll < Result < Arc < ColorImage > , String > > ;
12
15
13
16
#[ derive( Default ) ]
14
17
pub struct ImageCrateLoader {
15
- cache : Mutex < HashMap < String , Entry > > ,
18
+ cache : Arc < Mutex < HashMap < String , Entry > > > ,
16
19
}
17
20
18
21
impl ImageCrateLoader {
@@ -73,11 +76,69 @@ impl ImageLoader for ImageCrateLoader {
73
76
return Err ( LoadError :: NotSupported ) ;
74
77
}
75
78
76
- let mut cache = self . cache . lock ( ) ;
77
- if let Some ( entry) = cache. get ( uri) . cloned ( ) {
78
- match entry {
79
+ #[ cfg( not( target_arch = "wasm32" ) ) ]
80
+ #[ allow( clippy:: unnecessary_wraps) ] // needed here to match other return types
81
+ fn load_image (
82
+ ctx : & egui:: Context ,
83
+ uri : & str ,
84
+ cache : & Arc < Mutex < HashMap < String , Entry > > > ,
85
+ bytes : & Bytes ,
86
+ ) -> ImageLoadResult {
87
+ let uri = uri. to_owned ( ) ;
88
+ cache. lock ( ) . insert ( uri. clone ( ) , Poll :: Pending ) ;
89
+
90
+ // Do the image parsing on a bg thread
91
+ thread:: Builder :: new ( )
92
+ . name ( format ! ( "egui_extras::ImageLoader::load({uri:?})" ) )
93
+ . spawn ( {
94
+ let ctx = ctx. clone ( ) ;
95
+ let cache = cache. clone ( ) ;
96
+
97
+ let uri = uri. clone ( ) ;
98
+ let bytes = bytes. clone ( ) ;
99
+ move || {
100
+ log:: trace!( "ImageLoader - started loading {uri:?}" ) ;
101
+ let result = crate :: image:: load_image_bytes ( & bytes)
102
+ . map ( Arc :: new)
103
+ . map_err ( |err| err. to_string ( ) ) ;
104
+ log:: trace!( "ImageLoader - finished loading {uri:?}" ) ;
105
+ let prev = cache. lock ( ) . insert ( uri, Poll :: Ready ( result) ) ;
106
+ debug_assert ! ( matches!( prev, Some ( Poll :: Pending ) ) ) ;
107
+
108
+ ctx. request_repaint ( ) ;
109
+ }
110
+ } )
111
+ . expect ( "failed to spawn thread" ) ;
112
+
113
+ Ok ( ImagePoll :: Pending { size : None } )
114
+ }
115
+
116
+ #[ cfg( target_arch = "wasm32" ) ]
117
+ fn load_image (
118
+ _ctx : & egui:: Context ,
119
+ uri : & str ,
120
+ cache : & Arc < Mutex < HashMap < String , Entry > > > ,
121
+ bytes : & Bytes ,
122
+ ) -> ImageLoadResult {
123
+ let mut cache_lock = cache. lock ( ) ;
124
+ log:: trace!( "started loading {uri:?}" ) ;
125
+ let result = crate :: image:: load_image_bytes ( bytes)
126
+ . map ( Arc :: new)
127
+ . map_err ( |err| err. to_string ( ) ) ;
128
+ log:: trace!( "finished loading {uri:?}" ) ;
129
+ cache_lock. insert ( uri. into ( ) , std:: task:: Poll :: Ready ( result. clone ( ) ) ) ;
130
+ match result {
79
131
Ok ( image) => Ok ( ImagePoll :: Ready { image } ) ,
80
- Err ( err) => Err ( err) ,
132
+ Err ( err) => Err ( LoadError :: Loading ( err) ) ,
133
+ }
134
+ }
135
+
136
+ let entry = self . cache . lock ( ) . get ( uri) . cloned ( ) ;
137
+ if let Some ( entry) = entry {
138
+ match entry {
139
+ Poll :: Ready ( Ok ( image) ) => Ok ( ImagePoll :: Ready { image } ) ,
140
+ Poll :: Ready ( Err ( err) ) => Err ( LoadError :: Loading ( err) ) ,
141
+ Poll :: Pending => Ok ( ImagePoll :: Pending { size : None } ) ,
81
142
}
82
143
} else {
83
144
match ctx. try_load_bytes ( uri) {
@@ -90,19 +151,7 @@ impl ImageLoader for ImageCrateLoader {
90
151
} ) ;
91
152
}
92
153
}
93
-
94
- if bytes. starts_with ( b"version https://git-lfs" ) {
95
- return Err ( LoadError :: FormatNotSupported {
96
- detected_format : Some ( "git-lfs" . to_owned ( ) ) ,
97
- } ) ;
98
- }
99
-
100
- // (3)
101
- log:: trace!( "started loading {uri:?}" ) ;
102
- let result = crate :: image:: load_image_bytes ( & bytes) . map ( Arc :: new) ;
103
- log:: trace!( "finished loading {uri:?}" ) ;
104
- cache. insert ( uri. into ( ) , result. clone ( ) ) ;
105
- result. map ( |image| ImagePoll :: Ready { image } )
154
+ load_image ( ctx, uri, & self . cache , & bytes)
106
155
}
107
156
Ok ( BytesPoll :: Pending { size } ) => Ok ( ImagePoll :: Pending { size } ) ,
108
157
Err ( err) => Err ( err) ,
@@ -123,8 +172,9 @@ impl ImageLoader for ImageCrateLoader {
123
172
. lock ( )
124
173
. values ( )
125
174
. map ( |result| match result {
126
- Ok ( image) => image. pixels . len ( ) * size_of :: < egui:: Color32 > ( ) ,
127
- Err ( err) => err. byte_size ( ) ,
175
+ Poll :: Ready ( Ok ( image) ) => image. pixels . len ( ) * size_of :: < egui:: Color32 > ( ) ,
176
+ Poll :: Ready ( Err ( err) ) => err. len ( ) ,
177
+ Poll :: Pending => 0 ,
128
178
} )
129
179
. sum ( )
130
180
}
0 commit comments