/** * 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; }