LogLuvLoader.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. import {
  2. DataUtils,
  3. DataTextureLoader,
  4. FloatType,
  5. HalfFloatType,
  6. RGBAFormat
  7. } from 'three';
  8. class LogLuvLoader extends DataTextureLoader {
  9. constructor( manager ) {
  10. super( manager );
  11. this.type = HalfFloatType;
  12. }
  13. parse( buffer ) {
  14. const ifds = UTIF.decode( buffer );
  15. UTIF.decodeImage( buffer, ifds[ 0 ] );
  16. const rgba = UTIF.toRGBA( ifds[ 0 ], this.type );
  17. return {
  18. width: ifds[ 0 ].width,
  19. height: ifds[ 0 ].height,
  20. data: rgba,
  21. format: RGBAFormat,
  22. type: this.type,
  23. flipY: true
  24. };
  25. }
  26. setDataType( value ) {
  27. this.type = value;
  28. return this;
  29. }
  30. }
  31. // from https://github.com/photopea/UTIF.js (MIT License)
  32. const UTIF = {};
  33. UTIF.decode = function ( buff, prm ) {
  34. if ( prm == null ) prm = { parseMN: true, debug: false }; // read MakerNote, debug
  35. var data = new Uint8Array( buff ), offset = 0;
  36. var id = UTIF._binBE.readASCII( data, offset, 2 ); offset += 2;
  37. var bin = id == 'II' ? UTIF._binLE : UTIF._binBE;
  38. bin.readUshort( data, offset ); offset += 2;
  39. var ifdo = bin.readUint( data, offset );
  40. var ifds = [];
  41. while ( true ) {
  42. var cnt = bin.readUshort( data, ifdo ), typ = bin.readUshort( data, ifdo + 4 ); if ( cnt != 0 ) if ( typ < 1 || 13 < typ ) {
  43. console.log( 'error in TIFF' ); break;
  44. }
  45. UTIF._readIFD( bin, data, ifdo, ifds, 0, prm );
  46. ifdo = bin.readUint( data, ifdo + 2 + cnt * 12 );
  47. if ( ifdo == 0 ) break;
  48. }
  49. return ifds;
  50. };
  51. UTIF.decodeImage = function ( buff, img, ifds ) {
  52. if ( img.data ) return;
  53. var data = new Uint8Array( buff );
  54. var id = UTIF._binBE.readASCII( data, 0, 2 );
  55. if ( img[ 't256' ] == null ) return; // No width => probably not an image
  56. img.isLE = id == 'II';
  57. img.width = img[ 't256' ][ 0 ]; //delete img["t256"];
  58. img.height = img[ 't257' ][ 0 ]; //delete img["t257"];
  59. var cmpr = img[ 't259' ] ? img[ 't259' ][ 0 ] : 1; //delete img["t259"];
  60. var fo = img[ 't266' ] ? img[ 't266' ][ 0 ] : 1; //delete img["t266"];
  61. if ( img[ 't284' ] && img[ 't284' ][ 0 ] == 2 ) console.log( 'PlanarConfiguration 2 should not be used!' );
  62. if ( cmpr == 7 && img[ 't258' ] && img[ 't258' ].length > 3 ) img[ 't258' ] = img[ 't258' ].slice( 0, 3 );
  63. var bipp; // bits per pixel
  64. if ( img[ 't258' ] ) bipp = Math.min( 32, img[ 't258' ][ 0 ] ) * img[ 't258' ].length;
  65. else bipp = ( img[ 't277' ] ? img[ 't277' ][ 0 ] : 1 );
  66. // Some .NEF files have t258==14, even though they use 16 bits per pixel
  67. if ( cmpr == 1 && img[ 't279' ] != null && img[ 't278' ] && img[ 't262' ][ 0 ] == 32803 ) {
  68. bipp = Math.round( ( img[ 't279' ][ 0 ] * 8 ) / ( img.width * img[ 't278' ][ 0 ] ) );
  69. }
  70. var bipl = Math.ceil( img.width * bipp / 8 ) * 8;
  71. var soff = img[ 't273' ]; if ( soff == null ) soff = img[ 't324' ];
  72. var bcnt = img[ 't279' ]; if ( cmpr == 1 && soff.length == 1 ) bcnt = [ img.height * ( bipl >>> 3 ) ]; if ( bcnt == null ) bcnt = img[ 't325' ];
  73. //bcnt[0] = Math.min(bcnt[0], data.length); // Hasselblad, "RAW_HASSELBLAD_H3D39II.3FR"
  74. var bytes = new Uint8Array( img.height * ( bipl >>> 3 ) ), bilen = 0;
  75. if ( img[ 't322' ] != null ) {
  76. var tw = img[ 't322' ][ 0 ], th = img[ 't323' ][ 0 ];
  77. var tx = Math.floor( ( img.width + tw - 1 ) / tw );
  78. var ty = Math.floor( ( img.height + th - 1 ) / th );
  79. var tbuff = new Uint8Array( Math.ceil( tw * th * bipp / 8 ) | 0 );
  80. for ( var y = 0; y < ty; y ++ )
  81. for ( var x = 0; x < tx; x ++ ) {
  82. var i = y * tx + x; for ( var j = 0; j < tbuff.length; j ++ ) tbuff[ j ] = 0;
  83. UTIF.decode._decompress( img, ifds, data, soff[ i ], bcnt[ i ], cmpr, tbuff, 0, fo );
  84. // Might be required for 7 too. Need to check
  85. if ( cmpr == 6 ) bytes = tbuff;
  86. else UTIF._copyTile( tbuff, Math.ceil( tw * bipp / 8 ) | 0, th, bytes, Math.ceil( img.width * bipp / 8 ) | 0, img.height, Math.ceil( x * tw * bipp / 8 ) | 0, y * th );
  87. }
  88. bilen = bytes.length * 8;
  89. } else {
  90. var rps = img[ 't278' ] ? img[ 't278' ][ 0 ] : img.height; rps = Math.min( rps, img.height );
  91. for ( var i = 0; i < soff.length; i ++ ) {
  92. UTIF.decode._decompress( img, ifds, data, soff[ i ], bcnt[ i ], cmpr, bytes, Math.ceil( bilen / 8 ) | 0, fo );
  93. bilen += bipl * rps;
  94. }
  95. bilen = Math.min( bilen, bytes.length * 8 );
  96. }
  97. img.data = new Uint8Array( bytes.buffer, 0, Math.ceil( bilen / 8 ) | 0 );
  98. };
  99. UTIF.decode._decompress = function ( img, ifds, data, off, len, cmpr, tgt, toff ) {
  100. //console.log("compression", cmpr);
  101. //var time = Date.now();
  102. if ( cmpr == 34676 ) UTIF.decode._decodeLogLuv32( img, data, off, len, tgt, toff );
  103. else console.log( 'Unsupported compression', cmpr );
  104. //console.log(Date.now()-time);
  105. var bps = ( img[ 't258' ] ? Math.min( 32, img[ 't258' ][ 0 ] ) : 1 );
  106. var noc = ( img[ 't277' ] ? img[ 't277' ][ 0 ] : 1 ), bpp = ( bps * noc ) >>> 3, h = ( img[ 't278' ] ? img[ 't278' ][ 0 ] : img.height ), bpl = Math.ceil( bps * noc * img.width / 8 );
  107. // convert to Little Endian /*
  108. if ( bps == 16 && ! img.isLE && img[ 't33422' ] == null ) // not DNG
  109. for ( var y = 0; y < h; y ++ ) {
  110. //console.log("fixing endianity");
  111. var roff = toff + y * bpl;
  112. for ( var x = 1; x < bpl; x += 2 ) {
  113. var t = tgt[ roff + x ]; tgt[ roff + x ] = tgt[ roff + x - 1 ]; tgt[ roff + x - 1 ] = t;
  114. }
  115. } //*/
  116. if ( img[ 't317' ] && img[ 't317' ][ 0 ] == 2 ) {
  117. for ( var y = 0; y < h; y ++ ) {
  118. var ntoff = toff + y * bpl;
  119. if ( bps == 16 ) for ( var j = bpp; j < bpl; j += 2 ) {
  120. var nv = ( ( tgt[ ntoff + j + 1 ] << 8 ) | tgt[ ntoff + j ] ) + ( ( tgt[ ntoff + j - bpp + 1 ] << 8 ) | tgt[ ntoff + j - bpp ] );
  121. tgt[ ntoff + j ] = nv & 255; tgt[ ntoff + j + 1 ] = ( nv >>> 8 ) & 255;
  122. }
  123. else if ( noc == 3 ) for ( var j = 3; j < bpl; j += 3 ) {
  124. tgt[ ntoff + j ] = ( tgt[ ntoff + j ] + tgt[ ntoff + j - 3 ] ) & 255;
  125. tgt[ ntoff + j + 1 ] = ( tgt[ ntoff + j + 1 ] + tgt[ ntoff + j - 2 ] ) & 255;
  126. tgt[ ntoff + j + 2 ] = ( tgt[ ntoff + j + 2 ] + tgt[ ntoff + j - 1 ] ) & 255;
  127. }
  128. else for ( var j = bpp; j < bpl; j ++ ) tgt[ ntoff + j ] = ( tgt[ ntoff + j ] + tgt[ ntoff + j - bpp ] ) & 255;
  129. }
  130. }
  131. };
  132. UTIF.decode._decodeLogLuv32 = function ( img, data, off, len, tgt, toff ) {
  133. var w = img.width, qw = w * 4;
  134. var io = 0, out = new Uint8Array( qw );
  135. while ( io < len ) {
  136. var oo = 0;
  137. while ( oo < qw ) {
  138. var c = data[ off + io ]; io ++;
  139. if ( c < 128 ) {
  140. for ( var j = 0; j < c; j ++ ) out[ oo + j ] = data[ off + io + j ]; oo += c; io += c;
  141. } else {
  142. c = c - 126; for ( var j = 0; j < c; j ++ ) out[ oo + j ] = data[ off + io ]; oo += c; io ++;
  143. }
  144. }
  145. for ( var x = 0; x < w; x ++ ) {
  146. tgt[ toff + 0 ] = out[ x ];
  147. tgt[ toff + 1 ] = out[ x + w ];
  148. tgt[ toff + 2 ] = out[ x + w * 2 ];
  149. tgt[ toff + 4 ] = out[ x + w * 3 ];
  150. toff += 6;
  151. }
  152. }
  153. };
  154. UTIF.tags = {};
  155. //UTIF.ttypes = { 256:3,257:3,258:3, 259:3, 262:3, 273:4, 274:3, 277:3,278:4,279:4, 282:5, 283:5, 284:3, 286:5,287:5, 296:3, 305:2, 306:2, 338:3, 513:4, 514:4, 34665:4 };
  156. // start at tag 250
  157. UTIF._types = function () {
  158. var main = new Array( 250 ); main.fill( 0 );
  159. main = main.concat( [ 0, 0, 0, 0, 4, 3, 3, 3, 3, 3, 0, 0, 3, 0, 0, 0, 3, 0, 0, 2, 2, 2, 2, 4, 3, 0, 0, 3, 4, 4, 3, 3, 5, 5, 3, 2, 5, 5, 0, 0, 0, 0, 4, 4, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 3, 5, 5, 3, 0, 3, 3, 4, 4, 4, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] );
  160. var rest = { 33432: 2, 33434: 5, 33437: 5, 34665: 4, 34850: 3, 34853: 4, 34855: 3, 34864: 3, 34866: 4, 36864: 7, 36867: 2, 36868: 2, 37121: 7, 37377: 10, 37378: 5, 37380: 10, 37381: 5, 37383: 3, 37384: 3, 37385: 3, 37386: 5, 37510: 7, 37520: 2, 37521: 2, 37522: 2, 40960: 7, 40961: 3, 40962: 4, 40963: 4, 40965: 4, 41486: 5, 41487: 5, 41488: 3, 41985: 3, 41986: 3, 41987: 3, 41988: 5, 41989: 3, 41990: 3, 41993: 3, 41994: 3, 41995: 7, 41996: 3, 42032: 2, 42033: 2, 42034: 5, 42036: 2, 42037: 2, 59932: 7 };
  161. return {
  162. basic: {
  163. main: main,
  164. rest: rest
  165. },
  166. gps: {
  167. main: [ 1, 2, 5, 2, 5, 1, 5, 5, 0, 9 ],
  168. rest: { 18: 2, 29: 2 }
  169. }
  170. };
  171. }();
  172. UTIF._readIFD = function ( bin, data, offset, ifds, depth, prm ) {
  173. var cnt = bin.readUshort( data, offset ); offset += 2;
  174. var ifd = {};
  175. if ( prm.debug ) console.log( ' '.repeat( depth ), ifds.length - 1, '>>>----------------' );
  176. for ( var i = 0; i < cnt; i ++ ) {
  177. var tag = bin.readUshort( data, offset ); offset += 2;
  178. var type = bin.readUshort( data, offset ); offset += 2;
  179. var num = bin.readUint( data, offset ); offset += 4;
  180. var voff = bin.readUint( data, offset ); offset += 4;
  181. var arr = [];
  182. //ifd["t"+tag+"-"+UTIF.tags[tag]] = arr;
  183. if ( type == 1 || type == 7 ) {
  184. arr = new Uint8Array( data.buffer, ( num < 5 ? offset - 4 : voff ), num );
  185. }
  186. if ( type == 2 ) {
  187. var o0 = ( num < 5 ? offset - 4 : voff ), c = data[ o0 ], len = Math.max( 0, Math.min( num - 1, data.length - o0 ) );
  188. if ( c < 128 || len == 0 ) arr.push( bin.readASCII( data, o0, len ) );
  189. else arr = new Uint8Array( data.buffer, o0, len );
  190. }
  191. if ( type == 3 ) {
  192. for ( var j = 0; j < num; j ++ ) arr.push( bin.readUshort( data, ( num < 3 ? offset - 4 : voff ) + 2 * j ) );
  193. }
  194. if ( type == 4
  195. || type == 13 ) {
  196. for ( var j = 0; j < num; j ++ ) arr.push( bin.readUint( data, ( num < 2 ? offset - 4 : voff ) + 4 * j ) );
  197. }
  198. if ( type == 5 || type == 10 ) {
  199. var ri = type == 5 ? bin.readUint : bin.readInt;
  200. for ( var j = 0; j < num; j ++ ) arr.push( [ ri( data, voff + j * 8 ), ri( data, voff + j * 8 + 4 ) ] );
  201. }
  202. if ( type == 8 ) {
  203. for ( var j = 0; j < num; j ++ ) arr.push( bin.readShort( data, ( num < 3 ? offset - 4 : voff ) + 2 * j ) );
  204. }
  205. if ( type == 9 ) {
  206. for ( var j = 0; j < num; j ++ ) arr.push( bin.readInt( data, ( num < 2 ? offset - 4 : voff ) + 4 * j ) );
  207. }
  208. if ( type == 11 ) {
  209. for ( var j = 0; j < num; j ++ ) arr.push( bin.readFloat( data, voff + j * 4 ) );
  210. }
  211. if ( type == 12 ) {
  212. for ( var j = 0; j < num; j ++ ) arr.push( bin.readDouble( data, voff + j * 8 ) );
  213. }
  214. if ( num != 0 && arr.length == 0 ) {
  215. console.log( tag, 'unknown TIFF tag type: ', type, 'num:', num ); if ( i == 0 ) return; continue;
  216. }
  217. if ( prm.debug ) console.log( ' '.repeat( depth ), tag, type, UTIF.tags[ tag ], arr );
  218. ifd[ 't' + tag ] = arr;
  219. if ( tag == 330 || tag == 34665 || tag == 34853 || ( tag == 50740 && bin.readUshort( data, bin.readUint( arr, 0 ) ) < 300 ) || tag == 61440 ) {
  220. var oarr = tag == 50740 ? [ bin.readUint( arr, 0 ) ] : arr;
  221. var subfd = [];
  222. for ( var j = 0; j < oarr.length; j ++ ) UTIF._readIFD( bin, data, oarr[ j ], subfd, depth + 1, prm );
  223. if ( tag == 330 ) ifd.subIFD = subfd;
  224. if ( tag == 34665 ) ifd.exifIFD = subfd[ 0 ];
  225. if ( tag == 34853 ) ifd.gpsiIFD = subfd[ 0 ]; //console.log("gps", subfd[0]); }
  226. if ( tag == 50740 ) ifd.dngPrvt = subfd[ 0 ];
  227. if ( tag == 61440 ) ifd.fujiIFD = subfd[ 0 ];
  228. }
  229. if ( tag == 37500 && prm.parseMN ) {
  230. var mn = arr;
  231. //console.log(bin.readASCII(mn,0,mn.length), mn);
  232. if ( bin.readASCII( mn, 0, 5 ) == 'Nikon' ) ifd.makerNote = UTIF[ 'decode' ]( mn.slice( 10 ).buffer )[ 0 ];
  233. else if ( bin.readUshort( data, voff ) < 300 && bin.readUshort( data, voff + 4 ) <= 12 ) {
  234. var subsub = []; UTIF._readIFD( bin, data, voff, subsub, depth + 1, prm );
  235. ifd.makerNote = subsub[ 0 ];
  236. }
  237. }
  238. }
  239. ifds.push( ifd );
  240. if ( prm.debug ) console.log( ' '.repeat( depth ), '<<<---------------' );
  241. return offset;
  242. };
  243. UTIF.toRGBA = function ( out, type ) {
  244. const w = out.width, h = out.height, area = w * h, data = out.data;
  245. let img;
  246. switch ( type ) {
  247. case HalfFloatType:
  248. img = new Uint16Array( area * 4 );
  249. break;
  250. case FloatType:
  251. img = new Float32Array( area * 4 );
  252. break;
  253. default:
  254. console.error( 'THREE.LogLuvLoader: Unsupported texture data type:', type );
  255. }
  256. let intp = out[ 't262' ] ? out[ 't262' ][ 0 ] : 2;
  257. const bps = out[ 't258' ] ? Math.min( 32, out[ 't258' ][ 0 ] ) : 1;
  258. if ( out[ 't262' ] == null && bps == 1 ) intp = 0;
  259. if ( intp == 32845 ) {
  260. for ( let y = 0; y < h; y ++ ) {
  261. for ( let x = 0; x < w; x ++ ) {
  262. const si = ( y * w + x ) * 6, qi = ( y * w + x ) * 4;
  263. let L = ( data[ si + 1 ] << 8 ) | data[ si ];
  264. L = Math.pow( 2, ( L + 0.5 ) / 256 - 64 );
  265. const u = ( data[ si + 3 ] + 0.5 ) / 410;
  266. const v = ( data[ si + 5 ] + 0.5 ) / 410;
  267. // Luv to xyY
  268. const sX = ( 9 * u ) / ( 6 * u - 16 * v + 12 );
  269. const sY = ( 4 * v ) / ( 6 * u - 16 * v + 12 );
  270. const bY = L;
  271. // xyY to XYZ
  272. const X = ( sX * bY ) / sY, Y = bY, Z = ( 1 - sX - sY ) * bY / sY;
  273. // XYZ to linear RGB
  274. const r = 2.690 * X - 1.276 * Y - 0.414 * Z;
  275. const g = - 1.022 * X + 1.978 * Y + 0.044 * Z;
  276. const b = 0.061 * X - 0.224 * Y + 1.163 * Z;
  277. if ( type === HalfFloatType ) {
  278. img[ qi ] = DataUtils.toHalfFloat( Math.min( r, 65504 ) );
  279. img[ qi + 1 ] = DataUtils.toHalfFloat( Math.min( g, 65504 ) );
  280. img[ qi + 2 ] = DataUtils.toHalfFloat( Math.min( b, 65504 ) );
  281. img[ qi + 3 ] = DataUtils.toHalfFloat( 1 );
  282. } else {
  283. img[ qi ] = r;
  284. img[ qi + 1 ] = g;
  285. img[ qi + 2 ] = b;
  286. img[ qi + 3 ] = 1;
  287. }
  288. }
  289. }
  290. } else {
  291. console.log( 'Unsupported Photometric interpretation: ' + intp );
  292. }
  293. return img;
  294. };
  295. UTIF._binBE =
  296. {
  297. nextZero: function ( data, o ) {
  298. while ( data[ o ] != 0 ) o ++; return o;
  299. },
  300. readUshort: function ( buff, p ) {
  301. return ( buff[ p ] << 8 ) | buff[ p + 1 ];
  302. },
  303. readShort: function ( buff, p ) {
  304. var a = UTIF._binBE.ui8; a[ 0 ] = buff[ p + 1 ]; a[ 1 ] = buff[ p + 0 ]; return UTIF._binBE.i16[ 0 ];
  305. },
  306. readInt: function ( buff, p ) {
  307. var a = UTIF._binBE.ui8; a[ 0 ] = buff[ p + 3 ]; a[ 1 ] = buff[ p + 2 ]; a[ 2 ] = buff[ p + 1 ]; a[ 3 ] = buff[ p + 0 ]; return UTIF._binBE.i32[ 0 ];
  308. },
  309. readUint: function ( buff, p ) {
  310. var a = UTIF._binBE.ui8; a[ 0 ] = buff[ p + 3 ]; a[ 1 ] = buff[ p + 2 ]; a[ 2 ] = buff[ p + 1 ]; a[ 3 ] = buff[ p + 0 ]; return UTIF._binBE.ui32[ 0 ];
  311. },
  312. readASCII: function ( buff, p, l ) {
  313. var s = ''; for ( var i = 0; i < l; i ++ ) s += String.fromCharCode( buff[ p + i ] ); return s;
  314. },
  315. readFloat: function ( buff, p ) {
  316. var a = UTIF._binBE.ui8; for ( var i = 0; i < 4; i ++ ) a[ i ] = buff[ p + 3 - i ]; return UTIF._binBE.fl32[ 0 ];
  317. },
  318. readDouble: function ( buff, p ) {
  319. var a = UTIF._binBE.ui8; for ( var i = 0; i < 8; i ++ ) a[ i ] = buff[ p + 7 - i ]; return UTIF._binBE.fl64[ 0 ];
  320. },
  321. writeUshort: function ( buff, p, n ) {
  322. buff[ p ] = ( n >> 8 ) & 255; buff[ p + 1 ] = n & 255;
  323. },
  324. writeInt: function ( buff, p, n ) {
  325. var a = UTIF._binBE.ui8; UTIF._binBE.i32[ 0 ] = n; buff[ p + 3 ] = a[ 0 ]; buff[ p + 2 ] = a[ 1 ]; buff[ p + 1 ] = a[ 2 ]; buff[ p + 0 ] = a[ 3 ];
  326. },
  327. writeUint: function ( buff, p, n ) {
  328. buff[ p ] = ( n >> 24 ) & 255; buff[ p + 1 ] = ( n >> 16 ) & 255; buff[ p + 2 ] = ( n >> 8 ) & 255; buff[ p + 3 ] = ( n >> 0 ) & 255;
  329. },
  330. writeASCII: function ( buff, p, s ) {
  331. for ( var i = 0; i < s.length; i ++ ) buff[ p + i ] = s.charCodeAt( i );
  332. },
  333. writeDouble: function ( buff, p, n ) {
  334. UTIF._binBE.fl64[ 0 ] = n;
  335. for ( var i = 0; i < 8; i ++ ) buff[ p + i ] = UTIF._binBE.ui8[ 7 - i ];
  336. }
  337. };
  338. UTIF._binBE.ui8 = new Uint8Array( 8 );
  339. UTIF._binBE.i16 = new Int16Array( UTIF._binBE.ui8.buffer );
  340. UTIF._binBE.i32 = new Int32Array( UTIF._binBE.ui8.buffer );
  341. UTIF._binBE.ui32 = new Uint32Array( UTIF._binBE.ui8.buffer );
  342. UTIF._binBE.fl32 = new Float32Array( UTIF._binBE.ui8.buffer );
  343. UTIF._binBE.fl64 = new Float64Array( UTIF._binBE.ui8.buffer );
  344. UTIF._binLE =
  345. {
  346. nextZero: UTIF._binBE.nextZero,
  347. readUshort: function ( buff, p ) {
  348. return ( buff[ p + 1 ] << 8 ) | buff[ p ];
  349. },
  350. readShort: function ( buff, p ) {
  351. var a = UTIF._binBE.ui8; a[ 0 ] = buff[ p + 0 ]; a[ 1 ] = buff[ p + 1 ]; return UTIF._binBE.i16[ 0 ];
  352. },
  353. readInt: function ( buff, p ) {
  354. var a = UTIF._binBE.ui8; a[ 0 ] = buff[ p + 0 ]; a[ 1 ] = buff[ p + 1 ]; a[ 2 ] = buff[ p + 2 ]; a[ 3 ] = buff[ p + 3 ]; return UTIF._binBE.i32[ 0 ];
  355. },
  356. readUint: function ( buff, p ) {
  357. var a = UTIF._binBE.ui8; a[ 0 ] = buff[ p + 0 ]; a[ 1 ] = buff[ p + 1 ]; a[ 2 ] = buff[ p + 2 ]; a[ 3 ] = buff[ p + 3 ]; return UTIF._binBE.ui32[ 0 ];
  358. },
  359. readASCII: UTIF._binBE.readASCII,
  360. readFloat: function ( buff, p ) {
  361. var a = UTIF._binBE.ui8; for ( var i = 0; i < 4; i ++ ) a[ i ] = buff[ p + i ]; return UTIF._binBE.fl32[ 0 ];
  362. },
  363. readDouble: function ( buff, p ) {
  364. var a = UTIF._binBE.ui8; for ( var i = 0; i < 8; i ++ ) a[ i ] = buff[ p + i ]; return UTIF._binBE.fl64[ 0 ];
  365. },
  366. writeUshort: function ( buff, p, n ) {
  367. buff[ p ] = ( n ) & 255; buff[ p + 1 ] = ( n >> 8 ) & 255;
  368. },
  369. writeInt: function ( buff, p, n ) {
  370. var a = UTIF._binBE.ui8; UTIF._binBE.i32[ 0 ] = n; buff[ p + 0 ] = a[ 0 ]; buff[ p + 1 ] = a[ 1 ]; buff[ p + 2 ] = a[ 2 ]; buff[ p + 3 ] = a[ 3 ];
  371. },
  372. writeUint: function ( buff, p, n ) {
  373. buff[ p ] = ( n >>> 0 ) & 255; buff[ p + 1 ] = ( n >>> 8 ) & 255; buff[ p + 2 ] = ( n >>> 16 ) & 255; buff[ p + 3 ] = ( n >>> 24 ) & 255;
  374. },
  375. writeASCII: UTIF._binBE.writeASCII
  376. };
  377. UTIF._copyTile = function ( tb, tw, th, b, w, h, xoff, yoff ) {
  378. //log("copyTile", tw, th, w, h, xoff, yoff);
  379. var xlim = Math.min( tw, w - xoff );
  380. var ylim = Math.min( th, h - yoff );
  381. for ( var y = 0; y < ylim; y ++ ) {
  382. var tof = ( yoff + y ) * w + xoff;
  383. var sof = y * tw;
  384. for ( var x = 0; x < xlim; x ++ ) b[ tof + x ] = tb[ sof + x ];
  385. }
  386. };
  387. export { LogLuvLoader };