docs: protected int decodeProgressiveScan(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;
          }
  
          int[] componentIndexes = readScanHeader();
  
          validateProgressiveParam();
  
          Component[] components = frameHeader.getComponents();
  
          // Calculate MCU size
          calculateMCUs(componentIndexes, components);
  
          // AC scans can only contain one component, DC scans may contain more
          // than one component
          try {
              int restartsLeft = restartInterval;
              in.resetBuffer();
              resetDecoder();
              HuffmanTable curDCTable;
              HuffmanTable curACTable;
  
              /*
               * Note:If the compressed image data is non-interleaved, the MCU is defined to be one data unit
               */
              // interleaved
              if (scanHeader.getSs() == 0) {
                  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, blkIndex = 0; c < blocksNumInMCU; c++) {
                          index = blocksInMCU[c];
  
                          if (c == 0) {
                              blkIndex = 0;
                          } else {
                              if (index == blocksInMCU[c - 1]) {
                                  blkIndex++;
                              } else {
                                  blkIndex = 0;
                              }
                          }
                          curDCTable = components[index].dcHuffTable;
  
                          if (scanHeader.getAh() == 0) { // first scan
                              // only DC
                              decodeDCFirst(index, curDCTable, scanHeader.getAl(), allMCUDatas[index][m], blkIndex);
                          } else { // subsequent scans
                              // only DC
                              decodeDCRefine(scanHeader.getAl(), allMCUDatas[index][m], blkIndex);
  
                          }
                      }
                      // End decode MCU
  
                      restartsLeft--;
                  }
              } else {
                  // non-interleaved
                  int componentH = components[componentIndexes[0]].getH();
                  int componentV = components[componentIndexes[0]].getV();
                  int blksInVertica = (componentV == 1 ? MCUsPerColumn : ((frameHeader.getY() + 7) / DCTSIZE));
                  int blksInHorizon = (componentH == 1 ? MCUsPerRow : ((frameHeader.getX() + 7) / DCTSIZE));
                  int MCUIndex = 0, blkIndex = 0, secondBlkIndex = (componentH == 1 ? 1 : 2);
  
                  curACTable = components[componentIndexes[0]].acHuffTable;
  
                  for (int v = 0; v < blksInVertica; v++) {
                      MCUIndex = (v / componentV) * MCUsPerRow - 1;
  
                      for (int h = 0; h < blksInHorizon; h++) {
                          if (h % componentH == 0) {
                              MCUIndex++;
                              blkIndex = 0;
  
                              if (v % componentV != 0) {
                                  blkIndex = secondBlkIndex;
                              }
                          }
  
                          // 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;
                          }
  
                          if (scanHeader.getAh() == 0) {
                              decodeACFirst(curACTable, scanHeader.getSs(), scanHeader.getSe(), scanHeader.getAl(),
                                            allMCUDatas[componentIndexes[0]][MCUIndex], blkIndex);
                          } else {
                              decodeACRefine(curACTable, scanHeader.getSs(), scanHeader.getSe(), scanHeader.getAl(),
                                             allMCUDatas[componentIndexes[0]][MCUIndex], blkIndex);
                          }
  
                          blkIndex++;
  
                          /* There is always only one block per MCU */
                          restartsLeft--;
                      }
                  }
              }
  
              marker = nextMarker();
          } catch (JPEGMarkerException e) {
              marker = e.getMarker();
          } catch (EOFException e) {
              marker = -1;
          } catch (ArrayIndexOutOfBoundsException e) {
              // Note : just ignore huffman decode error
              marker = -1;
              broken = true;
          }
  
          return marker;
      }