LercDecode.js 78 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112
  1. /* jshint forin: false, bitwise: false */
  2. /*
  3. Copyright 2015-2018 Esri
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. A copy of the license and additional notices are located with the
  14. source distribution at:
  15. http://github.com/Esri/lerc/
  16. Contributors: Johannes Schmid, (LERC v1)
  17. Chayanika Khatua, (LERC v1)
  18. Wenxue Ju (LERC v1, v2.x)
  19. */
  20. /* Copyright 2015-2018 Esri. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @preserve */
  21. /**
  22. * a module for decoding LERC blobs
  23. * @module Lerc
  24. */
  25. (function() {
  26. //the original LercDecode for Version 1
  27. var LercDecode = (function() {
  28. // WARNING: This decoder version can only read old version 1 Lerc blobs. Use with caution.
  29. // Note: currently, this module only has an implementation for decoding LERC data, not encoding. The name of
  30. // the class was chosen to be future proof.
  31. var CntZImage = {};
  32. CntZImage.defaultNoDataValue = -3.4027999387901484e+38; // smallest Float32 value
  33. /**
  34. * Decode a LERC byte stream and return an object containing the pixel data and some required and optional
  35. * information about it, such as the image's width and height.
  36. *
  37. * @param {ArrayBuffer} input The LERC input byte stream
  38. * @param {object} [options] Decoding options, containing any of the following properties:
  39. * @config {number} [inputOffset = 0]
  40. * Skip the first inputOffset bytes of the input byte stream. A valid LERC file is expected at that position.
  41. * @config {Uint8Array} [encodedMask = null]
  42. * If specified, the decoder will not read mask information from the input and use the specified encoded
  43. * mask data instead. Mask header/data must not be present in the LERC byte stream in this case.
  44. * @config {number} [noDataValue = LercCode.defaultNoDataValue]
  45. * Pixel value to use for masked pixels.
  46. * @config {ArrayBufferView|Array} [pixelType = Float32Array]
  47. * The desired type of the pixelData array in the return value. Note that it is the caller's responsibility to
  48. * provide an appropriate noDataValue if the default pixelType is overridden.
  49. * @config {boolean} [returnMask = false]
  50. * If true, the return value will contain a maskData property of type Uint8Array which has one element per
  51. * pixel, the value of which is 1 or 0 depending on whether that pixel's data is present or masked. If the
  52. * input LERC data does not contain a mask, maskData will not be returned.
  53. * @config {boolean} [returnEncodedMask = false]
  54. * If true, the return value will contain a encodedMaskData property, which can be passed into encode() as
  55. * encodedMask.
  56. * @config {boolean} [returnFileInfo = false]
  57. * If true, the return value will have a fileInfo property that contains metadata obtained from the
  58. * LERC headers and the decoding process.
  59. * @config {boolean} [computeUsedBitDepths = false]
  60. * If true, the fileInfo property in the return value will contain the set of all block bit depths
  61. * encountered during decoding. Will only have an effect if returnFileInfo option is true.
  62. * @returns {{width, height, pixelData, minValue, maxValue, noDataValue, maskData, encodedMaskData, fileInfo}}
  63. */
  64. CntZImage.decode = function(input, options) {
  65. options = options || {};
  66. var skipMask = options.encodedMaskData || (options.encodedMaskData === null);
  67. var parsedData = parse(input, options.inputOffset || 0, skipMask);
  68. var noDataValue = (options.noDataValue !== null) ? options.noDataValue : CntZImage.defaultNoDataValue;
  69. var uncompressedData = uncompressPixelValues(parsedData, options.pixelType || Float32Array,
  70. options.encodedMaskData, noDataValue, options.returnMask);
  71. var result = {
  72. width: parsedData.width,
  73. height: parsedData.height,
  74. pixelData: uncompressedData.resultPixels,
  75. minValue: uncompressedData.minValue,
  76. maxValue: parsedData.pixels.maxValue,
  77. noDataValue: noDataValue
  78. };
  79. if (uncompressedData.resultMask) {
  80. result.maskData = uncompressedData.resultMask;
  81. }
  82. if (options.returnEncodedMask && parsedData.mask) {
  83. result.encodedMaskData = parsedData.mask.bitset ? parsedData.mask.bitset : null;
  84. }
  85. if (options.returnFileInfo) {
  86. result.fileInfo = formatFileInfo(parsedData);
  87. if (options.computeUsedBitDepths) {
  88. result.fileInfo.bitDepths = computeUsedBitDepths(parsedData);
  89. }
  90. }
  91. return result;
  92. };
  93. var uncompressPixelValues = function(data, TypedArrayClass, maskBitset, noDataValue, storeDecodedMask) {
  94. var blockIdx = 0;
  95. var numX = data.pixels.numBlocksX;
  96. var numY = data.pixels.numBlocksY;
  97. var blockWidth = Math.floor(data.width / numX);
  98. var blockHeight = Math.floor(data.height / numY);
  99. var scale = 2 * data.maxZError;
  100. var minValue = Number.MAX_VALUE, currentValue;
  101. maskBitset = maskBitset || ((data.mask) ? data.mask.bitset : null);
  102. var resultPixels, resultMask;
  103. resultPixels = new TypedArrayClass(data.width * data.height);
  104. if (storeDecodedMask && maskBitset) {
  105. resultMask = new Uint8Array(data.width * data.height);
  106. }
  107. var blockDataBuffer = new Float32Array(blockWidth * blockHeight);
  108. var xx, yy;
  109. for (var y = 0; y <= numY; y++) {
  110. var thisBlockHeight = (y !== numY) ? blockHeight : (data.height % numY);
  111. if (thisBlockHeight === 0) {
  112. continue;
  113. }
  114. for (var x = 0; x <= numX; x++) {
  115. var thisBlockWidth = (x !== numX) ? blockWidth : (data.width % numX);
  116. if (thisBlockWidth === 0) {
  117. continue;
  118. }
  119. var outPtr = y * data.width * blockHeight + x * blockWidth;
  120. var outStride = data.width - thisBlockWidth;
  121. var block = data.pixels.blocks[blockIdx];
  122. var blockData, blockPtr, constValue;
  123. if (block.encoding < 2) {
  124. // block is either uncompressed or bit-stuffed (encodings 0 and 1)
  125. if (block.encoding === 0) {
  126. // block is uncompressed
  127. blockData = block.rawData;
  128. } else {
  129. // block is bit-stuffed
  130. unstuff(block.stuffedData, block.bitsPerPixel, block.numValidPixels, block.offset, scale, blockDataBuffer, data.pixels.maxValue);
  131. blockData = blockDataBuffer;
  132. }
  133. blockPtr = 0;
  134. }
  135. else if (block.encoding === 2) {
  136. // block is all 0
  137. constValue = 0;
  138. }
  139. else {
  140. // block has constant value (encoding === 3)
  141. constValue = block.offset;
  142. }
  143. var maskByte;
  144. if (maskBitset) {
  145. for (yy = 0; yy < thisBlockHeight; yy++) {
  146. if (outPtr & 7) {
  147. //
  148. maskByte = maskBitset[outPtr >> 3];
  149. maskByte <<= outPtr & 7;
  150. }
  151. for (xx = 0; xx < thisBlockWidth; xx++) {
  152. if (!(outPtr & 7)) {
  153. // read next byte from mask
  154. maskByte = maskBitset[outPtr >> 3];
  155. }
  156. if (maskByte & 128) {
  157. // pixel data present
  158. if (resultMask) {
  159. resultMask[outPtr] = 1;
  160. }
  161. currentValue = (block.encoding < 2) ? blockData[blockPtr++] : constValue;
  162. minValue = minValue > currentValue ? currentValue : minValue;
  163. resultPixels[outPtr++] = currentValue;
  164. } else {
  165. // pixel data not present
  166. if (resultMask) {
  167. resultMask[outPtr] = 0;
  168. }
  169. resultPixels[outPtr++] = noDataValue;
  170. }
  171. maskByte <<= 1;
  172. }
  173. outPtr += outStride;
  174. }
  175. } else {
  176. // mask not present, simply copy block over
  177. if (block.encoding < 2) {
  178. // duplicating this code block for performance reasons
  179. // blockData case:
  180. for (yy = 0; yy < thisBlockHeight; yy++) {
  181. for (xx = 0; xx < thisBlockWidth; xx++) {
  182. currentValue = blockData[blockPtr++];
  183. minValue = minValue > currentValue ? currentValue : minValue;
  184. resultPixels[outPtr++] = currentValue;
  185. }
  186. outPtr += outStride;
  187. }
  188. }
  189. else {
  190. // constValue case:
  191. minValue = minValue > constValue ? constValue : minValue;
  192. for (yy = 0; yy < thisBlockHeight; yy++) {
  193. for (xx = 0; xx < thisBlockWidth; xx++) {
  194. resultPixels[outPtr++] = constValue;
  195. }
  196. outPtr += outStride;
  197. }
  198. }
  199. }
  200. if ((block.encoding === 1) && (blockPtr !== block.numValidPixels)) {
  201. throw "Block and Mask do not match";
  202. }
  203. blockIdx++;
  204. }
  205. }
  206. return {
  207. resultPixels: resultPixels,
  208. resultMask: resultMask,
  209. minValue: minValue
  210. };
  211. };
  212. var formatFileInfo = function(data) {
  213. return {
  214. "fileIdentifierString": data.fileIdentifierString,
  215. "fileVersion": data.fileVersion,
  216. "imageType": data.imageType,
  217. "height": data.height,
  218. "width": data.width,
  219. "maxZError": data.maxZError,
  220. "eofOffset": data.eofOffset,
  221. "mask": data.mask ? {
  222. "numBlocksX": data.mask.numBlocksX,
  223. "numBlocksY": data.mask.numBlocksY,
  224. "numBytes": data.mask.numBytes,
  225. "maxValue": data.mask.maxValue
  226. } : null,
  227. "pixels": {
  228. "numBlocksX": data.pixels.numBlocksX,
  229. "numBlocksY": data.pixels.numBlocksY,
  230. "numBytes": data.pixels.numBytes,
  231. "maxValue": data.pixels.maxValue,
  232. "noDataValue": data.noDataValue
  233. }
  234. };
  235. };
  236. var computeUsedBitDepths = function(data) {
  237. var numBlocks = data.pixels.numBlocksX * data.pixels.numBlocksY;
  238. var bitDepths = {};
  239. for (var i = 0; i < numBlocks; i++) {
  240. var block = data.pixels.blocks[i];
  241. if (block.encoding === 0) {
  242. bitDepths.float32 = true;
  243. } else if (block.encoding === 1) {
  244. bitDepths[block.bitsPerPixel] = true;
  245. } else {
  246. bitDepths[0] = true;
  247. }
  248. }
  249. return Object.keys(bitDepths);
  250. };
  251. var parse = function(input, fp, skipMask) {
  252. var data = {};
  253. // File header
  254. var fileIdView = new Uint8Array(input, fp, 10);
  255. data.fileIdentifierString = String.fromCharCode.apply(null, fileIdView);
  256. if (data.fileIdentifierString.trim() !== "CntZImage") {
  257. throw "Unexpected file identifier string: " + data.fileIdentifierString;
  258. }
  259. fp += 10;
  260. var view = new DataView(input, fp, 24);
  261. data.fileVersion = view.getInt32(0, true);
  262. data.imageType = view.getInt32(4, true);
  263. data.height = view.getUint32(8, true);
  264. data.width = view.getUint32(12, true);
  265. data.maxZError = view.getFloat64(16, true);
  266. fp += 24;
  267. // Mask Header
  268. if (!skipMask) {
  269. view = new DataView(input, fp, 16);
  270. data.mask = {};
  271. data.mask.numBlocksY = view.getUint32(0, true);
  272. data.mask.numBlocksX = view.getUint32(4, true);
  273. data.mask.numBytes = view.getUint32(8, true);
  274. data.mask.maxValue = view.getFloat32(12, true);
  275. fp += 16;
  276. // Mask Data
  277. if (data.mask.numBytes > 0) {
  278. var bitset = new Uint8Array(Math.ceil(data.width * data.height / 8));
  279. view = new DataView(input, fp, data.mask.numBytes);
  280. var cnt = view.getInt16(0, true);
  281. var ip = 2, op = 0;
  282. do {
  283. if (cnt > 0) {
  284. while (cnt--) { bitset[op++] = view.getUint8(ip++); }
  285. } else {
  286. var val = view.getUint8(ip++);
  287. cnt = -cnt;
  288. while (cnt--) { bitset[op++] = val; }
  289. }
  290. cnt = view.getInt16(ip, true);
  291. ip += 2;
  292. } while (ip < data.mask.numBytes);
  293. if ((cnt !== -32768) || (op < bitset.length)) {
  294. throw "Unexpected end of mask RLE encoding";
  295. }
  296. data.mask.bitset = bitset;
  297. fp += data.mask.numBytes;
  298. }
  299. else if ((data.mask.numBytes | data.mask.numBlocksY | data.mask.maxValue) === 0) { // Special case, all nodata
  300. data.mask.bitset = new Uint8Array(Math.ceil(data.width * data.height / 8));
  301. }
  302. }
  303. // Pixel Header
  304. view = new DataView(input, fp, 16);
  305. data.pixels = {};
  306. data.pixels.numBlocksY = view.getUint32(0, true);
  307. data.pixels.numBlocksX = view.getUint32(4, true);
  308. data.pixels.numBytes = view.getUint32(8, true);
  309. data.pixels.maxValue = view.getFloat32(12, true);
  310. fp += 16;
  311. var numBlocksX = data.pixels.numBlocksX;
  312. var numBlocksY = data.pixels.numBlocksY;
  313. // the number of blocks specified in the header does not take into account the blocks at the end of
  314. // each row/column with a special width/height that make the image complete in case the width is not
  315. // evenly divisible by the number of blocks.
  316. var actualNumBlocksX = numBlocksX + ((data.width % numBlocksX) > 0 ? 1 : 0);
  317. var actualNumBlocksY = numBlocksY + ((data.height % numBlocksY) > 0 ? 1 : 0);
  318. data.pixels.blocks = new Array(actualNumBlocksX * actualNumBlocksY);
  319. var blockI = 0;
  320. for (var blockY = 0; blockY < actualNumBlocksY; blockY++) {
  321. for (var blockX = 0; blockX < actualNumBlocksX; blockX++) {
  322. // Block
  323. var size = 0;
  324. var bytesLeft = input.byteLength - fp;
  325. view = new DataView(input, fp, Math.min(10, bytesLeft));
  326. var block = {};
  327. data.pixels.blocks[blockI++] = block;
  328. var headerByte = view.getUint8(0); size++;
  329. block.encoding = headerByte & 63;
  330. if (block.encoding > 3) {
  331. throw "Invalid block encoding (" + block.encoding + ")";
  332. }
  333. if (block.encoding === 2) {
  334. fp++;
  335. continue;
  336. }
  337. if ((headerByte !== 0) && (headerByte !== 2)) {
  338. headerByte >>= 6;
  339. block.offsetType = headerByte;
  340. if (headerByte === 2) {
  341. block.offset = view.getInt8(1); size++;
  342. } else if (headerByte === 1) {
  343. block.offset = view.getInt16(1, true); size += 2;
  344. } else if (headerByte === 0) {
  345. block.offset = view.getFloat32(1, true); size += 4;
  346. } else {
  347. throw "Invalid block offset type";
  348. }
  349. if (block.encoding === 1) {
  350. headerByte = view.getUint8(size); size++;
  351. block.bitsPerPixel = headerByte & 63;
  352. headerByte >>= 6;
  353. block.numValidPixelsType = headerByte;
  354. if (headerByte === 2) {
  355. block.numValidPixels = view.getUint8(size); size++;
  356. } else if (headerByte === 1) {
  357. block.numValidPixels = view.getUint16(size, true); size += 2;
  358. } else if (headerByte === 0) {
  359. block.numValidPixels = view.getUint32(size, true); size += 4;
  360. } else {
  361. throw "Invalid valid pixel count type";
  362. }
  363. }
  364. }
  365. fp += size;
  366. if (block.encoding === 3) {
  367. continue;
  368. }
  369. var arrayBuf, store8;
  370. if (block.encoding === 0) {
  371. var numPixels = (data.pixels.numBytes - 1) / 4;
  372. if (numPixels !== Math.floor(numPixels)) {
  373. throw "uncompressed block has invalid length";
  374. }
  375. arrayBuf = new ArrayBuffer(numPixels * 4);
  376. store8 = new Uint8Array(arrayBuf);
  377. store8.set(new Uint8Array(input, fp, numPixels * 4));
  378. var rawData = new Float32Array(arrayBuf);
  379. block.rawData = rawData;
  380. fp += numPixels * 4;
  381. } else if (block.encoding === 1) {
  382. var dataBytes = Math.ceil(block.numValidPixels * block.bitsPerPixel / 8);
  383. var dataWords = Math.ceil(dataBytes / 4);
  384. arrayBuf = new ArrayBuffer(dataWords * 4);
  385. store8 = new Uint8Array(arrayBuf);
  386. store8.set(new Uint8Array(input, fp, dataBytes));
  387. block.stuffedData = new Uint32Array(arrayBuf);
  388. fp += dataBytes;
  389. }
  390. }
  391. }
  392. data.eofOffset = fp;
  393. return data;
  394. };
  395. var unstuff = function(src, bitsPerPixel, numPixels, offset, scale, dest, maxValue) {
  396. var bitMask = (1 << bitsPerPixel) - 1;
  397. var i = 0, o;
  398. var bitsLeft = 0;
  399. var n, buffer;
  400. var nmax = Math.ceil((maxValue - offset) / scale);
  401. // get rid of trailing bytes that are already part of next block
  402. var numInvalidTailBytes = src.length * 4 - Math.ceil(bitsPerPixel * numPixels / 8);
  403. src[src.length - 1] <<= 8 * numInvalidTailBytes;
  404. for (o = 0; o < numPixels; o++) {
  405. if (bitsLeft === 0) {
  406. buffer = src[i++];
  407. bitsLeft = 32;
  408. }
  409. if (bitsLeft >= bitsPerPixel) {
  410. n = (buffer >>> (bitsLeft - bitsPerPixel)) & bitMask;
  411. bitsLeft -= bitsPerPixel;
  412. } else {
  413. var missingBits = (bitsPerPixel - bitsLeft);
  414. n = ((buffer & bitMask) << missingBits) & bitMask;
  415. buffer = src[i++];
  416. bitsLeft = 32 - missingBits;
  417. n += (buffer >>> bitsLeft);
  418. }
  419. //pixel values may exceed max due to quantization
  420. dest[o] = n < nmax ? offset + n * scale : maxValue;
  421. }
  422. return dest;
  423. };
  424. return CntZImage;
  425. })();
  426. //version 2. Supports 2.1, 2.2, 2.3
  427. var Lerc2Decode = (function() {
  428. "use strict";
  429. // Note: currently, this module only has an implementation for decoding LERC data, not encoding. The name of
  430. // the class was chosen to be future proof, following LercDecode.
  431. /*****************************************
  432. * private static class bitsutffer used by Lerc2Decode
  433. *******************************************/
  434. var BitStuffer = {
  435. //methods ending with 2 are for the new byte order used by Lerc2.3 and above.
  436. //originalUnstuff is used to unpack Huffman code table. code is duplicated to unstuffx for performance reasons.
  437. unstuff: function(src, dest, bitsPerPixel, numPixels, lutArr, offset, scale, maxValue) {
  438. var bitMask = (1 << bitsPerPixel) - 1;
  439. var i = 0, o;
  440. var bitsLeft = 0;
  441. var n, buffer, missingBits, nmax;
  442. // get rid of trailing bytes that are already part of next block
  443. var numInvalidTailBytes = src.length * 4 - Math.ceil(bitsPerPixel * numPixels / 8);
  444. src[src.length - 1] <<= 8 * numInvalidTailBytes;
  445. if (lutArr) {
  446. for (o = 0; o < numPixels; o++) {
  447. if (bitsLeft === 0) {
  448. buffer = src[i++];
  449. bitsLeft = 32;
  450. }
  451. if (bitsLeft >= bitsPerPixel) {
  452. n = (buffer >>> (bitsLeft - bitsPerPixel)) & bitMask;
  453. bitsLeft -= bitsPerPixel;
  454. }
  455. else {
  456. missingBits = (bitsPerPixel - bitsLeft);
  457. n = ((buffer & bitMask) << missingBits) & bitMask;
  458. buffer = src[i++];
  459. bitsLeft = 32 - missingBits;
  460. n += (buffer >>> bitsLeft);
  461. }
  462. dest[o] = lutArr[n];//offset + lutArr[n] * scale;
  463. }
  464. }
  465. else {
  466. nmax = Math.ceil((maxValue - offset) / scale);
  467. for (o = 0; o < numPixels; o++) {
  468. if (bitsLeft === 0) {
  469. buffer = src[i++];
  470. bitsLeft = 32;
  471. }
  472. if (bitsLeft >= bitsPerPixel) {
  473. n = (buffer >>> (bitsLeft - bitsPerPixel)) & bitMask;
  474. bitsLeft -= bitsPerPixel;
  475. }
  476. else {
  477. missingBits = (bitsPerPixel - bitsLeft);
  478. n = ((buffer & bitMask) << missingBits) & bitMask;
  479. buffer = src[i++];
  480. bitsLeft = 32 - missingBits;
  481. n += (buffer >>> bitsLeft);
  482. }
  483. //pixel values may exceed max due to quantization
  484. dest[o] = n < nmax ? offset + n * scale : maxValue;
  485. }
  486. }
  487. },
  488. unstuffLUT: function(src, bitsPerPixel, numPixels, offset, scale, maxValue) {
  489. var bitMask = (1 << bitsPerPixel) - 1;
  490. var i = 0, o = 0, missingBits = 0, bitsLeft = 0, n = 0;
  491. var buffer;
  492. var dest = [];
  493. // get rid of trailing bytes that are already part of next block
  494. var numInvalidTailBytes = src.length * 4 - Math.ceil(bitsPerPixel * numPixels / 8);
  495. src[src.length - 1] <<= 8 * numInvalidTailBytes;
  496. var nmax = Math.ceil((maxValue - offset) / scale);
  497. for (o = 0; o < numPixels; o++) {
  498. if (bitsLeft === 0) {
  499. buffer = src[i++];
  500. bitsLeft = 32;
  501. }
  502. if (bitsLeft >= bitsPerPixel) {
  503. n = (buffer >>> (bitsLeft - bitsPerPixel)) & bitMask;
  504. bitsLeft -= bitsPerPixel;
  505. } else {
  506. missingBits = (bitsPerPixel - bitsLeft);
  507. n = ((buffer & bitMask) << missingBits) & bitMask;
  508. buffer = src[i++];
  509. bitsLeft = 32 - missingBits;
  510. n += (buffer >>> bitsLeft);
  511. }
  512. //dest.push(n);
  513. dest[o] = n < nmax ? offset + n * scale : maxValue;
  514. }
  515. dest.unshift(offset);//1st one
  516. return dest;
  517. },
  518. unstuff2: function(src, dest, bitsPerPixel, numPixels, lutArr, offset, scale, maxValue) {
  519. var bitMask = (1 << bitsPerPixel) - 1;
  520. var i = 0, o;
  521. var bitsLeft = 0, bitPos = 0;
  522. var n, buffer, missingBits;
  523. if (lutArr) {
  524. for (o = 0; o < numPixels; o++) {
  525. if (bitsLeft === 0) {
  526. buffer = src[i++];
  527. bitsLeft = 32;
  528. bitPos = 0;
  529. }
  530. if (bitsLeft >= bitsPerPixel) {
  531. n = ((buffer >>> bitPos) & bitMask);
  532. bitsLeft -= bitsPerPixel;
  533. bitPos += bitsPerPixel;
  534. } else {
  535. missingBits = (bitsPerPixel - bitsLeft);
  536. n = (buffer >>> bitPos) & bitMask;
  537. buffer = src[i++];
  538. bitsLeft = 32 - missingBits;
  539. n |= (buffer & ((1 << missingBits) - 1)) << (bitsPerPixel - missingBits);
  540. bitPos = missingBits;
  541. }
  542. dest[o] = lutArr[n];
  543. }
  544. }
  545. else {
  546. var nmax = Math.ceil((maxValue - offset) / scale);
  547. for (o = 0; o < numPixels; o++) {
  548. if (bitsLeft === 0) {
  549. buffer = src[i++];
  550. bitsLeft = 32;
  551. bitPos = 0;
  552. }
  553. if (bitsLeft >= bitsPerPixel) {
  554. //no unsigned left shift
  555. n = ((buffer >>> bitPos) & bitMask);
  556. bitsLeft -= bitsPerPixel;
  557. bitPos += bitsPerPixel;
  558. } else {
  559. missingBits = (bitsPerPixel - bitsLeft);
  560. n = (buffer >>> bitPos) & bitMask;//((buffer & bitMask) << missingBits) & bitMask;
  561. buffer = src[i++];
  562. bitsLeft = 32 - missingBits;
  563. n |= (buffer & ((1 << missingBits) - 1)) << (bitsPerPixel - missingBits);
  564. bitPos = missingBits;
  565. }
  566. //pixel values may exceed max due to quantization
  567. dest[o] = n < nmax ? offset + n * scale : maxValue;
  568. }
  569. }
  570. return dest;
  571. },
  572. unstuffLUT2: function(src, bitsPerPixel, numPixels, offset, scale, maxValue) {
  573. var bitMask = (1 << bitsPerPixel) - 1;
  574. var i = 0, o = 0, missingBits = 0, bitsLeft = 0, n = 0, bitPos = 0;
  575. var buffer;
  576. var dest = [];
  577. var nmax = Math.ceil((maxValue - offset) / scale);
  578. for (o = 0; o < numPixels; o++) {
  579. if (bitsLeft === 0) {
  580. buffer = src[i++];
  581. bitsLeft = 32;
  582. bitPos = 0;
  583. }
  584. if (bitsLeft >= bitsPerPixel) {
  585. //no unsigned left shift
  586. n = ((buffer >>> bitPos) & bitMask);
  587. bitsLeft -= bitsPerPixel;
  588. bitPos += bitsPerPixel;
  589. } else {
  590. missingBits = (bitsPerPixel - bitsLeft);
  591. n = (buffer >>> bitPos) & bitMask;//((buffer & bitMask) << missingBits) & bitMask;
  592. buffer = src[i++];
  593. bitsLeft = 32 - missingBits;
  594. n |= (buffer & ((1 << missingBits) - 1)) << (bitsPerPixel - missingBits);
  595. bitPos = missingBits;
  596. }
  597. //dest.push(n);
  598. dest[o] = n < nmax ? offset + n * scale : maxValue;
  599. }
  600. dest.unshift(offset);
  601. return dest;
  602. },
  603. originalUnstuff: function(src, dest, bitsPerPixel, numPixels) {
  604. var bitMask = (1 << bitsPerPixel) - 1;
  605. var i = 0, o;
  606. var bitsLeft = 0;
  607. var n, buffer, missingBits;
  608. // get rid of trailing bytes that are already part of next block
  609. var numInvalidTailBytes = src.length * 4 - Math.ceil(bitsPerPixel * numPixels / 8);
  610. src[src.length - 1] <<= 8 * numInvalidTailBytes;
  611. for (o = 0; o < numPixels; o++) {
  612. if (bitsLeft === 0) {
  613. buffer = src[i++];
  614. bitsLeft = 32;
  615. }
  616. if (bitsLeft >= bitsPerPixel) {
  617. n = (buffer >>> (bitsLeft - bitsPerPixel)) & bitMask;
  618. bitsLeft -= bitsPerPixel;
  619. }
  620. else {
  621. missingBits = (bitsPerPixel - bitsLeft);
  622. n = ((buffer & bitMask) << missingBits) & bitMask;
  623. buffer = src[i++];
  624. bitsLeft = 32 - missingBits;
  625. n += (buffer >>> bitsLeft);
  626. }
  627. dest[o] = n;
  628. }
  629. return dest;
  630. },
  631. originalUnstuff2: function(src, dest, bitsPerPixel, numPixels) {
  632. var bitMask = (1 << bitsPerPixel) - 1;
  633. var i = 0, o;
  634. var bitsLeft = 0, bitPos = 0;
  635. var n, buffer, missingBits;
  636. //micro-optimizations
  637. for (o = 0; o < numPixels; o++) {
  638. if (bitsLeft === 0) {
  639. buffer = src[i++];
  640. bitsLeft = 32;
  641. bitPos = 0;
  642. }
  643. if (bitsLeft >= bitsPerPixel) {
  644. //no unsigned left shift
  645. n = ((buffer >>> bitPos) & bitMask);
  646. bitsLeft -= bitsPerPixel;
  647. bitPos += bitsPerPixel;
  648. } else {
  649. missingBits = (bitsPerPixel - bitsLeft);
  650. n = (buffer >>> bitPos) & bitMask;//((buffer & bitMask) << missingBits) & bitMask;
  651. buffer = src[i++];
  652. bitsLeft = 32 - missingBits;
  653. n |= (buffer & ((1 << missingBits) - 1)) << (bitsPerPixel - missingBits);
  654. bitPos = missingBits;
  655. }
  656. dest[o] = n;
  657. }
  658. return dest;
  659. }
  660. };
  661. /*****************************************
  662. *private static class used by Lerc2Decode
  663. ******************************************/
  664. var Lerc2Helpers = {
  665. HUFFMAN_LUT_BITS_MAX: 12, //use 2^12 lut, treat it like constant
  666. computeChecksumFletcher32: function(input) {
  667. var sum1 = 0xffff, sum2 = 0xffff;
  668. var len = input.length;
  669. var words = Math.floor(len / 2);
  670. var i = 0;
  671. while (words) {
  672. var tlen = (words >= 359) ? 359 : words;
  673. words -= tlen;
  674. do {
  675. sum1 += (input[i++] << 8);
  676. sum2 += sum1 += input[i++];
  677. } while (--tlen);
  678. sum1 = (sum1 & 0xffff) + (sum1 >>> 16);
  679. sum2 = (sum2 & 0xffff) + (sum2 >>> 16);
  680. }
  681. // add the straggler byte if it exists
  682. if (len & 1) {
  683. sum2 += sum1 += (input[i] << 8);
  684. }
  685. // second reduction step to reduce sums to 16 bits
  686. sum1 = (sum1 & 0xffff) + (sum1 >>> 16);
  687. sum2 = (sum2 & 0xffff) + (sum2 >>> 16);
  688. return (sum2 << 16 | sum1) >>> 0;
  689. },
  690. readHeaderInfo: function(input, data) {
  691. var ptr = data.ptr;
  692. var fileIdView = new Uint8Array(input, ptr, 6);
  693. var headerInfo = {};
  694. headerInfo.fileIdentifierString = String.fromCharCode.apply(null, fileIdView);
  695. if (headerInfo.fileIdentifierString.lastIndexOf("Lerc2", 0) !== 0) {
  696. throw "Unexpected file identifier string (expect Lerc2 ): " + headerInfo.fileIdentifierString;
  697. }
  698. ptr += 6;
  699. var view = new DataView(input, ptr, 8);
  700. var fileVersion = view.getInt32(0, true);
  701. headerInfo.fileVersion = fileVersion;
  702. ptr += 4;
  703. if (fileVersion >= 3) {
  704. headerInfo.checksum = view.getUint32(4, true); //nrows
  705. ptr += 4;
  706. }
  707. //keys start from here
  708. view = new DataView(input, ptr, 12);
  709. headerInfo.height = view.getUint32(0, true); //nrows
  710. headerInfo.width = view.getUint32(4, true); //ncols
  711. ptr += 8;
  712. if (fileVersion >= 4) {
  713. headerInfo.numDims = view.getUint32(8, true);
  714. ptr += 4;
  715. }
  716. else {
  717. headerInfo.numDims = 1;
  718. }
  719. view = new DataView(input, ptr, 40);
  720. headerInfo.numValidPixel = view.getUint32(0, true);
  721. headerInfo.microBlockSize = view.getInt32(4, true);
  722. headerInfo.blobSize = view.getInt32(8, true);
  723. headerInfo.imageType = view.getInt32(12, true);
  724. headerInfo.maxZError = view.getFloat64(16, true);
  725. headerInfo.zMin = view.getFloat64(24, true);
  726. headerInfo.zMax = view.getFloat64(32, true);
  727. ptr += 40;
  728. data.headerInfo = headerInfo;
  729. data.ptr = ptr;
  730. var checksum, keyLength;
  731. if (fileVersion >= 3) {
  732. keyLength = fileVersion >= 4 ? 52 : 48;
  733. checksum = this.computeChecksumFletcher32(new Uint8Array(input, ptr - keyLength, headerInfo.blobSize - 14));
  734. if (checksum !== headerInfo.checksum) {
  735. throw "Checksum failed.";
  736. }
  737. }
  738. return true;
  739. },
  740. checkMinMaxRanges: function(input, data) {
  741. var headerInfo = data.headerInfo;
  742. var OutPixelTypeArray = this.getDataTypeArray(headerInfo.imageType);
  743. var rangeBytes = headerInfo.numDims * this.getDataTypeSize(headerInfo.imageType);
  744. var minValues = this.readSubArray(input, data.ptr, OutPixelTypeArray, rangeBytes);
  745. var maxValues = this.readSubArray(input, data.ptr + rangeBytes, OutPixelTypeArray, rangeBytes);
  746. data.ptr += (2 * rangeBytes);
  747. var i, equal = true;
  748. for (i = 0; i < headerInfo.numDims; i++) {
  749. if (minValues[i] !== maxValues[i]) {
  750. equal = false;
  751. break;
  752. }
  753. }
  754. headerInfo.minValues = minValues;
  755. headerInfo.maxValues = maxValues;
  756. return equal;
  757. },
  758. readSubArray: function(input, ptr, OutPixelTypeArray, numBytes) {
  759. var rawData;
  760. if (OutPixelTypeArray === Uint8Array) {
  761. rawData = new Uint8Array(input, ptr, numBytes);
  762. }
  763. else {
  764. var arrayBuf = new ArrayBuffer(numBytes);
  765. var store8 = new Uint8Array(arrayBuf);
  766. store8.set(new Uint8Array(input, ptr, numBytes));
  767. rawData = new OutPixelTypeArray(arrayBuf);
  768. }
  769. return rawData;
  770. },
  771. readMask: function(input, data) {
  772. var ptr = data.ptr;
  773. var headerInfo = data.headerInfo;
  774. var numPixels = headerInfo.width * headerInfo.height;
  775. var numValidPixel = headerInfo.numValidPixel;
  776. var view = new DataView(input, ptr, 4);
  777. var mask = {};
  778. mask.numBytes = view.getUint32(0, true);
  779. ptr += 4;
  780. // Mask Data
  781. if ((0 === numValidPixel || numPixels === numValidPixel) && 0 !== mask.numBytes) {
  782. throw ("invalid mask");
  783. }
  784. var bitset, resultMask;
  785. if (numValidPixel === 0) {
  786. bitset = new Uint8Array(Math.ceil(numPixels / 8));
  787. mask.bitset = bitset;
  788. resultMask = new Uint8Array(numPixels);
  789. data.pixels.resultMask = resultMask;
  790. ptr += mask.numBytes;
  791. }// ????? else if (data.mask.numBytes > 0 && data.mask.numBytes< data.numValidPixel) {
  792. else if (mask.numBytes > 0) {
  793. bitset = new Uint8Array(Math.ceil(numPixels / 8));
  794. view = new DataView(input, ptr, mask.numBytes);
  795. var cnt = view.getInt16(0, true);
  796. var ip = 2, op = 0, val = 0;
  797. do {
  798. if (cnt > 0) {
  799. while (cnt--) { bitset[op++] = view.getUint8(ip++); }
  800. } else {
  801. val = view.getUint8(ip++);
  802. cnt = -cnt;
  803. while (cnt--) { bitset[op++] = val; }
  804. }
  805. cnt = view.getInt16(ip, true);
  806. ip += 2;
  807. } while (ip < mask.numBytes);
  808. if ((cnt !== -32768) || (op < bitset.length)) {
  809. throw "Unexpected end of mask RLE encoding";
  810. }
  811. resultMask = new Uint8Array(numPixels);
  812. var mb = 0, k = 0;
  813. for (k = 0; k < numPixels; k++) {
  814. if (k & 7) {
  815. mb = bitset[k >> 3];
  816. mb <<= k & 7;
  817. }
  818. else {
  819. mb = bitset[k >> 3];
  820. }
  821. if (mb & 128) {
  822. resultMask[k] = 1;
  823. }
  824. }
  825. data.pixels.resultMask = resultMask;
  826. mask.bitset = bitset;
  827. ptr += mask.numBytes;
  828. }
  829. data.ptr = ptr;
  830. data.mask = mask;
  831. return true;
  832. },
  833. readDataOneSweep: function(input, data, OutPixelTypeArray) {
  834. var ptr = data.ptr;
  835. var headerInfo = data.headerInfo;
  836. var numDims = headerInfo.numDims;
  837. var numPixels = headerInfo.width * headerInfo.height;
  838. var imageType = headerInfo.imageType;
  839. var numBytes = headerInfo.numValidPixel * Lerc2Helpers.getDataTypeSize(imageType) * numDims;
  840. //data.pixels.numBytes = numBytes;
  841. var rawData;
  842. var mask = data.pixels.resultMask;
  843. if (OutPixelTypeArray === Uint8Array) {
  844. rawData = new Uint8Array(input, ptr, numBytes);
  845. }
  846. else {
  847. var arrayBuf = new ArrayBuffer(numBytes);
  848. var store8 = new Uint8Array(arrayBuf);
  849. store8.set(new Uint8Array(input, ptr, numBytes));
  850. rawData = new OutPixelTypeArray(arrayBuf);
  851. }
  852. if (rawData.length === numPixels * numDims) {
  853. data.pixels.resultPixels = rawData;
  854. }
  855. else //mask
  856. {
  857. data.pixels.resultPixels = new OutPixelTypeArray(numPixels * numDims);
  858. var z = 0, k = 0, i = 0, nStart = 0;
  859. if (numDims > 1) {
  860. for (i=0; i < numDims; i++) {
  861. nStart = i * numPixels;
  862. for (k = 0; k < numPixels; k++) {
  863. if (mask[k]) {
  864. data.pixels.resultPixels[nStart + k] = rawData[z++];
  865. }
  866. }
  867. }
  868. }
  869. else {
  870. for (k = 0; k < numPixels; k++) {
  871. if (mask[k]) {
  872. data.pixels.resultPixels[k] = rawData[z++];
  873. }
  874. }
  875. }
  876. }
  877. ptr += numBytes;
  878. data.ptr = ptr; //return data;
  879. return true;
  880. },
  881. readHuffmanTree: function(input, data) {
  882. var BITS_MAX = this.HUFFMAN_LUT_BITS_MAX; //8 is slow for the large test image
  883. //var size_max = 1 << BITS_MAX;
  884. /* ************************
  885. * reading code table
  886. *************************/
  887. var view = new DataView(input, data.ptr, 16);
  888. data.ptr += 16;
  889. var version = view.getInt32(0, true);
  890. if (version < 2) {
  891. throw "unsupported Huffman version";
  892. }
  893. var size = view.getInt32(4, true);
  894. var i0 = view.getInt32(8, true);
  895. var i1 = view.getInt32(12, true);
  896. if (i0 >= i1) {
  897. return false;
  898. }
  899. var blockDataBuffer = new Uint32Array(i1 - i0);
  900. Lerc2Helpers.decodeBits(input, data, blockDataBuffer);
  901. var codeTable = []; //size
  902. var i, j, k, len;
  903. for (i = i0; i < i1; i++) {
  904. j = i - (i < size ? 0 : size);//wrap around
  905. codeTable[j] = { first: blockDataBuffer[i - i0], second: null };
  906. }
  907. var dataBytes = input.byteLength - data.ptr;
  908. var dataWords = Math.ceil(dataBytes / 4);
  909. var arrayBuf = new ArrayBuffer(dataWords * 4);
  910. var store8 = new Uint8Array(arrayBuf);
  911. store8.set(new Uint8Array(input, data.ptr, dataBytes));
  912. var stuffedData = new Uint32Array(arrayBuf); //must start from x*4
  913. var bitPos = 0, word, srcPtr = 0;
  914. word = stuffedData[0];
  915. for (i = i0; i < i1; i++) {
  916. j = i - (i < size ? 0 : size);//wrap around
  917. len = codeTable[j].first;
  918. if (len > 0) {
  919. codeTable[j].second = (word << bitPos) >>> (32 - len);
  920. if (32 - bitPos >= len) {
  921. bitPos += len;
  922. if (bitPos === 32) {
  923. bitPos = 0;
  924. srcPtr++;
  925. word = stuffedData[srcPtr];
  926. }
  927. }
  928. else {
  929. bitPos += len - 32;
  930. srcPtr++;
  931. word = stuffedData[srcPtr];
  932. codeTable[j].second |= word >>> (32 - bitPos);
  933. }
  934. }
  935. }
  936. //finished reading code table
  937. /* ************************
  938. * building lut
  939. *************************/
  940. var numBitsLUT = 0, numBitsLUTQick = 0;
  941. var tree = new TreeNode();
  942. for (i = 0; i < codeTable.length; i++) {
  943. if (codeTable[i] !== undefined) {
  944. numBitsLUT = Math.max(numBitsLUT, codeTable[i].first);
  945. }
  946. }
  947. if (numBitsLUT >= BITS_MAX) {
  948. numBitsLUTQick = BITS_MAX;
  949. }
  950. else {
  951. numBitsLUTQick = numBitsLUT;
  952. }
  953. if (numBitsLUT >= 30) {
  954. console.log("WARning, large NUM LUT BITS IS " + numBitsLUT);
  955. }
  956. var decodeLut = [], entry, code, numEntries, jj, currentBit, node;
  957. for (i = i0; i < i1; i++) {
  958. j = i - (i < size ? 0 : size);//wrap around
  959. len = codeTable[j].first;
  960. if (len > 0) {
  961. entry = [len, j];
  962. if (len <= numBitsLUTQick) {
  963. code = codeTable[j].second << (numBitsLUTQick - len);
  964. numEntries = 1 << (numBitsLUTQick - len);
  965. for (k = 0; k < numEntries; k++) {
  966. decodeLut[code | k] = entry;
  967. }
  968. }
  969. else {
  970. //build tree
  971. code = codeTable[j].second;
  972. node = tree;
  973. for (jj = len - 1; jj >= 0; jj--) {
  974. currentBit = code >>> jj & 1; //no left shift as length could be 30,31
  975. if (currentBit) {
  976. if (!node.right) {
  977. node.right = new TreeNode();
  978. }
  979. node = node.right;
  980. }
  981. else {
  982. if (!node.left) {
  983. node.left = new TreeNode();
  984. }
  985. node = node.left;
  986. }
  987. if (jj === 0 && !node.val) {
  988. node.val = entry[1];
  989. }
  990. }
  991. }
  992. }
  993. }
  994. return {
  995. decodeLut: decodeLut,
  996. numBitsLUTQick: numBitsLUTQick,
  997. numBitsLUT: numBitsLUT,
  998. tree: tree,
  999. stuffedData: stuffedData,
  1000. srcPtr: srcPtr,
  1001. bitPos: bitPos
  1002. };
  1003. },
  1004. readHuffman: function(input, data, OutPixelTypeArray) {
  1005. var headerInfo = data.headerInfo;
  1006. var numDims = headerInfo.numDims;
  1007. var height = data.headerInfo.height;
  1008. var width = data.headerInfo.width;
  1009. var numPixels = width * height;
  1010. //var size_max = 1 << BITS_MAX;
  1011. /* ************************
  1012. * reading huffman structure info
  1013. *************************/
  1014. var huffmanInfo = this.readHuffmanTree(input, data);
  1015. var decodeLut = huffmanInfo.decodeLut;
  1016. var tree = huffmanInfo.tree;
  1017. //stuffedData includes huffman headers
  1018. var stuffedData = huffmanInfo.stuffedData;
  1019. var srcPtr = huffmanInfo.srcPtr;
  1020. var bitPos = huffmanInfo.bitPos;
  1021. var numBitsLUTQick = huffmanInfo.numBitsLUTQick;
  1022. var numBitsLUT = huffmanInfo.numBitsLUT;
  1023. var offset = data.headerInfo.imageType === 0 ? 128 : 0;
  1024. /*************************
  1025. * decode
  1026. ***************************/
  1027. var node, val, delta, mask = data.pixels.resultMask, valTmp, valTmpQuick, currentBit;
  1028. var i, j, k, ii;
  1029. var prevVal = 0;
  1030. if (bitPos > 0) {
  1031. srcPtr++;
  1032. bitPos = 0;
  1033. }
  1034. var word = stuffedData[srcPtr];
  1035. var deltaEncode = data.encodeMode === 1;
  1036. var resultPixelsAllDim = new OutPixelTypeArray(numPixels * numDims);
  1037. var resultPixels = resultPixelsAllDim;
  1038. var iDim;
  1039. for (iDim = 0; iDim < headerInfo.numDims; iDim++) {
  1040. if (numDims > 1) {
  1041. //get the mem block of current dimension
  1042. resultPixels = new OutPixelTypeArray(resultPixelsAllDim.buffer, numPixels * iDim, numPixels);
  1043. prevVal = 0;
  1044. }
  1045. if (data.headerInfo.numValidPixel === width * height) { //all valid
  1046. for (k = 0, i = 0; i < height; i++) {
  1047. for (j = 0; j < width; j++, k++) {
  1048. val = 0;
  1049. valTmp = (word << bitPos) >>> (32 - numBitsLUTQick);
  1050. valTmpQuick = valTmp;// >>> deltaBits;
  1051. if (32 - bitPos < numBitsLUTQick) {
  1052. valTmp |= ((stuffedData[srcPtr + 1]) >>> (64 - bitPos - numBitsLUTQick));
  1053. valTmpQuick = valTmp;// >>> deltaBits;
  1054. }
  1055. if (decodeLut[valTmpQuick]) // if there, move the correct number of bits and done
  1056. {
  1057. val = decodeLut[valTmpQuick][1];
  1058. bitPos += decodeLut[valTmpQuick][0];
  1059. }
  1060. else {
  1061. valTmp = (word << bitPos) >>> (32 - numBitsLUT);
  1062. valTmpQuick = valTmp;// >>> deltaBits;
  1063. if (32 - bitPos < numBitsLUT) {
  1064. valTmp |= ((stuffedData[srcPtr + 1]) >>> (64 - bitPos - numBitsLUT));
  1065. valTmpQuick = valTmp;// >>> deltaBits;
  1066. }
  1067. node = tree;
  1068. for (ii = 0; ii < numBitsLUT; ii++) {
  1069. currentBit = valTmp >>> (numBitsLUT - ii - 1) & 1;
  1070. node = currentBit ? node.right : node.left;
  1071. if (!(node.left || node.right)) {
  1072. val = node.val;
  1073. bitPos = bitPos + ii + 1;
  1074. break;
  1075. }
  1076. }
  1077. }
  1078. if (bitPos >= 32) {
  1079. bitPos -= 32;
  1080. srcPtr++;
  1081. word = stuffedData[srcPtr];
  1082. }
  1083. delta = val - offset;
  1084. if (deltaEncode) {
  1085. if (j > 0) {
  1086. delta += prevVal; // use overflow
  1087. }
  1088. else if (i > 0) {
  1089. delta += resultPixels[k - width];
  1090. }
  1091. else {
  1092. delta += prevVal;
  1093. }
  1094. delta &= 0xFF; //overflow
  1095. resultPixels[k] = delta;//overflow
  1096. prevVal = delta;
  1097. }
  1098. else {
  1099. resultPixels[k] = delta;
  1100. }
  1101. }
  1102. }
  1103. }
  1104. else { //not all valid, use mask
  1105. for (k = 0, i = 0; i < height; i++) {
  1106. for (j = 0; j < width; j++, k++) {
  1107. if (mask[k]) {
  1108. val = 0;
  1109. valTmp = (word << bitPos) >>> (32 - numBitsLUTQick);
  1110. valTmpQuick = valTmp;// >>> deltaBits;
  1111. if (32 - bitPos < numBitsLUTQick) {
  1112. valTmp |= ((stuffedData[srcPtr + 1]) >>> (64 - bitPos - numBitsLUTQick));
  1113. valTmpQuick = valTmp;// >>> deltaBits;
  1114. }
  1115. if (decodeLut[valTmpQuick]) // if there, move the correct number of bits and done
  1116. {
  1117. val = decodeLut[valTmpQuick][1];
  1118. bitPos += decodeLut[valTmpQuick][0];
  1119. }
  1120. else {
  1121. valTmp = (word << bitPos) >>> (32 - numBitsLUT);
  1122. valTmpQuick = valTmp;// >>> deltaBits;
  1123. if (32 - bitPos < numBitsLUT) {
  1124. valTmp |= ((stuffedData[srcPtr + 1]) >>> (64 - bitPos - numBitsLUT));
  1125. valTmpQuick = valTmp;// >>> deltaBits;
  1126. }
  1127. node = tree;
  1128. for (ii = 0; ii < numBitsLUT; ii++) {
  1129. currentBit = valTmp >>> (numBitsLUT - ii - 1) & 1;
  1130. node = currentBit ? node.right : node.left;
  1131. if (!(node.left || node.right)) {
  1132. val = node.val;
  1133. bitPos = bitPos + ii + 1;
  1134. break;
  1135. }
  1136. }
  1137. }
  1138. if (bitPos >= 32) {
  1139. bitPos -= 32;
  1140. srcPtr++;
  1141. word = stuffedData[srcPtr];
  1142. }
  1143. delta = val - offset;
  1144. if (deltaEncode) {
  1145. if (j > 0 && mask[k - 1]) {
  1146. delta += prevVal; // use overflow
  1147. }
  1148. else if (i > 0 && mask[k - width]) {
  1149. delta += resultPixels[k - width];
  1150. }
  1151. else {
  1152. delta += prevVal;
  1153. }
  1154. delta &= 0xFF; //overflow
  1155. resultPixels[k] = delta;//overflow
  1156. prevVal = delta;
  1157. }
  1158. else {
  1159. resultPixels[k] = delta;
  1160. }
  1161. }
  1162. }
  1163. }
  1164. }
  1165. data.ptr = data.ptr + (srcPtr + 1) * 4 + (bitPos > 0 ? 4 : 0);
  1166. }
  1167. data.pixels.resultPixels = resultPixelsAllDim;
  1168. },
  1169. decodeBits: function(input, data, blockDataBuffer, offset, iDim) {
  1170. {
  1171. //bitstuff encoding is 3
  1172. var headerInfo = data.headerInfo;
  1173. var fileVersion = headerInfo.fileVersion;
  1174. //var block = {};
  1175. var blockPtr = 0;
  1176. var view = new DataView(input, data.ptr, 5);//to do
  1177. var headerByte = view.getUint8(0);
  1178. blockPtr++;
  1179. var bits67 = headerByte >> 6;
  1180. var n = (bits67 === 0) ? 4 : 3 - bits67;
  1181. var doLut = (headerByte & 32) > 0 ? true : false;//5th bit
  1182. var numBits = headerByte & 31;
  1183. var numElements = 0;
  1184. if (n === 1) {
  1185. numElements = view.getUint8(blockPtr); blockPtr++;
  1186. } else if (n === 2) {
  1187. numElements = view.getUint16(blockPtr, true); blockPtr += 2;
  1188. } else if (n === 4) {
  1189. numElements = view.getUint32(blockPtr, true); blockPtr += 4;
  1190. } else {
  1191. throw "Invalid valid pixel count type";
  1192. }
  1193. //fix: huffman codes are bit stuffed, but not bound by data's max value, so need to use originalUnstuff
  1194. //offset = offset || 0;
  1195. var scale = 2 * headerInfo.maxZError;
  1196. var stuffedData, arrayBuf, store8, dataBytes, dataWords;
  1197. var lutArr, lutData, lutBytes, lutBitsPerElement, bitsPerPixel;
  1198. var zMax = headerInfo.numDims > 1 ? headerInfo.maxValues[iDim] : headerInfo.zMax;
  1199. if (doLut) {
  1200. data.counter.lut++;
  1201. lutBytes = view.getUint8(blockPtr);
  1202. lutBitsPerElement = numBits;
  1203. blockPtr++;
  1204. dataBytes = Math.ceil((lutBytes - 1) * numBits / 8);
  1205. dataWords = Math.ceil(dataBytes / 4);
  1206. arrayBuf = new ArrayBuffer(dataWords * 4);
  1207. store8 = new Uint8Array(arrayBuf);
  1208. data.ptr += blockPtr;
  1209. store8.set(new Uint8Array(input, data.ptr, dataBytes));
  1210. lutData = new Uint32Array(arrayBuf);
  1211. data.ptr += dataBytes;
  1212. bitsPerPixel = 0;
  1213. while ((lutBytes - 1) >>> bitsPerPixel) {
  1214. bitsPerPixel++;
  1215. }
  1216. dataBytes = Math.ceil(numElements * bitsPerPixel / 8);
  1217. dataWords = Math.ceil(dataBytes / 4);
  1218. arrayBuf = new ArrayBuffer(dataWords * 4);
  1219. store8 = new Uint8Array(arrayBuf);
  1220. store8.set(new Uint8Array(input, data.ptr, dataBytes));
  1221. stuffedData = new Uint32Array(arrayBuf);
  1222. data.ptr += dataBytes;
  1223. if (fileVersion >= 3) {
  1224. lutArr = BitStuffer.unstuffLUT2(lutData, numBits, lutBytes - 1, offset, scale, zMax);
  1225. }
  1226. else {
  1227. lutArr = BitStuffer.unstuffLUT(lutData, numBits, lutBytes - 1, offset, scale, zMax);
  1228. }
  1229. //lutArr.unshift(0);
  1230. if (fileVersion >= 3) {
  1231. //BitStuffer.unstuff2(block, blockDataBuffer, headerInfo.zMax);
  1232. BitStuffer.unstuff2(stuffedData, blockDataBuffer, bitsPerPixel, numElements, lutArr);
  1233. }
  1234. else {
  1235. BitStuffer.unstuff(stuffedData, blockDataBuffer, bitsPerPixel, numElements, lutArr);
  1236. }
  1237. }
  1238. else {
  1239. //console.debug("bitstuffer");
  1240. data.counter.bitstuffer++;
  1241. bitsPerPixel = numBits;
  1242. data.ptr += blockPtr;
  1243. if (bitsPerPixel > 0) {
  1244. dataBytes = Math.ceil(numElements * bitsPerPixel / 8);
  1245. dataWords = Math.ceil(dataBytes / 4);
  1246. arrayBuf = new ArrayBuffer(dataWords * 4);
  1247. store8 = new Uint8Array(arrayBuf);
  1248. store8.set(new Uint8Array(input, data.ptr, dataBytes));
  1249. stuffedData = new Uint32Array(arrayBuf);
  1250. data.ptr += dataBytes;
  1251. if (fileVersion >= 3) {
  1252. if (offset == null) {
  1253. BitStuffer.originalUnstuff2(stuffedData, blockDataBuffer, bitsPerPixel, numElements);
  1254. }
  1255. else {
  1256. BitStuffer.unstuff2(stuffedData, blockDataBuffer, bitsPerPixel, numElements, false, offset, scale, zMax);
  1257. }
  1258. }
  1259. else {
  1260. if (offset == null) {
  1261. BitStuffer.originalUnstuff(stuffedData, blockDataBuffer, bitsPerPixel, numElements);
  1262. }
  1263. else {
  1264. BitStuffer.unstuff(stuffedData, blockDataBuffer, bitsPerPixel, numElements, false, offset, scale, zMax);
  1265. }
  1266. }
  1267. }
  1268. }
  1269. }
  1270. },
  1271. readTiles: function(input, data, OutPixelTypeArray) {
  1272. var headerInfo = data.headerInfo;
  1273. var width = headerInfo.width;
  1274. var height = headerInfo.height;
  1275. var microBlockSize = headerInfo.microBlockSize;
  1276. var imageType = headerInfo.imageType;
  1277. var dataTypeSize = Lerc2Helpers.getDataTypeSize(imageType);
  1278. var numBlocksX = Math.ceil(width / microBlockSize);
  1279. var numBlocksY = Math.ceil(height / microBlockSize);
  1280. data.pixels.numBlocksY = numBlocksY;
  1281. data.pixels.numBlocksX = numBlocksX;
  1282. data.pixels.ptr = 0;
  1283. var row = 0, col = 0, blockY = 0, blockX = 0, thisBlockHeight = 0, thisBlockWidth = 0, bytesLeft = 0, headerByte = 0, bits67 = 0, testCode = 0, outPtr = 0, outStride = 0, numBytes = 0, bytesleft = 0, z = 0, blockPtr = 0;
  1284. var view, block, arrayBuf, store8, rawData;
  1285. var blockEncoding;
  1286. var blockDataBuffer = new OutPixelTypeArray(microBlockSize * microBlockSize);
  1287. var lastBlockHeight = (height % microBlockSize) || microBlockSize;
  1288. var lastBlockWidth = (width % microBlockSize) || microBlockSize;
  1289. var offsetType, offset;
  1290. var numDims = headerInfo.numDims, iDim;
  1291. var mask = data.pixels.resultMask;
  1292. var resultPixels = data.pixels.resultPixels;
  1293. for (blockY = 0; blockY < numBlocksY; blockY++) {
  1294. thisBlockHeight = (blockY !== numBlocksY - 1) ? microBlockSize : lastBlockHeight;
  1295. for (blockX = 0; blockX < numBlocksX; blockX++) {
  1296. //console.debug("y" + blockY + " x" + blockX);
  1297. thisBlockWidth = (blockX !== numBlocksX - 1) ? microBlockSize : lastBlockWidth;
  1298. outPtr = blockY * width * microBlockSize + blockX * microBlockSize;
  1299. outStride = width - thisBlockWidth;
  1300. for (iDim = 0; iDim < numDims; iDim++) {
  1301. if (numDims > 1) {
  1302. resultPixels = new OutPixelTypeArray(data.pixels.resultPixels.buffer, width * height * iDim * dataTypeSize, width * height);
  1303. }
  1304. bytesLeft = input.byteLength - data.ptr;
  1305. view = new DataView(input, data.ptr, Math.min(10, bytesLeft));
  1306. block = {};
  1307. blockPtr = 0;
  1308. headerByte = view.getUint8(0);
  1309. blockPtr++;
  1310. bits67 = (headerByte >> 6) & 0xFF;
  1311. testCode = (headerByte >> 2) & 15; // use bits 2345 for integrity check
  1312. if (testCode !== (((blockX * microBlockSize) >> 3) & 15)) {
  1313. throw "integrity issue";
  1314. //return false;
  1315. }
  1316. blockEncoding = headerByte & 3;
  1317. if (blockEncoding > 3) {
  1318. data.ptr += blockPtr;
  1319. throw "Invalid block encoding (" + blockEncoding + ")";
  1320. }
  1321. else if (blockEncoding === 2) { //constant 0
  1322. data.counter.constant++;
  1323. data.ptr += blockPtr;
  1324. continue;
  1325. }
  1326. else if (blockEncoding === 0) { //uncompressed
  1327. data.counter.uncompressed++;
  1328. data.ptr += blockPtr;
  1329. numBytes = thisBlockHeight * thisBlockWidth * dataTypeSize;
  1330. bytesleft = input.byteLength - data.ptr;
  1331. numBytes = numBytes < bytesleft ? numBytes : bytesleft;
  1332. //bit alignment
  1333. arrayBuf = new ArrayBuffer((numBytes % dataTypeSize) === 0 ? numBytes : (numBytes + dataTypeSize - numBytes % dataTypeSize));
  1334. store8 = new Uint8Array(arrayBuf);
  1335. store8.set(new Uint8Array(input, data.ptr, numBytes));
  1336. rawData = new OutPixelTypeArray(arrayBuf);
  1337. z = 0;
  1338. if (mask) {
  1339. for (row = 0; row < thisBlockHeight; row++) {
  1340. for (col = 0; col < thisBlockWidth; col++) {
  1341. if (mask[outPtr]) {
  1342. resultPixels[outPtr] = rawData[z++];
  1343. }
  1344. outPtr++;
  1345. }
  1346. outPtr += outStride;
  1347. }
  1348. }
  1349. else {//all valid
  1350. for (row = 0; row < thisBlockHeight; row++) {
  1351. for (col = 0; col < thisBlockWidth; col++) {
  1352. resultPixels[outPtr++] = rawData[z++];
  1353. }
  1354. outPtr += outStride;
  1355. }
  1356. }
  1357. data.ptr += z * dataTypeSize;
  1358. }
  1359. else { //1 or 3
  1360. offsetType = Lerc2Helpers.getDataTypeUsed(imageType, bits67);
  1361. offset = Lerc2Helpers.getOnePixel(block, blockPtr, offsetType, view);
  1362. blockPtr += Lerc2Helpers.getDataTypeSize(offsetType);
  1363. if (blockEncoding === 3) //constant offset value
  1364. {
  1365. data.ptr += blockPtr;
  1366. data.counter.constantoffset++;
  1367. //you can delete the following resultMask case in favor of performance because val is constant and users use nodata mask, otherwise nodatavalue post processing handles it too.
  1368. //while the above statement is true, we're not doing it as we want to keep invalid pixel value at 0 rather than arbitrary values
  1369. if (mask) {
  1370. for (row = 0; row < thisBlockHeight; row++) {
  1371. for (col = 0; col < thisBlockWidth; col++) {
  1372. if (mask[outPtr]) {
  1373. resultPixels[outPtr] = offset;
  1374. }
  1375. outPtr++;
  1376. }
  1377. outPtr += outStride;
  1378. }
  1379. }
  1380. else {
  1381. for (row = 0; row < thisBlockHeight; row++) {
  1382. for (col = 0; col < thisBlockWidth; col++) {
  1383. resultPixels[outPtr++] = offset;
  1384. }
  1385. outPtr += outStride;
  1386. }
  1387. }
  1388. }
  1389. else { //bitstuff encoding is 3
  1390. data.ptr += blockPtr;
  1391. //heavy lifting
  1392. Lerc2Helpers.decodeBits(input, data, blockDataBuffer, offset, iDim);
  1393. blockPtr = 0;
  1394. if (mask) {
  1395. for (row = 0; row < thisBlockHeight; row++) {
  1396. for (col = 0; col < thisBlockWidth; col++) {
  1397. if (mask[outPtr]) {
  1398. resultPixels[outPtr] = blockDataBuffer[blockPtr++];
  1399. }
  1400. outPtr++;
  1401. }
  1402. outPtr += outStride;
  1403. }
  1404. }
  1405. else {
  1406. for (row = 0; row < thisBlockHeight; row++) {
  1407. for (col = 0; col < thisBlockWidth; col++) {
  1408. resultPixels[outPtr++] = blockDataBuffer[blockPtr++];
  1409. }
  1410. outPtr += outStride;
  1411. }
  1412. }
  1413. }
  1414. }
  1415. }
  1416. }
  1417. }
  1418. },
  1419. /*****************
  1420. * private methods (helper methods)
  1421. *****************/
  1422. formatFileInfo: function(data) {
  1423. return {
  1424. "fileIdentifierString": data.headerInfo.fileIdentifierString,
  1425. "fileVersion": data.headerInfo.fileVersion,
  1426. "imageType": data.headerInfo.imageType,
  1427. "height": data.headerInfo.height,
  1428. "width": data.headerInfo.width,
  1429. "numValidPixel": data.headerInfo.numValidPixel,
  1430. "microBlockSize": data.headerInfo.microBlockSize,
  1431. "blobSize": data.headerInfo.blobSize,
  1432. "maxZError": data.headerInfo.maxZError,
  1433. "pixelType": Lerc2Helpers.getPixelType(data.headerInfo.imageType),
  1434. "eofOffset": data.eofOffset,
  1435. "mask": data.mask ? {
  1436. "numBytes": data.mask.numBytes
  1437. } : null,
  1438. "pixels": {
  1439. "numBlocksX": data.pixels.numBlocksX,
  1440. "numBlocksY": data.pixels.numBlocksY,
  1441. //"numBytes": data.pixels.numBytes,
  1442. "maxValue": data.headerInfo.zMax,
  1443. "minValue": data.headerInfo.zMin,
  1444. "noDataValue": data.noDataValue
  1445. }
  1446. };
  1447. },
  1448. constructConstantSurface: function(data) {
  1449. var val = data.headerInfo.zMax;
  1450. var numDims = data.headerInfo.numDims;
  1451. var numPixels = data.headerInfo.height * data.headerInfo.width;
  1452. var numPixelAllDims = numPixels * numDims;
  1453. var i=0, k = 0, nStart=0;
  1454. var mask = data.pixels.resultMask;
  1455. if (mask) {
  1456. if (numDims > 1) {
  1457. for (i=0; i < numDims; i++) {
  1458. nStart = i * numPixels;
  1459. for (k = 0; k < numPixels; k++) {
  1460. if (mask[k]) {
  1461. data.pixels.resultPixels[nStart + k] = val;
  1462. }
  1463. }
  1464. }
  1465. }
  1466. else {
  1467. for (k = 0; k < numPixels; k++) {
  1468. if (mask[k]) {
  1469. data.pixels.resultPixels[k] = val;
  1470. }
  1471. }
  1472. }
  1473. }
  1474. else {
  1475. if (data.pixels.resultPixels.fill) {
  1476. data.pixels.resultPixels.fill(val);
  1477. }
  1478. else {
  1479. for (k = 0; k < numPixelAllDims; k++) {
  1480. data.pixels.resultPixels[k] = val;
  1481. }
  1482. }
  1483. }
  1484. return;
  1485. },
  1486. getDataTypeArray: function(t) {
  1487. var tp;
  1488. switch (t) {
  1489. case 0: //char
  1490. tp = Int8Array;
  1491. break;
  1492. case 1: //byte
  1493. tp = Uint8Array;
  1494. break;
  1495. case 2: //short
  1496. tp = Int16Array;
  1497. break;
  1498. case 3: //ushort
  1499. tp = Uint16Array;
  1500. break;
  1501. case 4:
  1502. tp = Int32Array;
  1503. break;
  1504. case 5:
  1505. tp = Uint32Array;
  1506. break;
  1507. case 6:
  1508. tp = Float32Array;
  1509. break;
  1510. case 7:
  1511. tp = Float64Array;
  1512. break;
  1513. default:
  1514. tp = Float32Array;
  1515. }
  1516. return tp;
  1517. },
  1518. getPixelType: function(t) {
  1519. var tp;
  1520. switch (t) {
  1521. case 0: //char
  1522. tp = "S8";
  1523. break;
  1524. case 1: //byte
  1525. tp = "U8";
  1526. break;
  1527. case 2: //short
  1528. tp = "S16";
  1529. break;
  1530. case 3: //ushort
  1531. tp = "U16";
  1532. break;
  1533. case 4:
  1534. tp = "S32";
  1535. break;
  1536. case 5:
  1537. tp = "U32";
  1538. break;
  1539. case 6:
  1540. tp = "F32";
  1541. break;
  1542. case 7:
  1543. tp = "F64"; //not supported
  1544. break;
  1545. default:
  1546. tp = "F32";
  1547. }
  1548. return tp;
  1549. },
  1550. isValidPixelValue: function(t, val) {
  1551. if (val == null) {
  1552. return false;
  1553. }
  1554. var isValid;
  1555. switch (t) {
  1556. case 0: //char
  1557. isValid = val >= -128 && val <= 127;
  1558. break;
  1559. case 1: //byte (unsigned char)
  1560. isValid = val >= 0 && val <= 255;
  1561. break;
  1562. case 2: //short
  1563. isValid = val >= -32768 && val <= 32767;
  1564. break;
  1565. case 3: //ushort
  1566. isValid = val >= 0 && val <= 65536;
  1567. break;
  1568. case 4: //int 32
  1569. isValid = val >= -2147483648 && val <= 2147483647;
  1570. break;
  1571. case 5: //uinit 32
  1572. isValid = val >= 0 && val <= 4294967296;
  1573. break;
  1574. case 6:
  1575. isValid = val >= -3.4027999387901484e+38 && val <= 3.4027999387901484e+38;
  1576. break;
  1577. case 7:
  1578. isValid = val >= 5e-324 && val <= 1.7976931348623157e+308;
  1579. break;
  1580. default:
  1581. isValid = false;
  1582. }
  1583. return isValid;
  1584. },
  1585. getDataTypeSize: function(t) {
  1586. var s = 0;
  1587. switch (t) {
  1588. case 0: //ubyte
  1589. case 1: //byte
  1590. s = 1;
  1591. break;
  1592. case 2: //short
  1593. case 3: //ushort
  1594. s = 2;
  1595. break;
  1596. case 4:
  1597. case 5:
  1598. case 6:
  1599. s = 4;
  1600. break;
  1601. case 7:
  1602. s = 8;
  1603. break;
  1604. default:
  1605. s = t;
  1606. }
  1607. return s;
  1608. },
  1609. getDataTypeUsed: function(dt, tc) {
  1610. var t = dt;
  1611. switch (dt) {
  1612. case 2: //short
  1613. case 4: //long
  1614. t = dt - tc;
  1615. break;
  1616. case 3: //ushort
  1617. case 5: //ulong
  1618. t = dt - 2 * tc;
  1619. break;
  1620. case 6: //float
  1621. if (0 === tc) {
  1622. t = dt;
  1623. }
  1624. else if (1 === tc) {
  1625. t = 2;
  1626. }
  1627. else {
  1628. t = 1;//byte
  1629. }
  1630. break;
  1631. case 7: //double
  1632. if (0 === tc) {
  1633. t = dt;
  1634. }
  1635. else {
  1636. t = dt - 2 * tc + 1;
  1637. }
  1638. break;
  1639. default:
  1640. t = dt;
  1641. break;
  1642. }
  1643. return t;
  1644. },
  1645. getOnePixel: function(block, blockPtr, offsetType, view) {
  1646. var temp = 0;
  1647. switch (offsetType) {
  1648. case 0: //char
  1649. temp = view.getInt8(blockPtr);
  1650. break;
  1651. case 1: //byte
  1652. temp = view.getUint8(blockPtr);
  1653. break;
  1654. case 2:
  1655. temp = view.getInt16(blockPtr, true);
  1656. break;
  1657. case 3:
  1658. temp = view.getUint16(blockPtr, true);
  1659. break;
  1660. case 4:
  1661. temp = view.getInt32(blockPtr, true);
  1662. break;
  1663. case 5:
  1664. temp = view.getUInt32(blockPtr, true);
  1665. break;
  1666. case 6:
  1667. temp = view.getFloat32(blockPtr, true);
  1668. break;
  1669. case 7:
  1670. //temp = view.getFloat64(blockPtr, true);
  1671. //blockPtr += 8;
  1672. //lerc2 encoding doesnt handle float 64, force to float32???
  1673. temp = view.getFloat64(blockPtr, true);
  1674. break;
  1675. default:
  1676. throw ("the decoder does not understand this pixel type");
  1677. }
  1678. return temp;
  1679. }
  1680. };
  1681. /***************************************************
  1682. *private class for a tree node. Huffman code is in Lerc2Helpers
  1683. ****************************************************/
  1684. var TreeNode = function(val, left, right) {
  1685. this.val = val;
  1686. this.left = left;
  1687. this.right = right;
  1688. };
  1689. var Lerc2Decode = {
  1690. /*
  1691. * ********removed options compared to LERC1. We can bring some of them back if needed.
  1692. * removed pixel type. LERC2 is typed and doesn't require user to give pixel type
  1693. * changed encodedMaskData to maskData. LERC2 's js version make it faster to use maskData directly.
  1694. * removed returnMask. mask is used by LERC2 internally and is cost free. In case of user input mask, it's returned as well and has neglible cost.
  1695. * removed nodatavalue. Because LERC2 pixels are typed, nodatavalue will sacrify a useful value for many types (8bit, 16bit) etc,
  1696. * user has to be knowledgable enough about raster and their data to avoid usability issues. so nodata value is simply removed now.
  1697. * We can add it back later if their's a clear requirement.
  1698. * removed encodedMask. This option was not implemented in LercDecode. It can be done after decoding (less efficient)
  1699. * removed computeUsedBitDepths.
  1700. *
  1701. *
  1702. * response changes compared to LERC1
  1703. * 1. encodedMaskData is not available
  1704. * 2. noDataValue is optional (returns only if user's noDataValue is with in the valid data type range)
  1705. * 3. maskData is always available
  1706. */
  1707. /*****************
  1708. * public properties
  1709. ******************/
  1710. //HUFFMAN_LUT_BITS_MAX: 12, //use 2^12 lut, not configurable
  1711. /*****************
  1712. * public methods
  1713. *****************/
  1714. /**
  1715. * Decode a LERC2 byte stream and return an object containing the pixel data and optional metadata.
  1716. *
  1717. * @param {ArrayBuffer} input The LERC input byte stream
  1718. * @param {object} [options] options Decoding options
  1719. * @param {number} [options.inputOffset] The number of bytes to skip in the input byte stream. A valid LERC file is expected at that position
  1720. * @param {boolean} [options.returnFileInfo] If true, the return value will have a fileInfo property that contains metadata obtained from the LERC headers and the decoding process
  1721. */
  1722. decode: function(/*byte array*/ input, /*object*/ options) {
  1723. //currently there's a bug in the sparse array, so please do not set to false
  1724. options = options || {};
  1725. var noDataValue = options.noDataValue;
  1726. //initialize
  1727. var i = 0, data = {};
  1728. data.ptr = options.inputOffset || 0;
  1729. data.pixels = {};
  1730. // File header
  1731. if (!Lerc2Helpers.readHeaderInfo(input, data)) {
  1732. return;
  1733. }
  1734. var headerInfo = data.headerInfo;
  1735. var fileVersion = headerInfo.fileVersion;
  1736. var OutPixelTypeArray = Lerc2Helpers.getDataTypeArray(headerInfo.imageType);
  1737. // Mask Header
  1738. Lerc2Helpers.readMask(input, data);
  1739. if (headerInfo.numValidPixel !== headerInfo.width * headerInfo.height && !data.pixels.resultMask) {
  1740. data.pixels.resultMask = options.maskData;
  1741. }
  1742. var numPixels = headerInfo.width * headerInfo.height;
  1743. data.pixels.resultPixels = new OutPixelTypeArray(numPixels * headerInfo.numDims);
  1744. data.counter = {
  1745. onesweep: 0,
  1746. uncompressed: 0,
  1747. lut: 0,
  1748. bitstuffer: 0,
  1749. constant: 0,
  1750. constantoffset: 0
  1751. };
  1752. if (headerInfo.numValidPixel !== 0) {
  1753. //not tested
  1754. if (headerInfo.zMax === headerInfo.zMin) //constant surface
  1755. {
  1756. Lerc2Helpers.constructConstantSurface(data);
  1757. }
  1758. else if (fileVersion >= 4 && Lerc2Helpers.checkMinMaxRanges(input, data)) {
  1759. Lerc2Helpers.constructConstantSurface(data);
  1760. }
  1761. else {
  1762. var view = new DataView(input, data.ptr, 2);
  1763. var bReadDataOneSweep = view.getUint8(0);
  1764. data.ptr++;
  1765. if (bReadDataOneSweep) {
  1766. //console.debug("OneSweep");
  1767. Lerc2Helpers.readDataOneSweep(input, data, OutPixelTypeArray);
  1768. }
  1769. else {
  1770. //lerc2.1: //bitstuffing + lut
  1771. //lerc2.2: //bitstuffing + lut + huffman
  1772. //lerc2.3: new bitstuffer
  1773. if (fileVersion > 1 && headerInfo.imageType <= 1 && Math.abs(headerInfo.maxZError - 0.5) < 0.00001) {
  1774. //this is 2.x plus 8 bit (unsigned and signed) data, possiblity of Huffman
  1775. var flagHuffman = view.getUint8(1);
  1776. data.ptr++;
  1777. data.encodeMode = flagHuffman;
  1778. if (flagHuffman > 2 || (fileVersion < 4 && flagHuffman > 1)) {
  1779. throw "Invalid Huffman flag " + flagHuffman;
  1780. }
  1781. if (flagHuffman) {//1 - delta Huffman, 2 - Huffman
  1782. //console.log("Huffman");
  1783. Lerc2Helpers.readHuffman(input, data, OutPixelTypeArray);
  1784. }
  1785. else {
  1786. //console.log("Tiles");
  1787. Lerc2Helpers.readTiles(input, data, OutPixelTypeArray);
  1788. }
  1789. }
  1790. else { //lerc2.x non-8 bit data
  1791. //console.log("Tiles");
  1792. Lerc2Helpers.readTiles(input, data, OutPixelTypeArray);
  1793. }
  1794. }
  1795. }
  1796. }
  1797. data.eofOffset = data.ptr;
  1798. var diff;
  1799. if (options.inputOffset) {
  1800. diff = data.headerInfo.blobSize + options.inputOffset - data.ptr;
  1801. if (Math.abs(diff) >= 1) {
  1802. //console.debug("incorrect eof: dataptr " + data.ptr + " offset " + options.inputOffset + " blobsize " + data.headerInfo.blobSize + " diff: " + diff);
  1803. data.eofOffset = options.inputOffset + data.headerInfo.blobSize;
  1804. }
  1805. }
  1806. else {
  1807. diff = data.headerInfo.blobSize - data.ptr;
  1808. if (Math.abs(diff) >= 1) {
  1809. //console.debug("incorrect first band eof: dataptr " + data.ptr + " blobsize " + data.headerInfo.blobSize + " diff: " + diff);
  1810. data.eofOffset = data.headerInfo.blobSize;
  1811. }
  1812. }
  1813. var result = {
  1814. width: headerInfo.width,
  1815. height: headerInfo.height,
  1816. pixelData: data.pixels.resultPixels,
  1817. minValue: headerInfo.zMin,
  1818. maxValue: headerInfo.zMax,
  1819. validPixelCount: headerInfo.numValidPixel,
  1820. dimCount: headerInfo.numDims,
  1821. dimStats: {
  1822. minValues: headerInfo.minValues,
  1823. maxValues: headerInfo.maxValues
  1824. },
  1825. maskData: data.pixels.resultMask
  1826. //noDataValue: noDataValue
  1827. };
  1828. //we should remove this if there's no existing client
  1829. //optional noDataValue processing, it's user's responsiblity
  1830. if (data.pixels.resultMask && Lerc2Helpers.isValidPixelValue(headerInfo.imageType, noDataValue)) {
  1831. var mask = data.pixels.resultMask;
  1832. for (i = 0; i < numPixels; i++) {
  1833. if (!mask[i]) {
  1834. result.pixelData[i] = noDataValue;
  1835. }
  1836. }
  1837. result.noDataValue = noDataValue;
  1838. }
  1839. data.noDataValue = noDataValue;
  1840. if (options.returnFileInfo) {
  1841. result.fileInfo = Lerc2Helpers.formatFileInfo(data);
  1842. }
  1843. return result;
  1844. },
  1845. getBandCount: function(/*byte array*/ input) {
  1846. var count = 0;
  1847. var i = 0;
  1848. var temp = {};
  1849. temp.ptr = 0;
  1850. temp.pixels = {};
  1851. while (i < input.byteLength - 58) {
  1852. Lerc2Helpers.readHeaderInfo(input, temp);
  1853. i += temp.headerInfo.blobSize;
  1854. count++;
  1855. temp.ptr = i;
  1856. }
  1857. return count;
  1858. }
  1859. };
  1860. return Lerc2Decode;
  1861. })();
  1862. var isPlatformLittleEndian = (function() {
  1863. var a = new ArrayBuffer(4);
  1864. var b = new Uint8Array(a);
  1865. var c = new Uint32Array(a);
  1866. c[0] = 1;
  1867. return b[0] === 1;
  1868. })();
  1869. var Lerc = {
  1870. /************wrapper**********************************************/
  1871. /**
  1872. * A wrapper for decoding both LERC1 and LERC2 byte streams capable of handling multiband pixel blocks for various pixel types.
  1873. *
  1874. * @alias module:Lerc
  1875. * @param {ArrayBuffer} input The LERC input byte stream
  1876. * @param {object} [options] The decoding options below are optional.
  1877. * @param {number} [options.inputOffset] The number of bytes to skip in the input byte stream. A valid Lerc file is expected at that position.
  1878. * @param {string} [options.pixelType] (LERC1 only) Default value is F32. Valid pixel types for input are U8/S8/S16/U16/S32/U32/F32.
  1879. * @param {number} [options.noDataValue] (LERC1 only). It is recommended to use the returned mask instead of setting this value.
  1880. * @returns {{width, height, pixels, pixelType, mask, statistics}}
  1881. * @property {number} width Width of decoded image.
  1882. * @property {number} height Height of decoded image.
  1883. * @property {array} pixels [band1, band2, …] Each band is a typed array of width*height.
  1884. * @property {string} pixelType The type of pixels represented in the output.
  1885. * @property {mask} mask Typed array with a size of width*height, or null if all pixels are valid.
  1886. * @property {array} statistics [statistics_band1, statistics_band2, …] Each element is a statistics object representing min and max values
  1887. **/
  1888. decode: function(encodedData, options) {
  1889. if (!isPlatformLittleEndian) {
  1890. throw "Big endian system is not supported.";
  1891. }
  1892. options = options || {};
  1893. var inputOffset = options.inputOffset || 0;
  1894. var fileIdView = new Uint8Array(encodedData, inputOffset, 10);
  1895. var fileIdentifierString = String.fromCharCode.apply(null, fileIdView);
  1896. var lerc, majorVersion;
  1897. if (fileIdentifierString.trim() === "CntZImage") {
  1898. lerc = LercDecode;
  1899. majorVersion = 1;
  1900. }
  1901. else if (fileIdentifierString.substring(0, 5) === "Lerc2") {
  1902. lerc = Lerc2Decode;
  1903. majorVersion = 2;
  1904. }
  1905. else {
  1906. throw "Unexpected file identifier string: " + fileIdentifierString;
  1907. }
  1908. var iPlane = 0, eof = encodedData.byteLength - 10, encodedMaskData, bandMasks = [], bandMask, maskData;
  1909. var decodedPixelBlock = {
  1910. width: 0,
  1911. height: 0,
  1912. pixels: [],
  1913. pixelType: options.pixelType,
  1914. mask: null,
  1915. statistics: []
  1916. };
  1917. while (inputOffset < eof) {
  1918. var result = lerc.decode(encodedData, {
  1919. inputOffset: inputOffset,//for both lerc1 and lerc2
  1920. encodedMaskData: encodedMaskData,//lerc1 only
  1921. maskData: maskData,//lerc2 only
  1922. returnMask: iPlane === 0 ? true : false,//lerc1 only
  1923. returnEncodedMask: iPlane === 0 ? true : false,//lerc1 only
  1924. returnFileInfo: true,//for both lerc1 and lerc2
  1925. pixelType: options.pixelType || null,//lerc1 only
  1926. noDataValue: options.noDataValue || null//lerc1 only
  1927. });
  1928. inputOffset = result.fileInfo.eofOffset;
  1929. if (iPlane === 0) {
  1930. encodedMaskData = result.encodedMaskData;//lerc1
  1931. maskData = result.maskData;//lerc2
  1932. decodedPixelBlock.width = result.width;
  1933. decodedPixelBlock.height = result.height;
  1934. decodedPixelBlock.dimCount = result.dimCount || 1;
  1935. //decodedPixelBlock.dimStats = decodedPixelBlock.dimStats;
  1936. decodedPixelBlock.pixelType = result.pixelType || result.fileInfo.pixelType;
  1937. decodedPixelBlock.mask = result.maskData;
  1938. }
  1939. if (majorVersion >1 && result.fileInfo.mask && result.fileInfo.mask.numBytes > 0) {
  1940. bandMasks.push(result.maskData);
  1941. }
  1942. iPlane++;
  1943. decodedPixelBlock.pixels.push(result.pixelData);
  1944. decodedPixelBlock.statistics.push({
  1945. minValue: result.minValue,
  1946. maxValue: result.maxValue,
  1947. noDataValue: result.noDataValue,
  1948. dimStats: result.dimStats
  1949. });
  1950. }
  1951. var i, j, numPixels;
  1952. if (majorVersion > 1 && bandMasks.length > 1) {
  1953. numPixels = decodedPixelBlock.width * decodedPixelBlock.height;
  1954. decodedPixelBlock.bandMasks = bandMasks;
  1955. maskData = new Uint8Array(numPixels);
  1956. maskData.set(bandMasks[0]);
  1957. for (i = 1; i < bandMasks.length; i++) {
  1958. bandMask = bandMasks[i];
  1959. for (j = 0; j < numPixels; j++) {
  1960. maskData[j] = maskData[j] & bandMask[j];
  1961. }
  1962. }
  1963. decodedPixelBlock.maskData = maskData;
  1964. }
  1965. return decodedPixelBlock;
  1966. }
  1967. };
  1968. if (typeof define === "function" && define.amd) {/* jshint ignore:line */
  1969. //amd loaders such as dojo and requireJS
  1970. //http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition
  1971. define([], function() { return Lerc; });/* jshint ignore:line */
  1972. }
  1973. else if (typeof module !== "undefined" && module.exports) {/* jshint ignore:line */
  1974. //commonJS module 1.0/1.1/1.1.1 systems, such as nodeJS
  1975. //http://wiki.commonjs.org/wiki/Modules
  1976. module.exports = Lerc;/* jshint ignore:line */
  1977. }
  1978. else {
  1979. //assign to this, most likely window
  1980. this.Lerc = Lerc;
  1981. }
  1982. })();