dicom-rle
Version:
Javascript DICOM Run Length Encoding Encoder/Decoder for Node.js and Browser
2 lines • 5.97 kB
JavaScript
/*! dicom-rle - 0.0.11 - 2025-04-03 | (c) 2022-2025 Pantelis Georgiadis | https://github.com/PantelisGeorgiadis/dicom-rle */
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("dicom-rle",[],t):"object"==typeof exports?exports["dicom-rle"]=t():e.dicomRle=t()}(this,(()=>{return e={237:(e,t,s)=>{const i={RleEncoder:s(638),RleDecoder:s(578),version:s(837)};e.exports=i},578:e=>{e.exports=class{decode(e,t){const s=(t=t||{}).planarConfiguration||0;if(!t.width||!t.height)throw new Error(`Width/height has an invalid value [w: ${t.width}, h: ${t.height}]`);if(!t.bitsAllocated||!t.samplesPerPixel)throw new Error(`Bits allocated/samples per pixel has an invalid value [allocated: ${t.bitsAllocated}, samples: ${t.samplesPerPixel}]`);const i=t.bitsAllocated/8+(t.bitsAllocated%8==0?0:1),r=t.width*t.height;let o=r*i*t.samplesPerPixel;1&~o||o++;const n=new Uint8Array(o),h=i*t.samplesPerPixel,a=new DataView(e.buffer);if(this.numberOfSegments=a.getInt32(0,!0),this.numberOfSegments!==h)throw new Error(`Unexpected number of RLE segments [expected: ${h}, got: ${this.numberOfSegments}]`);this.offsets=[];for(let e=0;e<15;e++)this.offsets[e]=a.getInt32(Int32Array.BYTES_PER_ELEMENT*(e+1),!0);this.data=e;for(let e=0;e<h;e++){let o,h;const a=Math.trunc(e/i),f=Math.trunc(e%i);0===s?(o=a*i,h=t.samplesPerPixel*i):(o=a*i*r,h=i),o+=i-f-1,this._decodeSegment(e,n,o,h)}return n}_getNumberOfSegments(){return this.numberOfSegments}_getSegmentOffset(e){return this.offsets[e]}_getSegmentLength(e){const t=this._getSegmentOffset(e);return e<this._getNumberOfSegments()-1?this._getSegmentOffset(e+1)-t:this.data.length-t}_decodeSegment(e,t,s,i){if(e<0||e>=this._getNumberOfSegments())throw new Error("Segment number out of range");const r=this._getSegmentOffset(e),o=this._getSegmentLength(e);this._decode(t,s,i,this.data,r,o)}_uncomplement(e,t){const s=1<<t;return e&1<<t-1?(e&s-1)-s:e}_decode(e,t,s,i,r,o){let n=t;const h=r+o,a=e.length;for(let t=r;t<h&&n<a;){const r=this._uncomplement(i[t++],8);if(r>=0){let o=r+1;if(h-t<o)throw new Error("RLE literal run exceeds input buffer length");if(n+(o-1)*s>=a)throw new Error("RLE literal run exceeds output buffer length");if(1===s)for(let s=0;s<o;++s,++t,++n)e[n]=i[t];else for(;o-- >0;)e[n]=i[t++],n+=s}else if(r>=-127){let o=-r;if(n+(o-1)*s>=a)throw new Error("RLE repeat run exceeds output buffer length");const h=i[t++];if(1===s)for(;o-- >=0;)e[n++]=h;else for(;o-- >=0;)e[n]=h,n+=s}if(t+1>=h)break}}}},638:e=>{e.exports=class{constructor(){this.count=0,this.offsets=new Array(15).fill(0),this.buffer=new Array(132).fill(0),this.encodedData=[],this.previousByte=-1,this.repeatCount=0,this.bufferPosition=0}encode(e,t){const s=(t=t||{}).planarConfiguration||0;if(!t.width||!t.height)throw new Error(`Width/height has an invalid value [w: ${t.width}, h: ${t.height}]`);if(!t.bitsAllocated||!t.samplesPerPixel)throw new Error(`Bits allocated/samples per pixel has an invalid value [allocated: ${t.bitsAllocated}, samples: ${t.samplesPerPixel}]`);const i=t.bitsAllocated/8+(t.bitsAllocated%8==0?0:1),r=t.width*t.height;let o=r*i*t.samplesPerPixel;1&~o||o++;const n=i*t.samplesPerPixel;for(let t=0;t<n;t++){this._nextSegment();const o=Math.trunc(t/i);let h,a;0===s?(h=o*i,a=n):(h=o*i*r,a=i),h+=i-Math.trunc(t%i)-1;for(let t=0;t<r;t++){if(h>=e.length)throw new Error("Read position is past end of frame buffer");this._encode(e[h]),h+=a}this._flush()}return this._makeEvenLength(),this._flush(),this._writeHeader(),new Uint8Array(this.encodedData)}_encode(e){if(e===this.previousByte){if(this.repeatCount++,this.repeatCount>2&&this.bufferPosition>0)for(;this.bufferPosition>0;){const e=Math.min(128,this.bufferPosition);this.encodedData.push(e-1),this._moveBuffer(e)}else if(this.repeatCount>128){const e=Math.min(this.repeatCount,128);this.encodedData.push(257-e),this.encodedData.push(this.previousByte),this.repeatCount-=e}}else{switch(this.repeatCount){case 0:break;case 1:this.buffer[this.bufferPosition++]=this.previousByte;break;case 2:this.buffer[this.bufferPosition++]=this.previousByte,this.buffer[this.bufferPosition++]=this.previousByte;break;default:for(;this.repeatCount>0;){const e=Math.min(this.repeatCount,128);this.encodedData.push(257-e),this.encodedData.push(this.previousByte),this.repeatCount-=e}}for(;this.bufferPosition>128;){const e=Math.min(128,this.bufferPosition);this.encodedData.push(e-1),this._moveBuffer(e)}this.previousByte=e,this.repeatCount=1}}_nextSegment(){this._flush(),1&~this.encodedData.length||this.encodedData.push(0),this.offsets[this.count++]=this.encodedData.length}_makeEvenLength(){this.encodedData.length%2==1&&this.encodedData.push(0)}_flush(){if(this.repeatCount<2)for(;this.repeatCount>0;)this.buffer[this.bufferPosition++]=this.previousByte,this.repeatCount--;for(;this.bufferPosition>0;){const e=Math.min(128,this.bufferPosition);this.encodedData.push(e-1),this._moveBuffer(e)}if(this.repeatCount>=2)for(;this.repeatCount>0;){const e=Math.min(this.repeatCount,128);this.encodedData.push(257-e),this.encodedData.push(this.previousByte),this.repeatCount-=e}this.previousByte=-1,this.repeatCount=0,this.bufferPosition=0}_moveBuffer(e){for(let t=0;t<e;t++)this.encodedData.push(this.buffer[t]);for(let t=e,s=0;t<this.bufferPosition;t++,s++)this.buffer[s]=this.buffer[t];this.bufferPosition=this.bufferPosition-e}_writeHeader(){const e=new ArrayBuffer(Uint32Array.BYTES_PER_ELEMENT+15*Int32Array.BYTES_PER_ELEMENT),t=new DataView(e);t.setUint32(0,this.count,!0);for(let e=0;e<this.count;e++)this.offsets[e]+=Uint32Array.BYTES_PER_ELEMENT+15*Int32Array.BYTES_PER_ELEMENT;for(let e=0;e<15;e++)t.setInt32(Uint32Array.BYTES_PER_ELEMENT+e*Int32Array.BYTES_PER_ELEMENT,this.offsets[e],!0);this.encodedData=[...new Uint8Array(e)].concat(this.encodedData)}}},837:e=>{e.exports="0.0.11"}},t={},function s(i){var r=t[i];if(void 0!==r)return r.exports;var o=t[i]={exports:{}};return e[i](o,o.exports,s),o.exports}(237);var e,t}));