docs: protected int decodeScan(int marker) throws IOException {
  
          try {
              while (marker != MarkerConstants.SOS) {
                  readTables(marker);
  
                  marker = nextMarker();
  
                  if (marker == -1) {
                      return marker;
                  }
              }
          } catch (JPEGMarkerException e) {
              // just ignore unknown marker
              return -1;
          }
  
          // Decode scan header
          int[] componentIndexes = readScanHeader();
          Component[] components = frameHeader.getComponents();
  
          // Calculate MCU size
          calculateMCUs(componentIndexes, components);
  
          try {
              int restartsLeft = restartInterval;
              in.resetBuffer();
              resetDecoder();
              HuffmanTable curDCTable;
              HuffmanTable curACTable;
              QuantizationTable curQTable;
  
              for (int m = 0; m < MCUsPerColumn * MCUsPerRow; m++) {
                  // If support restart interval
                  if (restartInterval > 0 && restartsLeft == 0) {
                      marker = nextMarker();
  
                      if (marker > MarkerConstants.RST7 || marker < MarkerConstants.RST0) {
                          return marker;
                      }
  
                      in.resetBuffer();
                      resetDecoder();
  
                      restartsLeft = restartInterval;
                  }
  
                  // Begin decode MCU
                  for (int c = 0, index = 0, ctr = 0; c < blocksNumInMCU; c++) {
                      index = blocksInMCU[c];
  
                      if (c == 0) {
                          ctr = 0;
                      } else {
                          if (index == blocksInMCU[c - 1]) {
                              ctr++;
                          } else {
                              ctr = 0;
                          }
                      }
  
                      // Begin decode block
                      curACTable = components[index].acHuffTable;
                      curDCTable = components[index].dcHuffTable;
                      curQTable = components[index].qTable;
  
                      // init 0
                      for (int z = 0; z < DCTSIZE2; z++) {
                          singleBlockData[z] = 0;
                      }
  
                      int s = 0, r = 0;
  
                      // Decode DC
                      s = curDCTable.decode(in);
                      if (s > 0) {
                          r = (int) in.readBits(s);
                          s = curDCTable.extend(r, s);
                      }
  
                      preDC[index] = s = preDC[index] + s;
                      singleBlockData[0] = s;
  
                      // Decode AC
                      for (int k = 1;;) {
                          s = curACTable.decode(in);
  
                          r = s >> 4;
                          s = s & 15;
  
                          if (s == 0) {
                              if (r == 15) {
                                  k += 16;
                                  continue;
                              } else {
                                  break;
                              }
                          } else {
                              k += r;
  
                              r = (int) in.readBits(s);
                              s = curACTable.extend(r, s);
  
                              // Output coefficient in natural (dezigzagged) order
                              singleBlockData[MarkerConstants.BLOCK_NATURAL_ORDER[k]] = s;
  
                              if (k >= 63) {
                                  break;
                              } else {
                                  k++;
                              }
                          }
                      }
                      // End decode block
  
                      if (fastIDCTMode) {
                          throw new UnsupportedOperationException("Not implemented yet");
                      } else {
                          inverseDCTCalculator.calculate(singleBlockData, 0, curQTable.getQ(), singleMCUData[index],
                                                         ctr * DCTSIZE2, components[index].getHorizonDCTScaledSize(),
                                                         components[index].getVerticaDCTScaledSize());
  
                      }
                  }
                  // End decode MCU
  
                  writeMCU();
  
                  restartsLeft--;
              }
  
              marker = nextMarker();
          } catch (JPEGMarkerException e) { // Unexpected marker occur
              marker = e.getMarker();
          } catch (EOFException e) {
              marker = -1;
          } catch (ArrayIndexOutOfBoundsException e) {
              // just ignore huffman decode error
              marker = -1;
              broken = true;
          }
  
          return marker;
      }