1 /* 2 * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.awt.image; 27 28 import java.awt.image.ImageConsumer; 29 import java.awt.image.ColorModel; 30 import java.util.Hashtable; 31 import java.awt.Rectangle; 32 33 /** 34 * An ImageFilter class for cropping images. 35 * This class extends the basic ImageFilter Class to extract a given 36 * rectangular region of an existing Image and provide a source for a 37 * new image containing just the extracted region. It is meant to 38 * be used in conjunction with a FilteredImageSource object to produce 39 * cropped versions of existing images. 40 * 41 * @see FilteredImageSource 42 * @see ImageFilter 43 * 44 * @author Jim Graham 45 */ 46 public class CropImageFilter extends ImageFilter { 47 int cropX; 48 int cropY; 49 int cropW; 50 int cropH; 51 52 /** 53 * Constructs a CropImageFilter that extracts the absolute rectangular 54 * region of pixels from its source Image as specified by the x, y, 55 * w, and h parameters. 56 * @param x the x location of the top of the rectangle to be extracted 57 * @param y the y location of the top of the rectangle to be extracted 58 * @param w the width of the rectangle to be extracted 59 * @param h the height of the rectangle to be extracted 60 */ 61 public CropImageFilter(int x, int y, int w, int h) { 62 cropX = x; 63 cropY = y; 64 cropW = w; 65 cropH = h; 66 } 67 68 @Override 69 public ImageFilter getScaledFilterInstance(double scaleX, double scaleY) { 70 Object instance = super.getScaledFilterInstance(scaleX, scaleY); 71 CropImageFilter filter = (CropImageFilter) instance; 72 filter.cropX = (int) Math.ceil(cropX * scaleX); 73 filter.cropY = (int) Math.ceil(cropY * scaleY); 74 filter.cropW = (int) Math.floor(cropW * scaleX); 75 filter.cropH = (int) Math.floor(cropH * scaleY); 76 return filter; 77 } 78 79 /** 80 * Passes along the properties from the source object after adding a 81 * property indicating the cropped region. 82 * This method invokes {@code super.setProperties}, 83 * which might result in additional properties being added. 84 * <p> 85 * Note: This method is intended to be called by the 86 * {@code ImageProducer} of the {@code Image} whose pixels 87 * are being filtered. Developers using 88 * this class to filter pixels from an image should avoid calling 89 * this method directly since that operation could interfere 90 * with the filtering operation. 91 */ 92 public void setProperties(Hashtable<?,?> props) { 93 @SuppressWarnings("unchecked") 94 Hashtable<Object,Object> p = (Hashtable<Object,Object>)props.clone(); 95 p.put("croprect", new Rectangle(cropX, cropY, cropW, cropH)); 96 super.setProperties(p); 97 } 98 99 /** 100 * Override the source image's dimensions and pass the dimensions 101 * of the rectangular cropped region to the ImageConsumer. 102 * <p> 103 * Note: This method is intended to be called by the 104 * {@code ImageProducer} of the {@code Image} whose 105 * pixels are being filtered. Developers using 106 * this class to filter pixels from an image should avoid calling 107 * this method directly since that operation could interfere 108 * with the filtering operation. 109 * @see ImageConsumer 110 */ 111 public void setDimensions(int w, int h) { 112 consumer.setDimensions(cropW, cropH); 113 } 114 115 /** 116 * Determine whether the delivered byte pixels intersect the region to 117 * be extracted and passes through only that subset of pixels that 118 * appear in the output region. 119 * <p> 120 * Note: This method is intended to be called by the 121 * {@code ImageProducer} of the {@code Image} whose 122 * pixels are being filtered. Developers using 123 * this class to filter pixels from an image should avoid calling 124 * this method directly since that operation could interfere 125 * with the filtering operation. 126 */ 127 public void setPixels(int x, int y, int w, int h, 128 ColorModel model, byte pixels[], int off, 129 int scansize) { 130 int x1 = x; 131 if (x1 < cropX) { 132 x1 = cropX; 133 } 134 int x2 = addWithoutOverflow(x, w); 135 if (x2 > cropX + cropW) { 136 x2 = cropX + cropW; 137 } 138 int y1 = y; 139 if (y1 < cropY) { 140 y1 = cropY; 141 } 142 143 int y2 = addWithoutOverflow(y, h); 144 if (y2 > cropY + cropH) { 145 y2 = cropY + cropH; 146 } 147 if (x1 >= x2 || y1 >= y2) { 148 return; 149 } 150 consumer.setPixels(x1 - cropX, y1 - cropY, (x2 - x1), (y2 - y1), 151 model, pixels, 152 off + (y1 - y) * scansize + (x1 - x), scansize); 153 } 154 155 /** 156 * Determine if the delivered int pixels intersect the region to 157 * be extracted and pass through only that subset of pixels that 158 * appear in the output region. 159 * <p> 160 * Note: This method is intended to be called by the 161 * {@code ImageProducer} of the {@code Image} whose 162 * pixels are being filtered. Developers using 163 * this class to filter pixels from an image should avoid calling 164 * this method directly since that operation could interfere 165 * with the filtering operation. 166 */ 167 public void setPixels(int x, int y, int w, int h, 168 ColorModel model, int pixels[], int off, 169 int scansize) { 170 int x1 = x; 171 if (x1 < cropX) { 172 x1 = cropX; 173 } 174 int x2 = addWithoutOverflow(x, w); 175 if (x2 > cropX + cropW) { 176 x2 = cropX + cropW; 177 } 178 int y1 = y; 179 if (y1 < cropY) { 180 y1 = cropY; 181 } 182 183 int y2 = addWithoutOverflow(y, h); 184 if (y2 > cropY + cropH) { 185 y2 = cropY + cropH; 186 } 187 if (x1 >= x2 || y1 >= y2) { 188 return; 189 } 190 consumer.setPixels(x1 - cropX, y1 - cropY, (x2 - x1), (y2 - y1), 191 model, pixels, 192 off + (y1 - y) * scansize + (x1 - x), scansize); 193 } 194 195 //check for potential overflow (see bug 4801285) 196 private int addWithoutOverflow(int x, int w) { 197 int x2 = x + w; 198 if ( x > 0 && w > 0 && x2 < 0 ) { 199 x2 = Integer.MAX_VALUE; 200 } else if( x < 0 && w < 0 && x2 > 0 ) { 201 x2 = Integer.MIN_VALUE; 202 } 203 return x2; 204 } 205 }