readFromBuffer()

in src/engine/loaders/LoaderDicom.js [1261:1893]


  readFromBuffer(indexFile, fileName, ratioLoaded, arrBuf, callbackProgress, callbackComplete) {
    if (typeof indexFile !== 'number') {
      console.log('LoaderDicom.readFromBuffer: bad indexFile argument');
    }
    if (typeof fileName !== 'string') {
      console.log('LoaderDicom.readFromBuffer: bad fileName argument');
    }
    if (typeof arrBuf !== 'object') {
      console.log('LoaderDicom.readFromBuffer: bad arrBuf argument');
    }
    // const bufBytes = new Uint8Array(arrBuf);
    // const isUint8Arr = bufBytes instanceof Uint8Array;
    // if (!isUint8Arr) {
    //   console.log('LoaderDicom. readFromBuffer. Error read buffer');
    //   return false;
    // }

    // console.log(`LoaderDicom. readFromBuffer. file = ${fileName}, ratio = ${ratioLoaded}`);

    // add info
    const dicomInfo = this.m_dicomInfo;
    const sliceInfo = new DicomSliceInfo();
    const strSlice = 'Slice ' + indexFile.toString();
    sliceInfo.m_sliceName = strSlice;
    sliceInfo.m_fileName = fileName;
    sliceInfo.m_tags = [];
    dicomInfo.m_sliceInfo.push(sliceInfo);

    const dataView = new DataView(arrBuf);
    if (dataView === null) {
      console.log('No memory');
      return LoadResult.ERROR_NO_MEMORY;
    }
    const fileSize = dataView.byteLength;
    // check dicom header
    const SIZE_HEAD = 144;
    if (fileSize < SIZE_HEAD) {
      // this.m_errors[indexFile] = DICOM_ERROR_TOO_SMALL_FILE;
      this.m_error = LoadResult.ERROR_TOO_SMALL_DATA_SIZE;
      if (callbackComplete !== undefined) {
        callbackComplete(LoadResult.ERROR_TOO_SMALL_DATA_SIZE);
      }
      return LoadResult.ERROR_TOO_SMALL_DATA_SIZE;
    }
    const OFF_MAGIC = 128;
    const SIZE_DWORD = 4;
    const SIZE_SHORT = 2;
    for (let i = 0; i < SIZE_DWORD; i++) {
      const v = dataView.getUint8(OFF_MAGIC + i);
      if (v !== MAGIC_DICM[i]) {
        this.m_errors[indexFile] = DICOM_ERROR_WRONG_HEADER;
        console.log(`Dicom readFromBuffer. Wrong header in file: ${fileName}`);
        if (callbackComplete !== undefined) {
          callbackComplete(LoadResult.WRONG_HEADER_MAGIC);
        }
        return LoadResult.WRONG_HEADER_MAGIC;
      }
    }
    let offset = OFF_MAGIC;
    offset += SIZE_DWORD;

    //
    this.m_littleEndian = true;
    this.m_explicit = true;
    this.m_metaFound = false;
    this.m_metaFinished = false;
    this.m_metaFinishedOffset = -1;
    this.m_needsDeflate = false;

    this.m_imageNumber = -1;
    this.m_xDim = -1;
    this.m_yDim = -1;
    this.m_bitsPerPixel = -1;
    this.m_windowCenter = -1;
    this.m_windowWidth = -1;
    let pixelBitMask = 0;
    let pixelPaddingValue = 0;
    let pixelsTagReaded = false;
    let pixelMinValue = -1;
    let pixelMaxValue = -1;

    // read tag by tag, until image tag
    let tag;
    for (tag = this.getNextTag(dataView, offset); tag !== null; ) {
      if (tag.isPixelData()) {
        pixelsTagReaded = true;
        break;
      }
      offset = tag.m_offsetEnd;
      tag = this.getNextTag(dataView, offset);
      if (tag === null) {
        break;
      }

      // add to tag info
      const dicomInfo = this.m_dicomInfo;
      const numlices = dicomInfo.m_sliceInfo.length;
      const sliceInfo = dicomInfo.m_sliceInfo[numlices - 1];
      const tagInfo = new DicomTagInfo();
      tagInfo.m_tag = '(' + LoaderDicom.numberToHexString(tag.m_group) + ',' + LoaderDicom.numberToHexString(tag.m_element) + ')';
      const strTagName = this.m_dictionary.getTextDesc(tag.m_group, tag.m_element);
      tagInfo.m_attrName = strTagName.length > 1 ? strTagName : '';

      let strVal = LoaderDicom.getAttrValueAsString(tag);
      strVal = strVal !== null ? strVal : '';

      tagInfo.m_attrValue = strVal;
      sliceInfo.m_tags.push(tagInfo);

      // console.log(`Add tag info. tag = ${tagInfo.m_tag} atNa = ${tagInfo.m_attrName} atVal = ${tagInfo.m_attrValue} `);

      // get important info from tag: image number
      if (tag.m_group === TAG_IMAGE_INSTANCE_NUMBER[0] && tag.m_element === TAG_IMAGE_INSTANCE_NUMBER[1]) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        const strNum = LoaderDicom.getStringAt(dv, 0, dataLen);
        this.m_imageNumber = parseInt(strNum, 10) - 1;
        if (DEBUG_PRINT_TAGS_INFO) {
          console.log(`Str = ${strNum}, ImageNumber = ${this.m_imageNumber}`);
        }
      }
      // get important tag: image rows
      if (tag.m_group === TAG_IMAGE_ROWS[0] && tag.m_element === TAG_IMAGE_ROWS[1]) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        const yDim = dataLen === SIZE_SHORT ? dv.getUint16(0, this.m_littleEndian) : dv.getUint32(0, this.m_littleEndian);
        if (DEBUG_PRINT_TAGS_INFO) {
          console.log(`yDim = ${yDim}`);
        }
        if (this.m_yDim < 0) {
          this.m_yDim = yDim;
        } else if (this.m_yDim !== yDim) {
          console.log('Bad image size y');
          if (callbackComplete !== undefined) {
            callbackComplete(LoadResult.WRONG_IMAGE_DIM_Y);
          }
          return LoadResult.WRONG_IMAGE_DIM_Y;
        }
      }
      // get important tag: image cols
      if (tag.m_group === TAG_IMAGE_COLS[0] && tag.m_element === TAG_IMAGE_COLS[1]) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        const xDim = dataLen === SIZE_SHORT ? dv.getUint16(0, this.m_littleEndian) : dv.getUint32(0, this.m_littleEndian);
        if (DEBUG_PRINT_TAGS_INFO) {
          console.log(`xDim = ${xDim}`);
        }
        if (this.m_xDim < 0) {
          this.m_xDim = xDim;
        } else if (this.m_xDim !== xDim) {
          console.log('Bad image size x');
          if (callbackComplete !== undefined) {
            callbackComplete(LoadResult.WRONG_IMAGE_DIM_X);
          }
          return LoadResult.WRONG_IMAGE_DIM_X;
        }
      }
      // get important tag: bits allocated
      if (tag.m_group === TAG_BITS_ALLOCATED[0] && tag.m_element === TAG_BITS_ALLOCATED[1]) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        this.m_bitsPerPixel = dataLen === SIZE_SHORT ? dv.getUint16(0, this.m_littleEndian) : dv.getUint32(0, this.m_littleEndian);
        if (DEBUG_PRINT_TAGS_INFO) {
          console.log(`bitsPerPixel = ${this.m_bitsPerPixel}`);
        }
      }

      // window center
      if (tag.m_group === TAG_WINDOW_CENTER[0] && tag.m_element === TAG_WINDOW_CENTER[1]) {
        if (tag.m_value != null && tag.m_value.byteLength > 0) {
          const dataLen = tag.m_value.byteLength;
          const dv = new DataView(tag.m_value);
          const strNum = LoaderDicom.getStringAt(dv, 0, dataLen);
          this.m_windowCenter = parseInt(strNum, 10);
          if (DEBUG_PRINT_TAGS_INFO) {
            console.log(`Str = ${strNum}, WindowCenter = ${this.m_windowCenter}`);
          }
        } // if non zero data
      } // window center

      // window width
      if (tag.m_group === TAG_WINDOW_WIDTH[0] && tag.m_element === TAG_WINDOW_WIDTH[1]) {
        if (tag.m_value != null && tag.m_value.byteLength > 0) {
          const dataLen = tag.m_value.byteLength;
          const dv = new DataView(tag.m_value);
          const strNum = LoaderDicom.getStringAt(dv, 0, dataLen);
          this.m_windowWidth = parseInt(strNum, 10);
          if (DEBUG_PRINT_TAGS_INFO) {
            console.log(`Str = ${strNum}, WindowWidth = ${this.m_windowWidth}`);
          }
        } // if non zero data
      } // window width

      // rescale intercept
      if (tag.m_group === TAG_RESCALE_INTERCEPT[0] && tag.m_element === TAG_RESCALE_INTERCEPT[1]) {
        if (tag.m_value != null && tag.m_value.byteLength > 0) {
          const dataLen = tag.m_value.byteLength;
          const dv = new DataView(tag.m_value);
          const strNum = LoaderDicom.getStringAt(dv, 0, dataLen);
          this.m_rescaleIntercept = parseInt(strNum, 10);
          if (DEBUG_PRINT_TAGS_INFO) {
            console.log(`Str = ${strNum}, RescaleIntercept = ${this.m_rescaleIntercept}`);
          }
        } // if non zero data
      } // rescale intercept

      // rescale slope
      if (tag.m_group === TAG_RESCALE_SLOPE[0] && tag.m_element === TAG_RESCALE_SLOPE[1]) {
        if (tag.m_value != null && tag.m_value.byteLength > 0) {
          const dataLen = tag.m_value.byteLength;
          const dv = new DataView(tag.m_value);
          const strNum = LoaderDicom.getStringAt(dv, 0, dataLen);
          this.m_rescaleSlope = parseInt(strNum, 10);
          if (DEBUG_PRINT_TAGS_INFO) {
            console.log(`Str = ${strNum}, RescaleSlope = ${this.m_rescaleSlope}`);
          }
        } // if non zero data
      } // rescale slope

      // rescale type
      if (tag.m_group === TAG_RESCALE_TYPE[0] && tag.m_element === TAG_RESCALE_TYPE[1]) {
        if (tag.m_value != null && tag.m_value.byteLength > 0) {
          const dataLen = tag.m_value.byteLength;
          const dv = new DataView(tag.m_value);
          const strVal = LoaderDicom.getStringAt(dv, 0, dataLen);
          if (strVal === 'HU') {
            this.m_rescaleHounsfield = true;
          }
          if (DEBUG_PRINT_TAGS_INFO) {
            console.log(`Str = ${strNum}, RescaleType = ${this.m_rescaleHounsfield}`);
          }
        } // if non zero data
      } // rescale type

      // pixel representation
      if (tag.m_group === TAG_PIXEL_REPRESENTATION[0] && tag.m_element === TAG_PIXEL_REPRESENTATION[1]) {
        if (tag.m_value != null && tag.m_value.byteLength > 0) {
          const dataLenPixRep = tag.m_value.byteLength;
          const dvPixRep = new DataView(tag.m_value);
          const pixRep =
            dataLenPixRep === SIZE_SHORT ? dvPixRep.getUint16(0, this.m_littleEndian) : dvPixRep.getUint32(0, this.m_littleEndian);
          if (pixRep === 1) {
            this.m_pixelRepresentaionSigned = true;
          }
          if (DEBUG_PRINT_TAGS_INFO) {
            console.log(`Str = ${strNum}, Pixel representation is signed = ${this.m_pixelRepresentaionSigned}`);
          }
        } // if non zero data
      } // rescale slope

      // get series number
      if (tag.m_group === TAG_SERIES_NUMBER[0] && tag.m_element === TAG_SERIES_NUMBER[1]) {
        if (tag.m_value != null && tag.m_value.byteLength > 0) {
          const dataLen = tag.m_value.byteLength;
          const dv = new DataView(tag.m_value);
          const strNum = LoaderDicom.getStringAt(dv, 0, dataLen);
          this.m_seriesNumber = parseInt(strNum, 10);
          if (DEBUG_PRINT_TAGS_INFO) {
            console.log(`Str = ${strNum}, SeriesNumber = ${this.m_seriesNumber}`);
          }
        } // if non zero data
      } // series number

      // get important tag: series description
      if (tag.m_group === TAG_SERIES_DESCRIPTION[0] && tag.m_element === TAG_SERIES_DESCRIPTION[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        this.m_seriesDescr = LoaderDicom.getStringAt(dv, 0, dataLen);
        if (DEBUG_PRINT_TAGS_INFO) {
          console.log(`Series description = ${this.m_seriesDescr}`);
        }
      }
      // get important tag: hight bit
      if (tag.m_group === TAG_IMAGE_HIGH_BIT[0] && tag.m_element === TAG_IMAGE_HIGH_BIT[1]) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        const highBit = dataLen === SIZE_SHORT ? dv.getUint16(0, this.m_littleEndian) : dv.getUint32(0, this.m_littleEndian);
        pixelBitMask = (1 << (highBit + 1)) - 1;
        if (DEBUG_PRINT_TAGS_INFO) {
          console.log(`highBit = ${highBit}`);
        }
      }

      // get important tag: min pixel value
      if (tag.m_group === TAG_IMAGE_SMALL_PIX_VAL[0] && tag.m_element === TAG_IMAGE_SMALL_PIX_VAL[1]) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        pixelMinValue = dataLen === SIZE_SHORT ? dv.getInt16(0, this.m_littleEndian) : dv.getInt32(0, this.m_littleEndian);
        if (DEBUG_PRINT_TAGS_INFO) {
          console.log(`pixelMinValue = ${pixelMinValue}`);
        }
      }

      // get important tag: max pixel value
      if (tag.m_group === TAG_IMAGE_LARGE_PIX_VAL[0] && tag.m_element === TAG_IMAGE_LARGE_PIX_VAL[1]) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        pixelMaxValue = dataLen === SIZE_SHORT ? dv.getInt16(0, this.m_littleEndian) : dv.getInt32(0, this.m_littleEndian);
        if (DEBUG_PRINT_TAGS_INFO) {
          console.log(`pixelMaxValue = ${pixelMaxValue}`);
        }
      }

      // get important tag: pixel padding value
      if (tag.m_group === TAG_PIXEL_PADDING_VALUE[0] && tag.m_element === TAG_PIXEL_PADDING_VALUE[1]) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        pixelPaddingValue = dataLen === SIZE_SHORT ? dv.getUint16(0, this.m_littleEndian) : dv.getUint32(0, this.m_littleEndian);
        this.m_padValue = pixelPaddingValue;
        if (DEBUG_PRINT_TAGS_INFO) {
          console.log(`pixelPaddingValue = ${pixelPaddingValue}`);
        }
      }
      // get important tag: pixel spacing in 2d (xy)
      if (tag.m_group === TAG_PIXEL_SPACING[0] && tag.m_element === TAG_PIXEL_SPACING[1]) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        const strPixelSpacing = LoaderDicom.getStringAt(dv, 0, dataLen);
        const strArr = strPixelSpacing.split('\\');
        if (strArr.length === SIZE_SHORT) {
          this.m_pixelSpacing.x = parseFloat(strArr[0]);
          this.m_pixelSpacing.y = parseFloat(strArr[1]);
          if (DEBUG_PRINT_TAGS_INFO) {
            console.log(`TAG. pixel spacing xy = ${this.m_pixelSpacing.x} * ${this.m_pixelSpacing.y}`);
          }
        }
      }
      // get important tag: image position (x,y,z)
      if (tag.m_group === TAG_IMAGE_POSITION[0] && tag.m_element === TAG_IMAGE_POSITION[1]) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        const strImagePosition = LoaderDicom.getStringAt(dv, 0, dataLen);
        const strArr = strImagePosition.split('\\');
        const NUM_COMPONENTS_3 = 3;
        if (strArr.length === NUM_COMPONENTS_3) {
          // eslint-disable-next-line
          const xPos = parseFloat(strArr[0]);
          // eslint-disable-next-line
          const yPos = parseFloat(strArr[1]);
          // eslint-disable-next-line
          const zPos = parseFloat(strArr[2]);
          this.m_imagePosMin.x = xPos < this.m_imagePosMin.x ? xPos : this.m_imagePosMin.x;
          this.m_imagePosMin.y = yPos < this.m_imagePosMin.y ? yPos : this.m_imagePosMin.y;
          this.m_imagePosMin.z = zPos < this.m_imagePosMin.z ? zPos : this.m_imagePosMin.z;
          this.m_imagePosMax.x = xPos > this.m_imagePosMax.x ? xPos : this.m_imagePosMax.x;
          this.m_imagePosMax.y = yPos > this.m_imagePosMax.y ? yPos : this.m_imagePosMax.y;
          this.m_imagePosMax.z = zPos > this.m_imagePosMax.z ? zPos : this.m_imagePosMax.z;
          if (DEBUG_PRINT_TAGS_INFO) {
            console.log(`TAG. image position x,y,z = ${xPos}, ${yPos}, ${zPos}`);
          }
        }
      }

      // slice thickness
      if (tag.m_group === TAG_SLICE_THICKNESS[0] && tag.m_element === TAG_SLICE_THICKNESS[1]) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        const strSliceThickness = LoaderDicom.getStringAt(dv, 0, dataLen);
        this.m_pixelSpacing.z = parseFloat(strSliceThickness);
        if (DEBUG_PRINT_TAGS_INFO) {
          console.log(`TAG. slice thickness = ${this.m_pixelSpacing.z}`);
        }
      }

      // get important tag: slice location (x,y,z)
      if (tag.m_group === TAG_SLICE_LOCATION[0] && tag.m_element === TAG_SLICE_LOCATION[1]) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        const strSliceLocation = LoaderDicom.getStringAt(dv, 0, dataLen);
        const sliceLoc = parseFloat(strSliceLocation);
        this.m_sliceLocation = sliceLoc;
        this.m_sliceLocMin = sliceLoc < this.m_sliceLocMin ? sliceLoc : this.m_sliceLocMin;
        this.m_sliceLocMax = sliceLoc > this.m_sliceLocMax ? sliceLoc : this.m_sliceLocMax;
        if (DEBUG_PRINT_TAGS_INFO) {
          console.log(`TAG. Slice location = ${this.m_sliceLocation}`);
        }
      }

      // get important tag: samples per pixel
      if (tag.m_group === TAG_SAMPLES_PER_PIXEL[0] && tag.m_element === TAG_SAMPLES_PER_PIXEL[1]) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        this.m_samplesPerPixel = dataLen === SIZE_SHORT ? dv.getUint16(0, this.m_littleEndian) : dv.getUint32(0, this.m_littleEndian);
        if (DEBUG_PRINT_TAGS_INFO) {
          console.log(`samplesPerPixel = ${this.m_samplesPerPixel}`);
        }
      }

      // dicom info
      if (tag.m_group === TAG_SERIES_DESCRIPTION[0] && tag.m_element === TAG_SERIES_DESCRIPTION[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        const strDescr = LoaderDicom.getStringAt(dv, 0, dataLen);
        // console.log(`DicomLoader. Series descr read = ${strDescr}`);
        this.m_dicomInfo.m_seriesDescr = strDescr;
      }
      if (tag.m_group === TAG_SERIES_TIME[0] && tag.m_element === TAG_SERIES_TIME[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        const strTimeMerged = LoaderDicom.getStringAt(dv, 0, dataLen);
        // eslint-disable-next-line
        const strHour = strTimeMerged.substring(0, 2);
        // eslint-disable-next-line
        const strMinute = strTimeMerged.substring(2, 4);
        // eslint-disable-next-line
        const strSec = strTimeMerged.substring(4, strTimeMerged.length);
        const strTimeBuild = `${strHour}:${strMinute}:${strSec}`;
        // console.log(`Series time read = ${strTimeBuild}`);
        this.m_dicomInfo.m_seriesTime = strTimeBuild;
        if (DEBUG_PRINT_TAGS_INFO) {
          console.log(`Series time = ${this.m_dicomInfo.m_seriesTime}`);
        }
      }
      if (tag.m_group === TAG_PATIENT_NAME[0] && tag.m_element === TAG_PATIENT_NAME[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        this.m_dicomInfo.m_patientName = LoaderDicom.getUtf8StringAt(dv, 0, dataLen);
        this.m_dicomInfo.m_patientName = this.m_dicomInfo.m_patientName.trim();
        //console.log(`m_patientName = ${this.m_dicomInfo.m_patientName}`);
      }
      if (tag.m_group === TAG_PATIENT_ID[0] && tag.m_element === TAG_PATIENT_ID[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        this.m_dicomInfo.m_patientId = LoaderDicom.getStringAt(dv, 0, dataLen);
        // console.log(`m_patientId = ${this.m_dicomInfo.m_patientId}`);
      }
      if (tag.m_group === TAG_PATIENT_GENDER[0] && tag.m_element === TAG_PATIENT_GENDER[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        this.m_dicomInfo.m_patientGender = LoaderDicom.getStringAt(dv, 0, dataLen);
        // console.log(`m_patientGender = ${this.m_dicomInfo.m_patientGender}`);
      }
      if (tag.m_group === TAG_PATIENT_BIRTH_DATE[0] && tag.m_element === TAG_PATIENT_BIRTH_DATE[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        const strDateMerged = LoaderDicom.getStringAt(dv, 0, dataLen);
        // eslint-disable-next-line
        const strY = strDateMerged.substring(0, 4);
        // eslint-disable-next-line
        const strM = strDateMerged.substring(4, 6);
        // eslint-disable-next-line
        const strD = strDateMerged.substring(6);
        this.m_dicomInfo.m_patientDateOfBirth = `${strD}/${strM}/${strY}`;
        // console.log(`m_patientDateOfBirth = ${this.m_dicomInfo.m_patientDateOfBirth}`);
      }
      if (tag.m_group === TAG_STUDY_DATE[0] && tag.m_element === TAG_STUDY_DATE[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        const strDateMerged = LoaderDicom.getStringAt(dv, 0, dataLen);
        // eslint-disable-next-line
        const strY = strDateMerged.substring(0, 4);
        // eslint-disable-next-line
        const strM = strDateMerged.substring(4, 6);
        // eslint-disable-next-line
        const strD = strDateMerged.substring(6);
        this.m_dicomInfo.m_studyDate = `${strD}/${strM}/${strY}`;
        // console.log(`m_studyDate = ${this.m_dicomInfo.m_studyDate}`);
      }
      if (tag.m_group === TAG_STUDY_DESCR[0] && tag.m_element === TAG_STUDY_DESCR[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        const strDescr = LoaderDicom.getStringAt(dv, 0, dataLen);
        this.m_dicomInfo.m_studyDescr = strDescr;
        this.m_dicomInfo.m_studyDescr = this.m_dicomInfo.m_studyDescr.trim();
        // console.log(`m_studyDescr = ${this.m_dicomInfo.m_studyDescr}`);
      }
      if (tag.m_group === TAG_BODY_PART_EXAMINED[0] && tag.m_element === TAG_BODY_PART_EXAMINED[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        this.m_dicomInfo.m_bodyPartExamined = LoaderDicom.getStringAt(dv, 0, dataLen);
        // console.log(`m_patientName = ${this.m_dicomInfo.m_patientName}`);
      }

      if (tag.m_group === TAG_ACQUISION_TIME[0] && tag.m_element === TAG_ACQUISION_TIME[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        this.m_dicomInfo.m_acquisionTime = LoaderDicom.getStringAt(dv, 0, dataLen);
        // console.log(`m_acquisionTime = ${this.m_dicomInfo.m_acquisionTime}`);
      }
      if (tag.m_group === TAG_INSTITUTION_NAME[0] && tag.m_element === TAG_INSTITUTION_NAME[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        this.m_dicomInfo.m_institutionName = LoaderDicom.getUtf8StringAt(dv, 0, dataLen);
        this.m_dicomInfo.m_institutionName = this.m_dicomInfo.m_institutionName.trim();
        // console.log(`m_institutionName = ${this.m_dicomInfo.m_institutionName}`);
      }

      if (tag.m_group === TAG_OPERATORS_NAME[0] && tag.m_element === TAG_OPERATORS_NAME[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        this.m_dicomInfo.m_operatorsName = LoaderDicom.getUtf8StringAt(dv, 0, dataLen);
        this.m_dicomInfo.m_operatorsName = this.m_dicomInfo.m_operatorsName.trim();
        // console.log(`m_operatorsName = ${this.m_dicomInfo.m_operatorsName}`);
      }
      if (tag.m_group === TAG_PHYSICANS_NAME[0] && tag.m_element === TAG_PHYSICANS_NAME[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        this.m_dicomInfo.m_physicansName = LoaderDicom.getUtf8StringAt(dv, 0, dataLen);
        this.m_dicomInfo.m_physicansName = this.m_dicomInfo.m_physicansName.trim();
        // console.log(`m_physicansName = ${this.m_dicomInfo.m_physicansName}`);
      }
      if (tag.m_group === TAG_MANUFACTURER_NAME[0] && tag.m_element === TAG_MANUFACTURER_NAME[1] && tag.m_value !== null) {
        const dataLen = tag.m_value.byteLength;
        const dv = new DataView(tag.m_value);
        this.m_dicomInfo.m_manufacturerName = LoaderDicom.getStringAt(dv, 0, dataLen);
        this.m_dicomInfo.m_manufacturerName = this.m_dicomInfo.m_manufacturerName.trim();
        // console.log(`m_manufacturerName = ${this.m_dicomInfo.m_manufacturerName}`);
      }
    } // for all tags readed
    if (!pixelsTagReaded) {
      if (callbackComplete !== undefined) {
        callbackComplete(LoadResult.ERROR_PIXELS_TAG_NOT_FOUND);
      }
      return LoadResult.ERROR_PIXELS_TAG_NOT_FOUND;
    }
    // check transform syntax
    if (this.m_transformSyntax.length > 1) {
      // const decoder = new jpeg.lossless.Decoder();
      // const outBuffer = decoder.decompress(tag.m_value);
      if (callbackComplete !== undefined) {
        callbackComplete(LoadResult.ERROR_COMPRESSED_IMAGE_NOT_SUPPORTED);
      }
      return LoadResult.ERROR_COMPRESSED_IMAGE_NOT_SUPPORTED;
    }

    // check correct data from tags
    const BITS_IN_BYTE = 8;
    const imageSizeBytes = Math.floor(this.m_xDim * this.m_yDim * (this.m_bitsPerPixel / BITS_IN_BYTE) * this.m_samplesPerPixel);
    if (imageSizeBytes !== tag.m_value.byteLength || pixelBitMask === 0) {
      console.log(`Wrong image pixels size. Readed ${tag.m_value.byteLength}, but expected ${imageSizeBytes}`);
      if (callbackComplete !== undefined) {
        callbackComplete(LoadResult.ERROR_COMPRESSED_IMAGE_NOT_SUPPORTED);
      }
      return LoadResult.WRONG_HEADER_DATA_SIZE;
    }

    const numPixels = this.m_xDim * this.m_yDim;
    // const volSlice = this.m_slicesVolume.getNewSlice();
    const volSlice = new DicomSlice();
    if (volSlice === null) {
      console.log('No memory');
      return LoadResult.ERROR_NO_MEMORY;
    }

    if (this.m_pixelRepresentaionSigned) {
      volSlice.m_image = new Int16Array(numPixels);
    } else {
      volSlice.m_image = new Uint16Array(numPixels);
    }
    if (volSlice.m_image === null) {
      console.log('No memory');
      return LoadResult.ERROR_NO_MEMORY;
    }
    volSlice.m_sliceNumber = this.m_imageNumber;
    volSlice.m_sliceLocation = this.m_sliceLocation;
    volSlice.m_patientName = this.m_dicomInfo.m_patientName;
    volSlice.m_studyDescr = this.m_dicomInfo.m_studyDescr;
    volSlice.m_studyDate = this.m_dicomInfo.m_studyDate;
    volSlice.m_seriesTime = this.m_dicomInfo.m_seriesTime;
    volSlice.m_seriesDescr = this.m_dicomInfo.m_seriesDescr;
    volSlice.m_bodyPartExamined = this.m_dicomInfo.m_bodyPartExamined;
    volSlice.m_institutionName = this.m_dicomInfo.m_institutionName;
    volSlice.m_operatorsName = this.m_dicomInfo.m_operatorsName;
    volSlice.m_physicansName = this.m_dicomInfo.m_physicansName;
    volSlice.buildHash();

    volSlice.m_xDim = this.m_xDim;
    volSlice.m_yDim = this.m_yDim;

    // console.log(`patName = ${volSlice.m_patientName}`);
    // console.log(`studyDescr = ${volSlice.m_studyDescr}`);
    // console.log(`studyDate = ${volSlice.m_studyDate}`);
    // console.log(`seriesTime = ${volSlice.m_seriesTime}`);
    // console.log(`seriesDescr = ${volSlice.m_seriesDescr}`);
    // console.log(`bodyPartExamined = ${volSlice.m_bodyPartExamined}`);

    // Fill slice image
    // const imageDst = this.m_slices[this.m_imageNumber];
    const imageDst = volSlice.m_image;
    const imageSrc = new DataView(tag.m_value);
    if (imageSrc === null) {
      console.log('No memory');
      return LoadResult.ERROR_NO_MEMORY;
    }

    const BITS_8 = 8;
    const BITS_16 = 16;
    const NUM_1 = 1;
    const NUM_3 = 3;

    let i;
    if (this.m_bitsPerPixel === BITS_8) {
      if (this.m_samplesPerPixel === NUM_1) {
        for (i = 0; i < numPixels; i++) {
          const val = imageSrc.getUint8(i);
          imageDst[i] = val;
        }
        // if 1 sample per pixel
      } else if (this.m_samplesPerPixel === NUM_3) {
        // if 3 samples per pixel
        let j = 0;
        for (i = 0; i < numPixels; i++, j += 3) {
          const b0 = imageSrc.getUint8(j + 0);
          const b1 = imageSrc.getUint8(j + 1);
          const b2 = imageSrc.getUint8(j + 2);
          // assert(b0 < 256);
          // assert(b1 < 256);
          // assert(b2 < 256);
          imageDst[i] = Math.floor((b0 + b1 + b2) / 3);
        }
      }
    } else if (this.m_bitsPerPixel === BITS_16) {
      let i2 = 0;
      for (i = 0; i < numPixels; i++) {
        let val = imageSrc.getUint16(i2, this.m_littleEndian);
        i2 += SIZE_SHORT;
        imageDst[i] = val;
      } // end for i pixels
    } else {
      // if 16 bpp
      console.log('TODO: need to implement reading non-8 and non-16 bit dicom images');
    }
    this.m_error = DICOM_ERROR_OK;

    // add volume slice to slices volume (and manage series)
    this.m_slicesVolume.addSlice(volSlice);

    // console.log(`Dicom read OK. Volume pixels = ${this.m_xDim} * ${this.m_yDim} * ${this.m_zDim}`);
    if (callbackComplete !== undefined) {
      callbackComplete(LoadResult.SUCCESS);
    }
    return LoadResult.SUCCESS;
  } // end readFromBuffer