/* JAI-Ext - OpenSource Java Advanced Image Extensions Library * http://www.geo-solutions.it/ * Copyright 2014 GeoSolutions * Licensed 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 it.geosolutions.jaiext.crop; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.RenderingHints.Key; import java.awt.geom.Rectangle2D; import java.awt.image.RenderedImage; import java.awt.image.renderable.ParameterBlock; import java.awt.image.renderable.RenderedImageFactory; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; import javax.media.jai.ImageLayout; import javax.media.jai.JAI; import javax.media.jai.ROI; import javax.media.jai.ROIShape; import javax.media.jai.operator.MosaicDescriptor; import com.sun.media.jai.opimage.RIFUtil; import it.geosolutions.jaiext.mosaic.MosaicOpImage; import it.geosolutions.jaiext.range.Range; import it.geosolutions.jaiext.range.RangeFactory; /** * The image factory for the Crop operator. * * @author Andrea Aime */ public class CropCRIF implements RenderedImageFactory { public CropCRIF() { } /** * Creates a new instance of {@link CropOpImage} in the rendered layer. * * @param paramBlock * parameter block with parameters minx, miny, width height * * @param renderHints * optional rendering hints which may be used to pass down a tile scheduler and tile * cache */ public RenderedImage create(ParameterBlock paramBlock, RenderingHints renderingHints) { RenderedImage image = (RenderedImage) paramBlock.getSource(0); float x = paramBlock.getFloatParameter(CropDescriptor.X_ARG); float y = paramBlock.getFloatParameter(CropDescriptor.Y_ARG); float width = paramBlock.getFloatParameter(CropDescriptor.WIDTH_ARG); float height = paramBlock.getFloatParameter(CropDescriptor.HEIGHT_ARG); ROI roi = (ROI) paramBlock.getObjectParameter(CropDescriptor.ROI_ARG); Range noData = (Range) paramBlock.getObjectParameter(CropDescriptor.NO_DATA_ARG); noData = RangeFactory.convert(noData, image.getSampleModel().getDataType()); double[] destNoData = (double[]) paramBlock.getObjectParameter(CropDescriptor.DEST_NO_DATA_ARG); // only leave tile cache and tile scheduler (we can't instantiate directly RenderingHints // as it won't allow for a null tile cache, even if the rest of JAI handles that peachy Map<Key, Object> tmp = new HashMap<RenderingHints.Key, Object>(); for (Object key : renderingHints.keySet()) { if (key == JAI.KEY_TILE_CACHE || key == JAI.KEY_TILE_SCHEDULER) { tmp.put((Key) key, renderingHints.get(key)); } } RenderingHints local = new RenderingHints(tmp); // selection of the layout ImageLayout layout = RIFUtil.getImageLayoutHint(local); // Creation of a Rectangle object containing the starting bounds Rectangle bounds = new Rectangle2D.Float(x, y, width, height).getBounds(); // Initialization of the final bounds Rectangle finalBounds = bounds; // If roi is present the final bounds are intersected with the ROI object if (roi != null) { Rectangle roiBounds = roi.getBounds(); if (finalBounds.contains(roiBounds)) { finalBounds = roiBounds; } else { finalBounds.intersection(roiBounds); } } // The final bounds coordinates are taken x = (float) finalBounds.getMinX(); y = (float) finalBounds.getMinY(); width = (float) finalBounds.getWidth(); height = (float) finalBounds.getHeight(); // If noData are present, the MosaicOpImage is used instead of the crop if (noData != null) { // The calculated bounds are taken as an input roi roi = new ROIShape(finalBounds); // The source image is taken as a list of data List<RenderedImage> listSrc = new Vector<RenderedImage>(); listSrc.add(image); // layout settings if (layout == null) { layout = new ImageLayout(); } layout.setHeight(finalBounds.height); layout.setWidth(finalBounds.width); layout.setMinX(finalBounds.x); layout.setMinY(finalBounds.y); // Mosaic operation image = new MosaicOpImage(listSrc, layout, local, MosaicDescriptor.MOSAIC_TYPE_OVERLAY, null, new ROI[] { roi }, null, destNoData, new Range[] { noData }); return image; } // If noData are not present, then the crop operation is performed return new CropOpImage(image, x, y, width, height, local); } }