@@ -433,7 +433,67 @@ window.Whammy = (function(){
433433 data : VP8 ,
434434 riff : riff
435435 }
436- }
436+ } /**
437+ * 读取指定偏移量处的小端模式的32位无符号整数
438+ * @param buffer - 数据缓冲区
439+ * @param offset - 起始偏移量
440+ * @returns 32位无符号整数
441+ */
442+ function readUint32LittleEndian ( buffer , offset ) {
443+ let val = parseInt (
444+ buffer
445+ . substr ( offset , 4 )
446+ . split ( "" )
447+ . map ( function ( i ) {
448+ var unpadded = i . charCodeAt ( 0 ) . toString ( 2 ) ;
449+ return new Array ( 8 - unpadded . length + 1 ) . join ( "0" ) + unpadded ;
450+ } )
451+ . reverse ( ) // 注意需要翻转字节序才是小端编码
452+ . join ( "" ) ,
453+ 2
454+ ) ;
455+ return val ;
456+ }
457+
458+ /**
459+ * 对于 VP8X,需要提取出其中的 VP8 或 VP8L bit stream chunk。
460+ * 关于 VP8X 格式,参见 Extended file format: https://developers.google.com/speed/webp/docs/riff_container#extended_file_format
461+ * @param buffer VP8X Chunk数据,不含 "VP8X" tag
462+ */
463+ function extractBitStreamFromVp8x ( buffer ) {
464+ //console.log("VP8X buffer:", buffer);
465+
466+ /*
467+ 跳过以下VP8X头:
468+ 32bit VP8X Chunk size
469+ 8bit Flags: Rsv I L E X A R
470+ 24bit Reserved
471+ 24bit Canvas Width Minus One
472+ 24bit Canvas Height Minus One
473+ */
474+ let offset = 4 + 1 + 3 + 3 + 3 ;
475+ // 搜索第一个"VP8 "或"VP8L" bit stream chunk
476+ while ( offset < buffer . length ) {
477+ let chunkTag = buffer . substr ( offset , 4 ) ;
478+ //console.log(`chunkTag: \"${chunkTag}\"`);
479+ offset += 4 ;
480+ let chunkSize = readUint32LittleEndian ( buffer , offset ) ;
481+ //console.log("chunkSize:", chunkSize);
482+ offset += 4 ;
483+ switch ( chunkTag ) {
484+ case "VP8 " :
485+ case "VP8L" :
486+ const size = buffer . substr ( offset - 4 , 4 ) ;
487+ const body = buffer . substr ( offset , chunkSize ) ;
488+ return size + body ;
489+ default :
490+ // 跳过不关心的数据块
491+ offset += chunkSize ;
492+ break ;
493+ }
494+ }
495+ console . error ( "VP8X format error: missing VP8/VP8L chunk." ) ;
496+ }
437497
438498 // i think i'm going off on a riff by pretending this is some known
439499 // idiom which i'm making a casual and brilliant pun about, but since
@@ -449,17 +509,27 @@ window.Whammy = (function(){
449509 while ( offset < string . length ) {
450510 var id = string . substr ( offset , 4 ) ;
451511 chunks [ id ] = chunks [ id ] || [ ] ;
452- if ( id == 'RIFF' || id == 'LIST' ) {
453- var len = parseInt ( string . substr ( offset + 4 , 4 ) . split ( '' ) . map ( function ( i ) {
454- var unpadded = i . charCodeAt ( 0 ) . toString ( 2 ) ;
455- return ( new Array ( 8 - unpadded . length + 1 ) ) . join ( '0' ) + unpadded
456- } ) . join ( '' ) , 2 ) ;
512+ if ( id == "RIFF" || id == "LIST" ) {
513+ var len = readUint32LittleEndian ( string , offset + 4 )
457514 var data = string . substr ( offset + 4 + 4 , len ) ;
515+ // console.log(data);
458516 offset += 4 + 4 + len ;
459517 chunks [ id ] . push ( parseRIFF ( data ) ) ;
460- } else if ( id == 'WEBP' ) {
461- // Use (offset + 8) to skip past "VP8 "/"VP8L"/"VP8X" field after "WEBP"
462- chunks [ id ] . push ( string . substr ( offset + 8 ) ) ;
518+ } else if ( id == "WEBP" ) {
519+ let vpVersion = string . substr ( offset + 4 , 4 ) ;
520+ switch ( vpVersion ) {
521+ case "VP8X" :
522+ chunks [ id ] . push ( extractBitStreamFromVp8x ( string . substr ( offset + 8 ) ) ) ;
523+ break ;
524+ case "VP8 " :
525+ case "VP8L" :
526+ // Use (offset + 8) to skip past "VP8 " / "VP8L" field after "WEBP"
527+ chunks [ id ] . push ( string . substr ( offset + 8 ) ) ;
528+ break ;
529+ default :
530+ console . error ( `not supported webp version: \"${ vpVersion } \"` ) ;
531+ break ;
532+ }
463533 offset = string . length ;
464534 } else {
465535 // Unknown chunk type; push entire payload
0 commit comments