1 /* 2 * Copyright (c) 1995, 2018, 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 /** 69 * Passes along the properties from the source object after adding a 70 * property indicating the cropped region. 71 * This method invokes {@code super.setProperties}, 72 * which might result in additional properties being added. 73 * <p> 74 * Note: This method is intended to be called by the 75 * {@code ImageProducer} of the {@code Image} whose pixels 76 * are being filtered. Developers using 77 * this class to filter pixels from an image should avoid calling 78 * this method directly since that operation could interfere 79 * with the filtering operation. 80 */ 81 public void setProperties(Hashtable<?,?> props) { 82 @SuppressWarnings("unchecked") 83 Hashtable<Object,Object> p = (Hashtable<Object,Object>)props.clone(); 84 p.put("croprect", new Rectangle(cropX, cropY, cropW, cropH)); 85 super.setProperties(p); 86 } 87 88 /** 89 * Override the source image's dimensions and pass the dimensions 90 * of the rectangular cropped region to the ImageConsumer. 91 * <p> 92 * Note: This method is intended to be called by the 93 * {@code ImageProducer} of the {@code Image} whose 94 * pixels are being filtered. Developers using 95 * this class to filter pixels from an image should avoid calling 96 * this method directly since that operation could interfere 97 * with the filtering operation. 98 * @see ImageConsumer 99 */ 100 public void setDimensions(int w, int h) { 101 consumer.setDimensions(cropW, cropH); 102 } 103 104 /** 105 * Determine whether the delivered byte pixels intersect the region to 106 * be extracted and passes through only that subset of pixels that 107 * appear in the output region. 108 * <p> 109 * Note: This method is intended to be called by the 110 * {@code ImageProducer} of the {@code Image} whose 111 * pixels are being filtered. Developers using 112 * this class to filter pixels from an image should avoid calling 113 * this method directly since that operation could interfere 114 * with the filtering operation. 115 */ 116 public void setPixels(int x, int y, int w, int h, 117 ColorModel model, byte[] pixels, int off, 118 int scansize) { 119 int x1 = x; 120 if (x1 < cropX) { 121 x1 = cropX; 122 } 123 int x2 = addWithoutOverflow(x, w); 124 if (x2 > cropX + cropW) { 125 x2 = cropX + cropW; 126 } 127 int y1 = y; 128 if (y1 < cropY) { 129 y1 = cropY; 130 } 131 132 int y2 = addWithoutOverflow(y, h); 133 if (y2 > cropY + cropH) { 134 y2 = cropY + cropH; 135 } 136 if (x1 >= x2 || y1 >= y2) { 137 return; 138 } 139 consumer.setPixels(x1 - cropX, y1 - cropY, (x2 - x1), (y2 - y1), 140 model, pixels, 141 off + (y1 - y) * scansize + (x1 - x), scansize); 142 } 143 144 /** 145 * Determine if the delivered int pixels intersect the region to 146 * be extracted and pass through only that subset of pixels that 147 * appear in the output region. 148 * <p> 149 * Note: This method is intended to be called by the 150 * {@code ImageProducer} of the {@code Image} whose 151 * pixels are being filtered. Developers using 152 * this class to filter pixels from an image should avoid calling 153 * this method directly since that operation could interfere 154 * with the filtering operation. 155 */ 156 public void setPixels(int x, int y, int w, int h, 157 ColorModel model, int[] pixels, int off, 158 int scansize) { 159 int x1 = x; 160 if (x1 < cropX) { 161 x1 = cropX; 162 } 163 int x2 = addWithoutOverflow(x, w); 164 if (x2 > cropX + cropW) { 165 x2 = cropX + cropW; 166 } 167 int y1 = y; 168 if (y1 < cropY) { 169 y1 = cropY; 170 } 171 172 int y2 = addWithoutOverflow(y, h); 173 if (y2 > cropY + cropH) { 174 y2 = cropY + cropH; 175 } 176 if (x1 >= x2 || y1 >= y2) { 177 return; 178 } 179 consumer.setPixels(x1 - cropX, y1 - cropY, (x2 - x1), (y2 - y1), 180 model, pixels, 181 off + (y1 - y) * scansize + (x1 - x), scansize); 182 } 183 184 //check for potential overflow (see bug 4801285) 185 private int addWithoutOverflow(int x, int w) { 186 int x2 = x + w; 187 if ( x > 0 && w > 0 && x2 < 0 ) { 188 x2 = Integer.MAX_VALUE; 189 } else if( x < 0 && w < 0 && x2 > 0 ) { 190 x2 = Integer.MIN_VALUE; 191 } 192 return x2; 193 } 194 }