1 /* 2 * Copyright (c) 2008, 2013, 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 com.sun.scenario.effect; 27 28 import com.sun.javafx.geom.BaseBounds; 29 import com.sun.javafx.geom.DirtyRegionContainer; 30 import com.sun.javafx.geom.DirtyRegionPool; 31 import com.sun.javafx.geom.RectBounds; 32 import com.sun.javafx.geom.Rectangle; 33 import com.sun.javafx.geom.transform.BaseTransform; 34 import com.sun.scenario.effect.impl.Renderer; 35 import com.sun.scenario.effect.impl.state.BoxBlurState; 36 import com.sun.scenario.effect.impl.state.LinearConvolveKernel; 37 38 /** 39 * A blur effect using a box-shaped convolution kernel, with a configurable 40 * size for each dimension of the kernel and a number of passes to control 41 * the quality of the blur. 42 */ 43 public class BoxBlur extends LinearConvolveCoreEffect { 44 45 private final BoxBlurState state = new BoxBlurState(); 46 47 /** 48 * Constructs a new {@code BoxBlur} effect with 49 * the default blur sizes (1, 1) 50 * and the default number of passes (1), 51 * using the default input for source data. 52 * This is a shorthand equivalent to: 53 * <pre> 54 * new BoxBlur(1, 1, 1, DefaultInput) 55 * </pre> 56 */ 57 public BoxBlur() { 58 this(1.0f, 1.0f); 59 } 60 61 /** 62 * Constructs a new {@code BoxBlur} effect with 63 * the given blur sizes 64 * and the default number of passes (1), 65 * using the default input for source data. 66 * This is a shorthand equivalent to: 67 * <pre> 68 * new BoxBlur(hsize, vsize, 1, DefaultInput) 69 * </pre> 70 * 71 * @param hsize the horizontal size of the BoxBlur kernel 72 * @param vsize the vertical size of the BoxBlur kernel 73 * @throws IllegalArgumentException if either {@code hsize} 74 * or {@code vsize} is outside the allowable range 75 */ 76 public BoxBlur(float hsize, float vsize) { 77 this(hsize, vsize, 1, DefaultInput); 78 } 79 80 /** 81 * Constructs a new {@code BoxBlur} effect with 82 * the given blur sizes 83 * and number of passes, 84 * using the default input for source data. 85 * This is a shorthand equivalent to: 86 * <pre> 87 * new BoxBlur(hsize, vsize, passes, DefaultInput) 88 * </pre> 89 * 90 * @param hsize the horizontal size of the BoxBlur kernel 91 * @param vsize the vertical size of the BoxBlur kernel 92 * @param passes the number of blur passes to execute 93 * @throws IllegalArgumentException if either {@code hsize} 94 * or {@code vsize} or {@code passes} 95 * is outside the allowable range 96 */ 97 public BoxBlur(float hsize, float vsize, int passes) { 98 this(hsize, vsize, passes, DefaultInput); 99 } 100 101 /** 102 * Constructs a new {@code BoxBlur} effect with 103 * the given blur sizes 104 * and number of passes, 105 * using the output of the specified effect for source data. 106 * 107 * @param hsize the horizontal size of the BoxBlur kernel 108 * @param vsize the vertical size of the BoxBlur kernel 109 * @param passes the number of blur passes to execute 110 * @param input the single input {@code Effect} 111 * @throws IllegalArgumentException if either {@code hsize} 112 * or {@code vsize} or {@code passes} 113 * is outside the allowable range 114 */ 115 public BoxBlur(float hsize, float vsize, int passes, Effect input) { 116 super(input); 117 setHorizontalSize(hsize); 118 setVerticalSize(vsize); 119 setPasses(passes); 120 } 121 122 @Override 123 LinearConvolveKernel getState() { 124 return state; 125 } 126 127 /** 128 * Returns the input for this {@code Effect}. 129 * 130 * @return the input for this {@code Effect} 131 */ 132 public final Effect getInput() { 133 return getInputs().get(0); 134 } 135 136 /** 137 * Sets the input for this {@code Effect}. 138 * Sets the input for this {@code Effect} to a specific 139 * {@code Effect} or to the default input if {@code input} is 140 * {@code null}. 141 * 142 * @param input the input for this {@code Effect} 143 */ 144 public void setInput(Effect input) { 145 setInput(0, input); 146 } 147 148 /** 149 * Returns the horizontal size of the effect kernel. 150 * 151 * @return the horizontal size of the effect kernel 152 */ 153 public float getHorizontalSize() { 154 return state.getHsize(); 155 } 156 157 /** 158 * Sets the horizontal size of the effect kernel. 159 * <pre> 160 * Min: 0 161 * Max: 255 162 * Default: 1 163 * Identity: 0 164 * </pre> 165 * 166 * @param hsize the horizontal size of the effect kernel 167 * @throws IllegalArgumentException if {@code hsize} 168 * is outside the allowable range 169 */ 170 public final void setHorizontalSize(float hsize) { 171 state.setHsize(hsize); 172 } 173 174 /** 175 * Returns the vertical size of the effect kernel. 176 * 177 * @return the vertical size of the effect kernel 178 */ 179 public float getVerticalSize() { 180 return state.getVsize(); 181 } 182 183 /** 184 * Sets the vertical size of the effect kernel. 185 * <pre> 186 * Min: 0 187 * Max: 255 188 * Default: 1 189 * Identity: 0 190 * </pre> 191 * 192 * @param vsize the vertical size of the effect kernel 193 * @throws IllegalArgumentException if {@code vsize} 194 * is outside the allowable range 195 */ 196 public final void setVerticalSize(float vsize) { 197 state.setVsize(vsize); 198 } 199 200 /** 201 * Returns the number of passes of the effect kernel to control the 202 * quality of the blur. 203 * 204 * @return the number of passes of the effect kernel 205 */ 206 public int getPasses() { 207 return state.getBlurPasses(); 208 } 209 210 /** 211 * Sets the number of passes of the effect kernel to control the 212 * quality of the blur. 213 * <pre> 214 * Min: 0 215 * Max: 3 216 * Default: 1 217 * Identity: 0 218 * </pre> 219 * A setting of 1 creates a low quality blur. A setting of 3 creates 220 * a blur that is very close to a Gaussian blur. 221 * 222 * @param passes 223 * @throws IllegalArgumentException if {@code passes} is outside the 224 * allowable range 225 */ 226 public final void setPasses(int passes) { 227 state.setBlurPasses(passes); 228 } 229 230 @Override 231 public AccelType getAccelType(FilterContext fctx) { 232 return Renderer.getRenderer(fctx).getAccelType(); 233 } 234 235 @Override 236 public BaseBounds getBounds(BaseTransform transform, Effect defaultInput) { 237 BaseBounds r = super.getBounds(null, defaultInput); 238 int hgrow = state.getKernelSize(0) / 2; 239 int vgrow = state.getKernelSize(1) / 2; 240 RectBounds ret = new RectBounds(r.getMinX(), r.getMinY(), r.getMaxX(), r.getMaxY()); 241 ret.grow(hgrow, vgrow); 242 return transformBounds(transform, ret); 243 } 244 245 @Override 246 public Rectangle getResultBounds(BaseTransform transform, 247 Rectangle outputClip, 248 ImageData... inputDatas) 249 { 250 Rectangle r = inputDatas[0].getTransformedBounds(null); 251 r = state.getResultBounds(r, 0); 252 r = state.getResultBounds(r, 1); 253 r.intersectWith(outputClip); 254 return r; 255 } 256 257 @Override 258 public boolean reducesOpaquePixels() { 259 if (!state.isNop()) { 260 return true; 261 } 262 final Effect input = getInput(); 263 return input != null && input.reducesOpaquePixels(); 264 } 265 266 @Override 267 public DirtyRegionContainer getDirtyRegions(Effect defaultInput, DirtyRegionPool regionPool) { 268 Effect di = getDefaultedInput(0, defaultInput); 269 DirtyRegionContainer drc = di.getDirtyRegions(defaultInput, regionPool); 270 271 drc.grow(state.getKernelSize(0) / 2, state.getKernelSize(1) / 2); 272 273 return drc; 274 } 275 }