/**
  * Returns a list of tiles constructed from the given array of files. Every file in the given
  * array must exist, be a valid image and have a valid <cite>World File</cite>, i.e. a file of the
  * same name in the same directory then the image file, but with an extension like {@code ".tfw"}
  * (for TIFF images) or {@code ".jgw"} (for JPEG images).
  *
  * <p>This method loads the World Files and fetches the image sizes immediately. The world file
  * applies to the first image in the file. If the file contains more than one image, then each
  * additional image is assumed to represent the same data than the first image at a different
  * resolution.
  *
  * <p>{@section Customization} If the files contain many images but those images are
  * <strong>not</strong> overviews of the first image at different resolution, then subclasses can
  * use only a specific image by overriding this method as below, where {@code imageIndex} is the
  * index of the image to use (typically 0):
  *
  * <p>{@preformat java public List<Tile> listTiles(final ImageReaderSpi provider, final Path...
  * inputs) throws IOException { final List<Tile> tiles = new ArrayList<Tile>(inputs.length); for
  * (final Path input : inputs) { tiles.add(new Tile(provider, input, imageIndex)); } return tiles;
  * } }
  *
  * <p>This method is invoked by {@link #create(Path, PathMatcher, ImageReaderSpi)}, so it can be
  * overridden for controlling the tiles to be built when {@code TileManagerFactory} scans a
  * directory.
  *
  * @param provider The image reader provider to use. If {@code null}, the provider will be
  *     inferred from each input. If it can't be inferred, then an exception is thrown.
  * @param inputs The image files.
  * @return The tiles constructed from the image files.
  * @throws IOException If no <cite>World File</cite> were found for a given image file, or if an
  *     error occurred while reading a file.
  * @see Tile#Tile(ImageReaderSpi, File, int)
  * @since 3.18
  */
 public List<Tile> listTiles(final ImageReaderSpi provider, final Path... inputs)
     throws IOException {
   try (final TileReaderPool readers = new TileReaderPool()) {
     final Set<ImageReaderSpi> providers = new HashSet<>();
     final List<Tile> tiles = new ArrayList<>(inputs.length);
     for (final Path input : inputs) {
       tiles.addAll(toTiles(provider, readers, providers, input));
     }
     readers.dispose();
     return tiles;
   }
 }
  private List<Tile> toTiles(
      ImageReaderSpi provider, TileReaderPool readers, Set<ImageReaderSpi> providers, Path input)
      throws IOException {

    // Creates the tile for the first image, which usually have the maximal resolution.
    // The Tile constructor will read the TFW file and infer a provider if the given
    // 'provider' argument is null. If this is a new provider, then we need to declare
    // it to the pool of image readers before to use it.
    final List<Tile> tiles = new ArrayList<>();
    final Tile root = new Tile(provider, input, 0);
    if (providers.add(root.getImageReaderSpi())) {
      readers.setProviders(providers);
    }

    final AffineTransform scaledGridToCRS = new AffineTransform();
    final AffineTransform gridToCRS = root.getPendingGridToCRS(false);
    final ImageReader reader = root.getImageReader(readers, true, true);
    final int numImages = reader.getNumImages(false); // Result may be -1.
    for (int index = 0; index != numImages; index++) { // Intentional use of !=, not <.
      final int width, height;
      try {
        width = reader.getWidth(index);
        height = reader.getHeight(index);
      } catch (IndexOutOfBoundsException e) {
        // As explained in ImageReader javadoc, this approach is sometime
        // more efficient than invoking reader.getNumImages(true) first.
        break;
      }
      final Tile tile;
      if (index == 0) {
        tile = root;
      } else {
        final Rectangle region = root.getRegion();
        scaledGridToCRS.setTransform(new AffineTransform(gridToCRS));
        scaledGridToCRS.scale(region.width / (double) width, region.height / (double) height);
        tile = new Tile(root.getImageReaderSpi(), input, index, region, scaledGridToCRS);
      }
      tile.setSize(width, height);
      tiles.add(tile);
    }
    reader.dispose();
    return tiles;
  }