| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.sis.image; |
| |
| import java.util.Optional; |
| import java.awt.Dimension; |
| import java.awt.Rectangle; |
| import java.awt.image.Raster; |
| import java.awt.image.RenderedImage; |
| import java.awt.image.WritableRaster; |
| import java.awt.image.WritableRenderedImage; |
| import java.awt.image.RasterFormatException; |
| import org.apache.sis.internal.feature.Resources; |
| |
| |
| /** |
| * Iterator for the {@link SequenceType#LINEAR} traversal order. |
| * This iterator behaves as is the while image was a single tile. |
| * Calls to {@link #next()} move the current position by increasing the following values, in order: |
| * |
| * <ol> |
| * <li>Column index in image (from left to right)</li> |
| * <li>Row index in image (from top to bottom).</li> |
| * </ol> |
| * |
| * This class uses the {@link Raster} API for traversing the pixels of the image, |
| * i.e. it does not yet provide optimization for commonly used sample models. |
| * |
| * @author Johann Sorel (Geomatys) |
| * @author Martin Desruisseaux (Geomatys) |
| * @version 1.0 |
| * @since 1.0 |
| * @module |
| */ |
| final class LinearIterator extends DefaultIterator { |
| /** |
| * Creates an iterator for the given region in the given raster. |
| * |
| * @param input the raster which contains the sample values to read. |
| * @param output the raster where to write the sample values, or {@code null} for read-only iterator. |
| * @param subArea the raster region where to perform the iteration, or {@code null} for iterating over all the raster domain. |
| * @param window size of the window to use in {@link #createWindow(TransferType)} method, or {@code null} if none. |
| */ |
| LinearIterator(final Raster input, final WritableRaster output, final Rectangle subArea, final Dimension window) { |
| super(input, output, subArea, window); |
| } |
| |
| /** |
| * Creates an iterator for the given region in the given image. |
| * |
| * @param input the image which contains the sample values to read. |
| * @param output the image where to write the sample values, or {@code null} for read-only iterator. |
| * @param subArea the image region where to perform the iteration, or {@code null} for iterating over all the image domain. |
| * @param window size of the window to use in {@link #createWindow(TransferType)} method, or {@code null} if none. |
| */ |
| LinearIterator(final RenderedImage input, final WritableRenderedImage output, final Rectangle subArea, final Dimension window) { |
| super(input, output, subArea, window); |
| } |
| |
| /** |
| * Returns the order in which pixels are traversed. |
| */ |
| @Override |
| public Optional<SequenceType> getIterationOrder() { |
| return Optional.of(SequenceType.LINEAR); |
| } |
| |
| /** |
| * Moves the iterator to the next pixel on the current row, or to the next row. |
| * This method behaves as if the whole image was a single tile. |
| * |
| * @return {@code true} if the current pixel is valid, or {@code false} if there is no more pixels. |
| * @throws IllegalStateException if this iterator already reached end of iteration in a previous call |
| * to {@code next()}, and {@link #rewind()} or {@link #moveTo(int,int)} have not been invoked. |
| */ |
| @Override |
| public boolean next() { |
| if (++x >= currentUpperX) { // Move to next column, potentially on a different tile. |
| if (x < upperX) { |
| close(); // Must be invoked before `tileX` change. |
| tileX++; |
| } else { |
| x = lowerX; // Beginning of next row. |
| if (++y >= currentUpperY) { // Move to next line. |
| close(); // Must be invoked before `tileY` change. |
| if (++tileY >= tileUpperY) { |
| endOfIteration(); |
| return false; |
| } |
| } else if (tileX == tileLowerX) { |
| return true; // Beginning of next row is in the same tile. |
| } |
| close(); // Must be invoked before `tileX` change. |
| tileX = tileLowerX; |
| } |
| /* |
| * At this point the (x,y) pixel coordinates have been updated and are inside the domain of validity. |
| * We may need to change tile, either because we moved to the tile on the right or because we start a |
| * new row (in which case we need to move to the leftmost tile). The only case where we can skip tile |
| * change is when the image has only one tile width (in which case tileX == tileLowerX) and the next |
| * row is still on the same tile. |
| */ |
| if (fetchTile() > y) { |
| throw new RasterFormatException(Resources.format(Resources.Keys.IncompatibleTile_2, tileX, tileY)); |
| } |
| } |
| return true; |
| } |
| } |