@@ -229,16 +229,29 @@ async fn load_gltf<'a, 'b>(
229
229
Texture :: from_buffer ( buffer, ImageType :: MimeType ( mime_type) ) ?
230
230
}
231
231
gltf:: image:: Source :: Uri { uri, mime_type } => {
232
- let parent = load_context. path ( ) . parent ( ) . unwrap ( ) ;
233
- let image_path = parent. join ( uri) ;
234
- let bytes = load_context. read_asset_bytes ( image_path. clone ( ) ) . await ?;
232
+ let uri = percent_encoding:: percent_decode_str ( uri)
233
+ . decode_utf8 ( )
234
+ . unwrap ( ) ;
235
+ let uri = uri. as_ref ( ) ;
236
+ let ( bytes, image_type) = match DataUri :: parse ( uri) {
237
+ Ok ( data_uri) => ( data_uri. decode ( ) ?, ImageType :: MimeType ( data_uri. mime_type ) ) ,
238
+ Err ( ( ) ) => {
239
+ let parent = load_context. path ( ) . parent ( ) . unwrap ( ) ;
240
+ let image_path = parent. join ( uri) ;
241
+ let bytes = load_context. read_asset_bytes ( image_path. clone ( ) ) . await ?;
242
+
243
+ let extension = Path :: new ( uri) . extension ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
244
+ let image_type = ImageType :: Extension ( extension) ;
245
+
246
+ ( bytes, image_type)
247
+ }
248
+ } ;
249
+
235
250
Texture :: from_buffer (
236
251
& bytes,
237
252
mime_type
238
253
. map ( |mt| ImageType :: MimeType ( mt) )
239
- . unwrap_or_else ( || {
240
- ImageType :: Extension ( image_path. extension ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) )
241
- } ) ,
254
+ . unwrap_or ( image_type) ,
242
255
) ?
243
256
}
244
257
} ;
@@ -576,23 +589,27 @@ async fn load_buffers(
576
589
load_context : & LoadContext < ' _ > ,
577
590
asset_path : & Path ,
578
591
) -> Result < Vec < Vec < u8 > > , GltfError > {
579
- const OCTET_STREAM_URI : & str = "data: application/octet-stream;base64, " ;
592
+ const OCTET_STREAM_URI : & str = "application/octet-stream" ;
580
593
581
594
let mut buffer_data = Vec :: new ( ) ;
582
595
for buffer in gltf. buffers ( ) {
583
596
match buffer. source ( ) {
584
597
gltf:: buffer:: Source :: Uri ( uri) => {
585
- if uri. starts_with ( "data:" ) {
586
- buffer_data. push ( base64:: decode (
587
- uri. strip_prefix ( OCTET_STREAM_URI )
588
- . ok_or ( GltfError :: BufferFormatUnsupported ) ?,
589
- ) ?) ;
590
- } else {
591
- // TODO: Remove this and add dep
592
- let buffer_path = asset_path. parent ( ) . unwrap ( ) . join ( uri) ;
593
- let buffer_bytes = load_context. read_asset_bytes ( buffer_path) . await ?;
594
- buffer_data. push ( buffer_bytes) ;
595
- }
598
+ let uri = percent_encoding:: percent_decode_str ( uri)
599
+ . decode_utf8 ( )
600
+ . unwrap ( ) ;
601
+ let uri = uri. as_ref ( ) ;
602
+ let buffer_bytes = match DataUri :: parse ( uri) {
603
+ Ok ( data_uri) if data_uri. mime_type == OCTET_STREAM_URI => data_uri. decode ( ) ?,
604
+ Ok ( _) => return Err ( GltfError :: BufferFormatUnsupported ) ,
605
+ Err ( ( ) ) => {
606
+ // TODO: Remove this and add dep
607
+ let buffer_path = asset_path. parent ( ) . unwrap ( ) . join ( uri) ;
608
+ let buffer_bytes = load_context. read_asset_bytes ( buffer_path) . await ?;
609
+ buffer_bytes
610
+ }
611
+ } ;
612
+ buffer_data. push ( buffer_bytes) ;
596
613
}
597
614
gltf:: buffer:: Source :: Bin => {
598
615
if let Some ( blob) = gltf. blob . as_deref ( ) {
@@ -653,6 +670,43 @@ fn resolve_node_hierarchy(
653
670
. collect ( )
654
671
}
655
672
673
+ struct DataUri < ' a > {
674
+ mime_type : & ' a str ,
675
+ base64 : bool ,
676
+ data : & ' a str ,
677
+ }
678
+
679
+ fn split_once ( input : & str , delimiter : char ) -> Option < ( & str , & str ) > {
680
+ let mut iter = input. splitn ( 2 , delimiter) ;
681
+ Some ( ( iter. next ( ) ?, iter. next ( ) ?) )
682
+ }
683
+
684
+ impl < ' a > DataUri < ' a > {
685
+ fn parse ( uri : & ' a str ) -> Result < DataUri < ' a > , ( ) > {
686
+ let uri = uri. strip_prefix ( "data:" ) . ok_or ( ( ) ) ?;
687
+ let ( mime_type, data) = split_once ( uri, ',' ) . ok_or ( ( ) ) ?;
688
+
689
+ let ( mime_type, base64) = match mime_type. strip_suffix ( ";base64" ) {
690
+ Some ( mime_type) => ( mime_type, true ) ,
691
+ None => ( mime_type, false ) ,
692
+ } ;
693
+
694
+ Ok ( DataUri {
695
+ mime_type,
696
+ base64,
697
+ data,
698
+ } )
699
+ }
700
+
701
+ fn decode ( & self ) -> Result < Vec < u8 > , base64:: DecodeError > {
702
+ if self . base64 {
703
+ base64:: decode ( self . data )
704
+ } else {
705
+ Ok ( self . data . as_bytes ( ) . to_owned ( ) )
706
+ }
707
+ }
708
+ }
709
+
656
710
#[ cfg( test) ]
657
711
mod test {
658
712
use super :: resolve_node_hierarchy;
0 commit comments