EXRLoader.js 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192
  1. /**
  2. * @author Richard M. / https://github.com/richardmonette
  3. *
  4. * OpenEXR loader which, currently, supports reading 16 bit half data, in either
  5. * uncompressed or PIZ wavelet compressed form.
  6. *
  7. * Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
  8. * implementation, so I have preserved their copyright notices.
  9. */
  10. import {
  11. DataTextureLoader,
  12. DefaultLoadingManager,
  13. FloatType,
  14. RGBAFormat,
  15. RGBFormat
  16. } from "../../../build/three.module.js";
  17. // /*
  18. // Copyright (c) 2014 - 2017, Syoyo Fujita
  19. // All rights reserved.
  20. // Redistribution and use in source and binary forms, with or without
  21. // modification, are permitted provided that the following conditions are met:
  22. // * Redistributions of source code must retain the above copyright
  23. // notice, this list of conditions and the following disclaimer.
  24. // * Redistributions in binary form must reproduce the above copyright
  25. // notice, this list of conditions and the following disclaimer in the
  26. // documentation and/or other materials provided with the distribution.
  27. // * Neither the name of the Syoyo Fujita nor the
  28. // names of its contributors may be used to endorse or promote products
  29. // derived from this software without specific prior written permission.
  30. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  31. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  32. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  33. // DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  34. // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  35. // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  36. // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  37. // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  38. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  39. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  40. // */
  41. // // TinyEXR contains some OpenEXR code, which is licensed under ------------
  42. // ///////////////////////////////////////////////////////////////////////////
  43. // //
  44. // // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
  45. // // Digital Ltd. LLC
  46. // //
  47. // // All rights reserved.
  48. // //
  49. // // Redistribution and use in source and binary forms, with or without
  50. // // modification, are permitted provided that the following conditions are
  51. // // met:
  52. // // * Redistributions of source code must retain the above copyright
  53. // // notice, this list of conditions and the following disclaimer.
  54. // // * Redistributions in binary form must reproduce the above
  55. // // copyright notice, this list of conditions and the following disclaimer
  56. // // in the documentation and/or other materials provided with the
  57. // // distribution.
  58. // // * Neither the name of Industrial Light & Magic nor the names of
  59. // // its contributors may be used to endorse or promote products derived
  60. // // from this software without specific prior written permission.
  61. // //
  62. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  63. // // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  64. // // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  65. // // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  66. // // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  67. // // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  68. // // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  69. // // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  70. // // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  71. // // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  72. // // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  73. // //
  74. // ///////////////////////////////////////////////////////////////////////////
  75. // // End of OpenEXR license -------------------------------------------------
  76. var EXRLoader = function ( manager ) {
  77. this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
  78. };
  79. EXRLoader.prototype = Object.create( DataTextureLoader.prototype );
  80. EXRLoader.prototype._parser = function ( buffer ) {
  81. const USHORT_RANGE = ( 1 << 16 );
  82. const BITMAP_SIZE = ( USHORT_RANGE >> 3 );
  83. const HUF_ENCBITS = 16; // literal (value) bit length
  84. const HUF_DECBITS = 14; // decoding bit size (>= 8)
  85. const HUF_ENCSIZE = ( 1 << HUF_ENCBITS ) + 1; // encoding table size
  86. const HUF_DECSIZE = 1 << HUF_DECBITS; // decoding table size
  87. const HUF_DECMASK = HUF_DECSIZE - 1;
  88. const SHORT_ZEROCODE_RUN = 59;
  89. const LONG_ZEROCODE_RUN = 63;
  90. const SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN;
  91. const BYTES_PER_HALF = 2;
  92. const ULONG_SIZE = 8;
  93. const FLOAT32_SIZE = 4;
  94. const INT32_SIZE = 4;
  95. const INT16_SIZE = 2;
  96. const INT8_SIZE = 1;
  97. function reverseLutFromBitmap( bitmap, lut ) {
  98. var k = 0;
  99. for ( var i = 0; i < USHORT_RANGE; ++ i ) {
  100. if ( ( i == 0 ) || ( bitmap[ i >> 3 ] & ( 1 << ( i & 7 ) ) ) ) {
  101. lut[ k ++ ] = i;
  102. }
  103. }
  104. var n = k - 1;
  105. while ( k < USHORT_RANGE ) lut[ k ++ ] = 0;
  106. return n;
  107. }
  108. function hufClearDecTable( hdec ) {
  109. for ( var i = 0; i < HUF_DECSIZE; i ++ ) {
  110. hdec[ i ] = {};
  111. hdec[ i ].len = 0;
  112. hdec[ i ].lit = 0;
  113. hdec[ i ].p = null;
  114. }
  115. }
  116. const getBitsReturn = { l: 0, c: 0, lc: 0 };
  117. function getBits( nBits, c, lc, uInt8Array, inOffset ) {
  118. while ( lc < nBits ) {
  119. c = ( c << 8 ) | parseUint8Array( uInt8Array, inOffset );
  120. lc += 8;
  121. }
  122. lc -= nBits;
  123. getBitsReturn.l = ( c >> lc ) & ( ( 1 << nBits ) - 1 );
  124. getBitsReturn.c = c;
  125. getBitsReturn.lc = lc;
  126. }
  127. const hufTableBuffer = new Array( 59 );
  128. function hufCanonicalCodeTable( hcode ) {
  129. for ( var i = 0; i <= 58; ++ i ) hufTableBuffer[ i ] = 0;
  130. for ( var i = 0; i < HUF_ENCSIZE; ++ i ) hufTableBuffer[ hcode[ i ] ] += 1;
  131. var c = 0;
  132. for ( var i = 58; i > 0; -- i ) {
  133. var nc = ( ( c + hufTableBuffer[ i ] ) >> 1 );
  134. hufTableBuffer[ i ] = c;
  135. c = nc;
  136. }
  137. for ( var i = 0; i < HUF_ENCSIZE; ++ i ) {
  138. var l = hcode[ i ];
  139. if ( l > 0 ) hcode[ i ] = l | ( hufTableBuffer[ l ] ++ << 6 );
  140. }
  141. }
  142. function hufUnpackEncTable( uInt8Array, inDataView, inOffset, ni, im, iM, hcode ) {
  143. var p = inOffset;
  144. var c = 0;
  145. var lc = 0;
  146. for ( ; im <= iM; im ++ ) {
  147. if ( p.value - inOffset.value > ni ) return false;
  148. getBits( 6, c, lc, uInt8Array, p );
  149. var l = getBitsReturn.l;
  150. c = getBitsReturn.c;
  151. lc = getBitsReturn.lc;
  152. hcode[ im ] = l;
  153. if ( l == LONG_ZEROCODE_RUN ) {
  154. if ( p.value - inOffset.value > ni ) {
  155. throw 'Something wrong with hufUnpackEncTable';
  156. }
  157. getBits( 8, c, lc, uInt8Array, p );
  158. var zerun = getBitsReturn.l + SHORTEST_LONG_RUN;
  159. c = getBitsReturn.c;
  160. lc = getBitsReturn.lc;
  161. if ( im + zerun > iM + 1 ) {
  162. throw 'Something wrong with hufUnpackEncTable';
  163. }
  164. while ( zerun -- ) hcode[ im ++ ] = 0;
  165. im --;
  166. } else if ( l >= SHORT_ZEROCODE_RUN ) {
  167. var zerun = l - SHORT_ZEROCODE_RUN + 2;
  168. if ( im + zerun > iM + 1 ) {
  169. throw 'Something wrong with hufUnpackEncTable';
  170. }
  171. while ( zerun -- ) hcode[ im ++ ] = 0;
  172. im --;
  173. }
  174. }
  175. hufCanonicalCodeTable( hcode );
  176. }
  177. function hufLength( code ) {
  178. return code & 63;
  179. }
  180. function hufCode( code ) {
  181. return code >> 6;
  182. }
  183. function hufBuildDecTable( hcode, im, iM, hdecod ) {
  184. for ( ; im <= iM; im ++ ) {
  185. var c = hufCode( hcode[ im ] );
  186. var l = hufLength( hcode[ im ] );
  187. if ( c >> l ) {
  188. throw 'Invalid table entry';
  189. }
  190. if ( l > HUF_DECBITS ) {
  191. var pl = hdecod[ ( c >> ( l - HUF_DECBITS ) ) ];
  192. if ( pl.len ) {
  193. throw 'Invalid table entry';
  194. }
  195. pl.lit ++;
  196. if ( pl.p ) {
  197. var p = pl.p;
  198. pl.p = new Array( pl.lit );
  199. for ( var i = 0; i < pl.lit - 1; ++ i ) {
  200. pl.p[ i ] = p[ i ];
  201. }
  202. } else {
  203. pl.p = new Array( 1 );
  204. }
  205. pl.p[ pl.lit - 1 ] = im;
  206. } else if ( l ) {
  207. var plOffset = 0;
  208. for ( var i = 1 << ( HUF_DECBITS - l ); i > 0; i -- ) {
  209. var pl = hdecod[ ( c << ( HUF_DECBITS - l ) ) + plOffset ];
  210. if ( pl.len || pl.p ) {
  211. throw 'Invalid table entry';
  212. }
  213. pl.len = l;
  214. pl.lit = im;
  215. plOffset ++;
  216. }
  217. }
  218. }
  219. return true;
  220. }
  221. const getCharReturn = { c: 0, lc: 0 };
  222. function getChar( c, lc, uInt8Array, inOffset ) {
  223. c = ( c << 8 ) | parseUint8Array( uInt8Array, inOffset );
  224. lc += 8;
  225. getCharReturn.c = c;
  226. getCharReturn.lc = lc;
  227. }
  228. const getCodeReturn = { c: 0, lc: 0 };
  229. function getCode( po, rlc, c, lc, uInt8Array, inDataView, inOffset, outBuffer, outBufferOffset, outBufferEndOffset ) {
  230. if ( po == rlc ) {
  231. if ( lc < 8 ) {
  232. getChar( c, lc, uInt8Array, inOffset );
  233. c = getCharReturn.c;
  234. lc = getCharReturn.lc;
  235. }
  236. lc -= 8;
  237. var cs = ( c >> lc );
  238. var cs = new Uint8Array( [ cs ] )[ 0 ];
  239. if ( outBufferOffset.value + cs > outBufferEndOffset ) {
  240. return false;
  241. }
  242. var s = outBuffer[ outBufferOffset.value - 1 ];
  243. while ( cs -- > 0 ) {
  244. outBuffer[ outBufferOffset.value ++ ] = s;
  245. }
  246. } else if ( outBufferOffset.value < outBufferEndOffset ) {
  247. outBuffer[ outBufferOffset.value ++ ] = po;
  248. } else {
  249. return false;
  250. }
  251. getCodeReturn.c = c;
  252. getCodeReturn.lc = lc;
  253. }
  254. function UInt16( value ) {
  255. return ( value & 0xFFFF );
  256. }
  257. function Int16( value ) {
  258. var ref = UInt16( value );
  259. return ( ref > 0x7FFF ) ? ref - 0x10000 : ref;
  260. }
  261. const wdec14Return = { a: 0, b: 0 };
  262. function wdec14( l, h ) {
  263. var ls = Int16( l );
  264. var hs = Int16( h );
  265. var hi = hs;
  266. var ai = ls + ( hi & 1 ) + ( hi >> 1 );
  267. var as = ai;
  268. var bs = ai - hi;
  269. wdec14Return.a = as;
  270. wdec14Return.b = bs;
  271. }
  272. function wav2Decode( j, buffer, nx, ox, ny, oy ) {
  273. var n = ( nx > ny ) ? ny : nx;
  274. var p = 1;
  275. var p2;
  276. while ( p <= n ) p <<= 1;
  277. p >>= 1;
  278. p2 = p;
  279. p >>= 1;
  280. while ( p >= 1 ) {
  281. var py = 0;
  282. var ey = py + oy * ( ny - p2 );
  283. var oy1 = oy * p;
  284. var oy2 = oy * p2;
  285. var ox1 = ox * p;
  286. var ox2 = ox * p2;
  287. var i00, i01, i10, i11;
  288. for ( ; py <= ey; py += oy2 ) {
  289. var px = py;
  290. var ex = py + ox * ( nx - p2 );
  291. for ( ; px <= ex; px += ox2 ) {
  292. var p01 = px + ox1;
  293. var p10 = px + oy1;
  294. var p11 = p10 + ox1;
  295. wdec14( buffer[ px + j ], buffer[ p10 + j ] );
  296. i00 = wdec14Return.a;
  297. i10 = wdec14Return.b;
  298. wdec14( buffer[ p01 + j ], buffer[ p11 + j ] );
  299. i01 = wdec14Return.a;
  300. i11 = wdec14Return.b;
  301. wdec14( i00, i01 );
  302. buffer[ px + j ] = wdec14Return.a;
  303. buffer[ p01 + j ] = wdec14Return.b;
  304. wdec14( i10, i11 );
  305. buffer[ p10 + j ] = wdec14Return.a;
  306. buffer[ p11 + j ] = wdec14Return.b;
  307. }
  308. if ( nx & p ) {
  309. var p10 = px + oy1;
  310. wdec14( buffer[ px + j ], buffer[ p10 + j ] );
  311. i00 = wdec14Return.a;
  312. buffer[ p10 + j ] = wdec14Return.b;
  313. buffer[ px + j ] = i00;
  314. }
  315. }
  316. if ( ny & p ) {
  317. var px = py;
  318. var ex = py + ox * ( nx - p2 );
  319. for ( ; px <= ex; px += ox2 ) {
  320. var p01 = px + ox1;
  321. wdec14( buffer[ px + j ], buffer[ p01 + j ] );
  322. i00 = wdec14Return.a;
  323. buffer[ p01 + j ] = wdec14Return.b;
  324. buffer[ px + j ] = i00;
  325. }
  326. }
  327. p2 = p;
  328. p >>= 1;
  329. }
  330. return py;
  331. }
  332. function hufDecode( encodingTable, decodingTable, uInt8Array, inDataView, inOffset, ni, rlc, no, outBuffer, outOffset ) {
  333. var c = 0;
  334. var lc = 0;
  335. var outBufferEndOffset = no;
  336. var inOffsetEnd = Math.trunc( inOffset.value + ( ni + 7 ) / 8 );
  337. while ( inOffset.value < inOffsetEnd ) {
  338. getChar( c, lc, uInt8Array, inOffset );
  339. c = getCharReturn.c;
  340. lc = getCharReturn.lc;
  341. while ( lc >= HUF_DECBITS ) {
  342. var index = ( c >> ( lc - HUF_DECBITS ) ) & HUF_DECMASK;
  343. var pl = decodingTable[ index ];
  344. if ( pl.len ) {
  345. lc -= pl.len;
  346. getCode( pl.lit, rlc, c, lc, uInt8Array, inDataView, inOffset, outBuffer, outOffset, outBufferEndOffset );
  347. c = getCodeReturn.c;
  348. lc = getCodeReturn.lc;
  349. } else {
  350. if ( ! pl.p ) {
  351. throw 'hufDecode issues';
  352. }
  353. var j;
  354. for ( j = 0; j < pl.lit; j ++ ) {
  355. var l = hufLength( encodingTable[ pl.p[ j ] ] );
  356. while ( lc < l && inOffset.value < inOffsetEnd ) {
  357. getChar( c, lc, uInt8Array, inOffset );
  358. c = getCharReturn.c;
  359. lc = getCharReturn.lc;
  360. }
  361. if ( lc >= l ) {
  362. if ( hufCode( encodingTable[ pl.p[ j ] ] ) == ( ( c >> ( lc - l ) ) & ( ( 1 << l ) - 1 ) ) ) {
  363. lc -= l;
  364. getCode( pl.p[ j ], rlc, c, lc, uInt8Array, inDataView, inOffset, outBuffer, outOffset, outBufferEndOffset );
  365. c = getCodeReturn.c;
  366. lc = getCodeReturn.lc;
  367. break;
  368. }
  369. }
  370. }
  371. if ( j == pl.lit ) {
  372. throw 'hufDecode issues';
  373. }
  374. }
  375. }
  376. }
  377. var i = ( 8 - ni ) & 7;
  378. c >>= i;
  379. lc -= i;
  380. while ( lc > 0 ) {
  381. var pl = decodingTable[ ( c << ( HUF_DECBITS - lc ) ) & HUF_DECMASK ];
  382. if ( pl.len ) {
  383. lc -= pl.len;
  384. getCode( pl.lit, rlc, c, lc, uInt8Array, inDataView, inOffset, outBuffer, outOffset, outBufferEndOffset );
  385. c = getCodeReturn.c;
  386. lc = getCodeReturn.lc;
  387. } else {
  388. throw 'hufDecode issues';
  389. }
  390. }
  391. return true;
  392. }
  393. function hufUncompress( uInt8Array, inDataView, inOffset, nCompressed, outBuffer, outOffset, nRaw ) {
  394. var initialInOffset = inOffset.value;
  395. var im = parseUint32( inDataView, inOffset );
  396. var iM = parseUint32( inDataView, inOffset );
  397. inOffset.value += 4;
  398. var nBits = parseUint32( inDataView, inOffset );
  399. inOffset.value += 4;
  400. if ( im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE ) {
  401. throw 'Something wrong with HUF_ENCSIZE';
  402. }
  403. var freq = new Array( HUF_ENCSIZE );
  404. var hdec = new Array( HUF_DECSIZE );
  405. hufClearDecTable( hdec );
  406. var ni = nCompressed - ( inOffset.value - initialInOffset );
  407. hufUnpackEncTable( uInt8Array, inDataView, inOffset, ni, im, iM, freq );
  408. if ( nBits > 8 * ( nCompressed - ( inOffset.value - initialInOffset ) ) ) {
  409. throw 'Something wrong with hufUncompress';
  410. }
  411. hufBuildDecTable( freq, im, iM, hdec );
  412. hufDecode( freq, hdec, uInt8Array, inDataView, inOffset, nBits, iM, nRaw, outBuffer, outOffset );
  413. }
  414. function applyLut( lut, data, nData ) {
  415. for ( var i = 0; i < nData; ++ i ) {
  416. data[ i ] = lut[ data[ i ] ];
  417. }
  418. }
  419. function decompressPIZ( outBuffer, outOffset, uInt8Array, inDataView, inOffset, tmpBufSize, num_channels, exrChannelInfos, dataWidth, num_lines ) {
  420. var bitmap = new Uint8Array( BITMAP_SIZE );
  421. var minNonZero = parseUint16( inDataView, inOffset );
  422. var maxNonZero = parseUint16( inDataView, inOffset );
  423. if ( maxNonZero >= BITMAP_SIZE ) {
  424. throw 'Something is wrong with PIZ_COMPRESSION BITMAP_SIZE';
  425. }
  426. if ( minNonZero <= maxNonZero ) {
  427. for ( var i = 0; i < maxNonZero - minNonZero + 1; i ++ ) {
  428. bitmap[ i + minNonZero ] = parseUint8( inDataView, inOffset );
  429. }
  430. }
  431. var lut = new Uint16Array( USHORT_RANGE );
  432. reverseLutFromBitmap( bitmap, lut );
  433. var length = parseUint32( inDataView, inOffset );
  434. hufUncompress( uInt8Array, inDataView, inOffset, length, outBuffer, outOffset, tmpBufSize );
  435. var pizChannelData = new Array( num_channels );
  436. var outBufferEnd = 0;
  437. for ( var i = 0; i < num_channels; i ++ ) {
  438. pizChannelData[ i ] = {};
  439. pizChannelData[ i ][ 'start' ] = outBufferEnd;
  440. pizChannelData[ i ][ 'end' ] = pizChannelData[ i ][ 'start' ];
  441. pizChannelData[ i ][ 'nx' ] = dataWidth;
  442. pizChannelData[ i ][ 'ny' ] = num_lines;
  443. pizChannelData[ i ][ 'size' ] = 1;
  444. outBufferEnd += pizChannelData[ i ].nx * pizChannelData[ i ].ny * pizChannelData[ i ].size;
  445. }
  446. var fooOffset = 0;
  447. for ( var i = 0; i < num_channels; i ++ ) {
  448. for ( var j = 0; j < pizChannelData[ i ].size; ++ j ) {
  449. fooOffset += wav2Decode(
  450. j + fooOffset,
  451. outBuffer,
  452. pizChannelData[ i ].nx,
  453. pizChannelData[ i ].size,
  454. pizChannelData[ i ].ny,
  455. pizChannelData[ i ].nx * pizChannelData[ i ].size
  456. );
  457. }
  458. }
  459. applyLut( lut, outBuffer, outBufferEnd );
  460. return true;
  461. }
  462. function parseNullTerminatedString( buffer, offset ) {
  463. var uintBuffer = new Uint8Array( buffer );
  464. var endOffset = 0;
  465. while ( uintBuffer[ offset.value + endOffset ] != 0 ) {
  466. endOffset += 1;
  467. }
  468. var stringValue = new TextDecoder().decode(
  469. uintBuffer.slice( offset.value, offset.value + endOffset )
  470. );
  471. offset.value = offset.value + endOffset + 1;
  472. return stringValue;
  473. }
  474. function parseFixedLengthString( buffer, offset, size ) {
  475. var stringValue = new TextDecoder().decode(
  476. new Uint8Array( buffer ).slice( offset.value, offset.value + size )
  477. );
  478. offset.value = offset.value + size;
  479. return stringValue;
  480. }
  481. function parseUlong( dataView, offset ) {
  482. var uLong = dataView.getUint32( 0, true );
  483. offset.value = offset.value + ULONG_SIZE;
  484. return uLong;
  485. }
  486. function parseUint32( dataView, offset ) {
  487. var Uint32 = dataView.getUint32( offset.value, true );
  488. offset.value = offset.value + INT32_SIZE;
  489. return Uint32;
  490. }
  491. function parseUint8Array( uInt8Array, offset ) {
  492. var Uint8 = uInt8Array[ offset.value ];
  493. offset.value = offset.value + INT8_SIZE;
  494. return Uint8;
  495. }
  496. function parseUint8( dataView, offset ) {
  497. var Uint8 = dataView.getUint8( offset.value );
  498. offset.value = offset.value + INT8_SIZE;
  499. return Uint8;
  500. }
  501. function parseFloat32( dataView, offset ) {
  502. var float = dataView.getFloat32( offset.value, true );
  503. offset.value += FLOAT32_SIZE;
  504. return float;
  505. }
  506. // https://stackoverflow.com/questions/5678432/decompressing-half-precision-floats-in-javascript
  507. function decodeFloat16( binary ) {
  508. var exponent = ( binary & 0x7C00 ) >> 10,
  509. fraction = binary & 0x03FF;
  510. return ( binary >> 15 ? - 1 : 1 ) * (
  511. exponent ?
  512. (
  513. exponent === 0x1F ?
  514. fraction ? NaN : Infinity :
  515. Math.pow( 2, exponent - 15 ) * ( 1 + fraction / 0x400 )
  516. ) :
  517. 6.103515625e-5 * ( fraction / 0x400 )
  518. );
  519. }
  520. function parseUint16( dataView, offset ) {
  521. var Uint16 = dataView.getUint16( offset.value, true );
  522. offset.value += INT16_SIZE;
  523. return Uint16;
  524. }
  525. function parseFloat16( buffer, offset ) {
  526. return decodeFloat16( parseUint16( buffer, offset ) );
  527. }
  528. function parseChlist( dataView, buffer, offset, size ) {
  529. var startOffset = offset.value;
  530. var channels = [];
  531. while ( offset.value < ( startOffset + size - 1 ) ) {
  532. var name = parseNullTerminatedString( buffer, offset );
  533. var pixelType = parseUint32( dataView, offset ); // TODO: Cast this to UINT, HALF or FLOAT
  534. var pLinear = parseUint8( dataView, offset );
  535. offset.value += 3; // reserved, three chars
  536. var xSampling = parseUint32( dataView, offset );
  537. var ySampling = parseUint32( dataView, offset );
  538. channels.push( {
  539. name: name,
  540. pixelType: pixelType,
  541. pLinear: pLinear,
  542. xSampling: xSampling,
  543. ySampling: ySampling
  544. } );
  545. }
  546. offset.value += 1;
  547. return channels;
  548. }
  549. function parseChromaticities( dataView, offset ) {
  550. var redX = parseFloat32( dataView, offset );
  551. var redY = parseFloat32( dataView, offset );
  552. var greenX = parseFloat32( dataView, offset );
  553. var greenY = parseFloat32( dataView, offset );
  554. var blueX = parseFloat32( dataView, offset );
  555. var blueY = parseFloat32( dataView, offset );
  556. var whiteX = parseFloat32( dataView, offset );
  557. var whiteY = parseFloat32( dataView, offset );
  558. return { redX: redX, redY: redY, greenX: greenX, greenY: greenY, blueX: blueX, blueY: blueY, whiteX: whiteX, whiteY: whiteY };
  559. }
  560. function parseCompression( dataView, offset ) {
  561. var compressionCodes = [
  562. 'NO_COMPRESSION',
  563. 'RLE_COMPRESSION',
  564. 'ZIPS_COMPRESSION',
  565. 'ZIP_COMPRESSION',
  566. 'PIZ_COMPRESSION',
  567. 'PXR24_COMPRESSION',
  568. 'B44_COMPRESSION',
  569. 'B44A_COMPRESSION',
  570. 'DWAA_COMPRESSION',
  571. 'DWAB_COMPRESSION'
  572. ];
  573. var compression = parseUint8( dataView, offset );
  574. return compressionCodes[ compression ];
  575. }
  576. function parseBox2i( dataView, offset ) {
  577. var xMin = parseUint32( dataView, offset );
  578. var yMin = parseUint32( dataView, offset );
  579. var xMax = parseUint32( dataView, offset );
  580. var yMax = parseUint32( dataView, offset );
  581. return { xMin: xMin, yMin: yMin, xMax: xMax, yMax: yMax };
  582. }
  583. function parseLineOrder( dataView, offset ) {
  584. var lineOrders = [
  585. 'INCREASING_Y'
  586. ];
  587. var lineOrder = parseUint8( dataView, offset );
  588. return lineOrders[ lineOrder ];
  589. }
  590. function parseV2f( dataView, offset ) {
  591. var x = parseFloat32( dataView, offset );
  592. var y = parseFloat32( dataView, offset );
  593. return [ x, y ];
  594. }
  595. function parseValue( dataView, buffer, offset, type, size ) {
  596. if ( type === 'string' || type === 'iccProfile' ) {
  597. return parseFixedLengthString( buffer, offset, size );
  598. } else if ( type === 'chlist' ) {
  599. return parseChlist( dataView, buffer, offset, size );
  600. } else if ( type === 'chromaticities' ) {
  601. return parseChromaticities( dataView, offset );
  602. } else if ( type === 'compression' ) {
  603. return parseCompression( dataView, offset );
  604. } else if ( type === 'box2i' ) {
  605. return parseBox2i( dataView, offset );
  606. } else if ( type === 'lineOrder' ) {
  607. return parseLineOrder( dataView, offset );
  608. } else if ( type === 'float' ) {
  609. return parseFloat32( dataView, offset );
  610. } else if ( type === 'v2f' ) {
  611. return parseV2f( dataView, offset );
  612. } else if ( type === 'int' ) {
  613. return parseUint32( dataView, offset );
  614. } else {
  615. throw 'Cannot parse value for unsupported type: ' + type;
  616. }
  617. }
  618. var bufferDataView = new DataView( buffer );
  619. var uInt8Array = new Uint8Array( buffer );
  620. var EXRHeader = {};
  621. bufferDataView.getUint32( 0, true ); // magic
  622. bufferDataView.getUint8( 4, true ); // versionByteZero
  623. bufferDataView.getUint8( 5, true ); // fullMask
  624. // start of header
  625. var offset = { value: 8 }; // start at 8, after magic stuff
  626. var keepReading = true;
  627. while ( keepReading ) {
  628. var attributeName = parseNullTerminatedString( buffer, offset );
  629. if ( attributeName == 0 ) {
  630. keepReading = false;
  631. } else {
  632. var attributeType = parseNullTerminatedString( buffer, offset );
  633. var attributeSize = parseUint32( bufferDataView, offset );
  634. var attributeValue = parseValue( bufferDataView, buffer, offset, attributeType, attributeSize );
  635. EXRHeader[ attributeName ] = attributeValue;
  636. }
  637. }
  638. // offsets
  639. var dataWindowHeight = EXRHeader.dataWindow.yMax + 1;
  640. var scanlineBlockSize = 1; // 1 for NO_COMPRESSION
  641. if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
  642. scanlineBlockSize = 32;
  643. }
  644. var numBlocks = dataWindowHeight / scanlineBlockSize;
  645. for ( var i = 0; i < numBlocks; i ++ ) {
  646. parseUlong( bufferDataView, offset ); // scanlineOffset
  647. }
  648. // we should be passed the scanline offset table, start reading pixel data
  649. var width = EXRHeader.dataWindow.xMax - EXRHeader.dataWindow.xMin + 1;
  650. var height = EXRHeader.dataWindow.yMax - EXRHeader.dataWindow.yMin + 1;
  651. var numChannels = EXRHeader.channels.length;
  652. var byteArray = new Float32Array( width * height * numChannels );
  653. var channelOffsets = {
  654. R: 0,
  655. G: 1,
  656. B: 2,
  657. A: 3
  658. };
  659. if ( EXRHeader.compression === 'NO_COMPRESSION' ) {
  660. for ( var y = 0; y < height; y ++ ) {
  661. var y_scanline = parseUint32( bufferDataView, offset );
  662. parseUint32( bufferDataView, offset ); // dataSize
  663. for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
  664. var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
  665. if ( EXRHeader.channels[ channelID ].pixelType === 1 ) {
  666. // HALF
  667. for ( var x = 0; x < width; x ++ ) {
  668. var val = parseFloat16( bufferDataView, offset );
  669. byteArray[ ( ( ( height - y_scanline ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
  670. }
  671. } else {
  672. throw 'EXRLoader._parser: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + '. Only pixelType is 1 (HALF) is supported.';
  673. }
  674. }
  675. }
  676. } else if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
  677. for ( var scanlineBlockIdx = 0; scanlineBlockIdx < height / scanlineBlockSize; scanlineBlockIdx ++ ) {
  678. parseUint32( bufferDataView, offset ); // line_no
  679. parseUint32( bufferDataView, offset ); // data_len
  680. var tmpBufferSize = width * scanlineBlockSize * ( EXRHeader.channels.length * BYTES_PER_HALF );
  681. var tmpBuffer = new Uint16Array( tmpBufferSize );
  682. var tmpOffset = { value: 0 };
  683. decompressPIZ( tmpBuffer, tmpOffset, uInt8Array, bufferDataView, offset, tmpBufferSize, numChannels, EXRHeader.channels, width, scanlineBlockSize );
  684. for ( var line_y = 0; line_y < scanlineBlockSize; line_y ++ ) {
  685. for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
  686. var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
  687. if ( EXRHeader.channels[ channelID ].pixelType === 1 ) {
  688. // HALF
  689. for ( var x = 0; x < width; x ++ ) {
  690. var val = decodeFloat16( tmpBuffer[ ( channelID * ( scanlineBlockSize * width ) ) + ( line_y * width ) + x ] );
  691. var true_y = line_y + ( scanlineBlockIdx * scanlineBlockSize );
  692. byteArray[ ( ( ( height - true_y ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
  693. }
  694. } else {
  695. throw 'EXRLoader._parser: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + '. Only pixelType is 1 (HALF) is supported.';
  696. }
  697. }
  698. }
  699. }
  700. } else {
  701. throw 'EXRLoader._parser: ' + EXRHeader.compression + ' is unsupported';
  702. }
  703. return {
  704. header: EXRHeader,
  705. width: width,
  706. height: height,
  707. data: byteArray,
  708. format: EXRHeader.channels.length == 4 ? RGBAFormat : RGBFormat,
  709. type: FloatType
  710. };
  711. };
  712. export { EXRLoader };