docs: private static IndexColorModel createIndexColorModel(BufferedImage pImage, int pNumberOfColors, int pHints) {
          // TODO: Use ImageUtil.hasTransparentPixels(pImage, true) ||
          // -- haraldK, 20021024, experimental, try to use one transparent pixel
          boolean useTransparency = isTransparent(pHints);
  
          if (useTransparency) {
              pNumberOfColors--;
          }
  
          //System.out.println("Transp: " + useTransparency + " colors: " + pNumberOfColors);
          int width = pImage.getWidth();
          int height = pImage.getHeight();
  
          // Using 4 bits from R, G & B.
          @SuppressWarnings("unchecked")
          List<Counter>[] colors = new List[1 << 12];// [4096]
  
          // Speedup, doesn't decrease image quality much
          int step = 1;
  
          if (isFast(pHints)) {
              step += (width * height / 16384);// 128x128px
          }
          int sampleCount = 0;
          int rgb;
  
          //for (int x = 0; x < width; x++) {
          //for (int y = 0; y < height; y++) {
          for (int x = 0; x < width; x++) {
              for (int y = x % step; y < height; y += step) {
                  // Count the number of color samples
                  sampleCount++;
  
                  // Get ARGB pixel from image
                  rgb = (pImage.getRGB(x, y) & 0xFFFFFF);
  
                  // Get index from high four bits of each component.
                  int index = (((rgb & 0xF00000) >>> 12) | ((rgb & 0x00F000) >>> 8) | ((rgb & 0x0000F0) >>> 4));
  
                  // Get the 'hash vector' for that key.
                  List<Counter> v = colors[index];
  
                  if (v == null) {
                      // No colors in this bin yet so create vector and
                      // add color.
                      v = new ArrayList<Counter>();
                      v.add(new Counter(rgb));
                      colors[index] = v;
                  }
                  else {
                      // Find our color in the bin or create a counter for it.
                      Iterator i = v.iterator();
  
                      while (true) {
                          if (i.hasNext()) {
                              // try adding our color to each counter...
                              if (((Counter) i.next()).add(rgb)) {
                                  break;
                              }
                          }
                          else {
                              v.add(new Counter(rgb));
                              break;
                          }
                      }
                  }
              }
          }
  
          // All colours found, reduce to pNumberOfColors
          int numberOfCubes = 1;
          int fCube = 0;
          Cube[] cubes = new Cube[pNumberOfColors];
  
          cubes[0] = new Cube(colors, sampleCount);
  
          //cubes[0] = new Cube(colors, width * height);
          while (numberOfCubes < pNumberOfColors) {
              while (cubes[fCube].isDone()) {
                  fCube++;
                  
                  if (fCube == numberOfCubes) {
                      break;
                  }
              }
              
              if (fCube == numberOfCubes) {
                  break;
              }
              
              Cube cube = cubes[fCube];
              Cube newCube = cube.split();
  
              if (newCube != null) {
                  if (newCube.count > cube.count) {
                      Cube tmp = cube;
  
                      cube = newCube;
                      newCube = tmp;
                  }
  
                  int j = fCube;
                  int count = cube.count;
  
                  for (int i = fCube + 1; i < numberOfCubes; i++) {
                      if (cubes[i].count < count) {
                          break;
                      }
                      cubes[j++] = cubes[i];
                  }
  
                  cubes[j++] = cube;
                  count = newCube.count;
  
                  while (j < numberOfCubes) {
                      if (cubes[j].count < count) {
                          break;
                      }
                      j++;
                  }
  
                  System.arraycopy(cubes, j, cubes, j + 1, numberOfCubes - j);
  
                  cubes[j/*++*/] = newCube;
                  numberOfCubes++;
              }
          }
  
          // Create RGB arrays with correct number of colors
          // If we have transparency, the last color will be the transparent one
          byte[] r = new byte[useTransparency ? numberOfCubes + 1 : numberOfCubes];
          byte[] g = new byte[useTransparency ? numberOfCubes + 1 : numberOfCubes];
          byte[] b = new byte[useTransparency ? numberOfCubes + 1 : numberOfCubes];
  
          for (int i = 0; i < numberOfCubes; i++) {
              int val = cubes[i].averageColor();
  
              r[i] = (byte) ((val >> 16) & 0xFF);
              g[i] = (byte) ((val >> 8) & 0xFF);
              b[i] = (byte) ((val) & 0xFF);
  
              //System.out.println("Color [" + i + "]: #" +
              //                   (((val>>16)<16)?"0":"") +
              //                   Integer.toHexString(val));
          }
  
          // For some reason using less than 8 bits causes a bug in the dither
          //  - transparency added to all totally black colors?
          int numOfBits = 8;
  
          // -- haraldK, 20021024, as suggested by Thomas E. Deweese
          // plus adding a transparent pixel
          IndexColorModel icm;
          if (useTransparency) {
              icm = new InverseColorMapIndexColorModel(numOfBits, r.length, r, g, b, r.length - 1);
          }
          else {
              icm = new InverseColorMapIndexColorModel(numOfBits, r.length, r, g, b);
          }
          return icm;
      }