Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.scene.effect;
027
028import javafx.beans.property.DoubleProperty;
029import javafx.beans.property.DoublePropertyBase;
030import javafx.beans.property.IntegerProperty;
031import javafx.beans.property.IntegerPropertyBase;
032import javafx.beans.property.ObjectProperty;
033import javafx.scene.Node;
034
035import com.sun.javafx.Utils;
036import com.sun.javafx.effect.EffectDirtyBits;
037import com.sun.javafx.effect.EffectUtils;
038import com.sun.javafx.geom.BaseBounds;
039import com.sun.javafx.geom.transform.BaseTransform;
040import com.sun.javafx.scene.BoundsAccessor;
041
042
043/**
044 * A blur effect using a simple box filter kernel, with separately
045 * configurable sizes in both dimensions, and an iteration parameter
046 * that controls the quality of the resulting blur.
047 *
048 * <p>
049 * Example:
050 * <pre><code>
051 * BoxBlur boxBlur = new BoxBlur();
052 * boxBlur.setWidth(10);
053 * boxBlur.setHeight(3);
054 * boxBlur.setIterations(3);
055 *
056 * Text text = new Text();
057 * text.setText("Blurry Text!");
058 * text.setFill(Color.web("0x3b596d"));
059 * text.setFont(Font.font(null, FontWeight.BOLD, 50));
060 * text.setX(10);
061 * text.setY(50);
062 * text.setEffect(boxBlur);
063 * </pre></code>
064 * <p>
065 * The code above produces the following:
066 * </p>
067 * <p>
068 * <img src="doc-files/boxblur.png"/>
069 * </p>
070 */
071public class BoxBlur extends Effect {
072
073    /**
074     * Creates a new instance of BoxBlur with default parameters.
075     */
076    public BoxBlur() {}
077
078    /**
079     * Creates a new instance of BoxBlur with specified width, height and
080     * iterations.
081     * @param width the horizontal dimension of the blur effect
082     * @param height the vertical dimension of the blur effect
083     * @param iterations the number of times to iterate the blur effect to
084     * improve its "quality" or "smoothness"
085     */
086    public BoxBlur(double width, double height, int iterations) {
087        setWidth(width);
088        setHeight(height);
089        setIterations(iterations);
090    }
091
092    @Override
093    com.sun.scenario.effect.BoxBlur impl_createImpl() {
094        return new com.sun.scenario.effect.BoxBlur();
095    };
096    /**
097     * The input for this {@code Effect}.
098     * If set to {@code null}, or left unspecified, a graphical image of
099     * the {@code Node} to which the {@code Effect} is attached will be
100     * used as the input.
101     * @defaultValue null
102     */
103    private ObjectProperty<Effect> input;
104
105
106    public final void setInput(Effect value) {
107        inputProperty().set(value);
108    }
109
110    public final Effect getInput() {
111        return input == null ? null : input.get();
112    }
113
114    public final ObjectProperty<Effect> inputProperty() {
115        if (input == null) {
116            input = new EffectInputProperty("input");
117        }
118        return input;
119    }
120
121    @Override
122    boolean impl_checkChainContains(Effect e) {
123        Effect localInput = getInput();
124        if (localInput == null)
125            return false;
126        if (localInput == e)
127            return true;
128        return localInput.impl_checkChainContains(e);
129    }
130
131    /**
132     * The horizontal dimension of the blur effect.
133     * The color information for a given pixel will be spread across
134     * a Box of the indicated width centered over the pixel.
135     * Values less than or equal to 1 will not spread the color data
136     * beyond the pixel where it originated from and so will have
137     * no effect.
138     * <pre>
139     *       Min:   0.0
140     *       Max: 255.0
141     *   Default:   5.0
142     *  Identity:  &lt;1.0
143     * </pre>
144     * @defaultValue 5.0
145     */
146    private DoubleProperty width;
147
148
149    public final void setWidth(double value) {
150        widthProperty().set(value);
151    }
152
153    public final double getWidth() {
154        return width == null ? 5 : width.get();
155    }
156
157    public final DoubleProperty widthProperty() {
158        if (width == null) {
159            width = new DoublePropertyBase(5) {
160
161                @Override
162                public void invalidated() {
163                    markDirty(EffectDirtyBits.EFFECT_DIRTY);
164                    effectBoundsChanged();
165                }
166
167                @Override
168                public Object getBean() {
169                    return BoxBlur.this;
170                }
171
172                @Override
173                public String getName() {
174                    return "width";
175                }
176            };
177        }
178        return width;
179    }
180
181    /**
182     * The vertical dimension of the blur effect.
183     * The color information for a given pixel will be spread across
184     * a Box of the indicated height centered over the pixel.
185     * Values less than or equal to 1 will not spread the color data
186     * beyond the pixel where it originated from and so will have
187     * no effect.
188     * <pre>
189     *       Min:   0.0
190     *       Max: 255.0
191     *   Default:   5.0
192     *  Identity:  &lt;1.0
193     * </pre>
194     * @defaultValue 5.0
195     */
196    private DoubleProperty height;
197
198
199    public final void setHeight(double value) {
200        heightProperty().set(value);
201    }
202
203    public final double getHeight() {
204        return height == null ? 5 : height.get();
205    }
206
207    public final DoubleProperty heightProperty() {
208        if (height == null) {
209            height = new DoublePropertyBase(5) {
210
211                @Override
212                public void invalidated() {
213                    markDirty(EffectDirtyBits.EFFECT_DIRTY);
214                    effectBoundsChanged();
215                }
216
217                @Override
218                public Object getBean() {
219                    return BoxBlur.this;
220                }
221
222                @Override
223                public String getName() {
224                    return "height";
225                }
226            };
227        }
228        return height;
229    }
230
231    /**
232     * The number of times to iterate the blur effect to improve its
233     * "quality" or "smoothness".
234     * Iterating the effect 3 times approximates the quality of a
235     * Gaussian Blur to within 3%.
236     * <pre>
237     *       Min:   0
238     *       Max:   3
239     *   Default:   1
240     *  Identity:   0
241     * </pre>
242     * @defaultValue 1
243     */
244    private IntegerProperty iterations;
245
246
247    public final void setIterations(int value) {
248        iterationsProperty().set(value);
249    }
250
251    public final int getIterations() {
252        return iterations == null ? 1 : iterations.get();
253    }
254
255    public final IntegerProperty iterationsProperty() {
256        if (iterations == null) {
257            iterations = new IntegerPropertyBase(1) {
258
259                @Override
260                public void invalidated() {
261                    markDirty(EffectDirtyBits.EFFECT_DIRTY);
262                    effectBoundsChanged();
263                }
264
265                @Override
266                public Object getBean() {
267                    return BoxBlur.this;
268                }
269
270                @Override
271                public String getName() {
272                    return "iterations";
273                }
274            };
275        }
276        return iterations;
277    }
278
279    private int getClampedWidth() {
280        return Utils.clamp(0, (int) getWidth(), 255);
281    }
282
283    private int getClampedHeight() {
284        return Utils.clamp(0, (int) getHeight(), 255);
285    }
286
287    private int getClampedIterations() {
288        return Utils.clamp(0, getIterations(), 3);
289    }
290
291    @Override
292    void impl_update() {
293        Effect localInput = getInput();
294        if (localInput != null) {
295            localInput.impl_sync();
296        }
297
298        com.sun.scenario.effect.BoxBlur peer =
299                (com.sun.scenario.effect.BoxBlur) impl_getImpl();
300        peer.setInput(localInput == null ? null : localInput.impl_getImpl());
301        peer.setHorizontalSize(getClampedWidth());
302        peer.setVerticalSize(getClampedHeight());
303        peer.setPasses(getClampedIterations());
304    }
305
306    /**
307     * @treatAsPrivate implementation detail
308     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
309     */
310    @Deprecated
311    @Override
312    public BaseBounds impl_getBounds(BaseBounds bounds,
313                                     BaseTransform tx,
314                                     Node node,
315                                     BoundsAccessor boundsAccessor) {
316        bounds = EffectUtils.getInputBounds(bounds,
317                                            BaseTransform.IDENTITY_TRANSFORM,
318                                            node, boundsAccessor,
319                                            getInput());
320
321        int localIterations = getClampedIterations();
322
323        int hgrow = EffectUtils.getKernelSize(getClampedWidth(), localIterations);
324        int vgrow = EffectUtils.getKernelSize(getClampedHeight(), localIterations);
325
326        bounds = bounds.deriveWithPadding(hgrow, vgrow, 0);
327
328        return EffectUtils.transformBounds(tx, bounds);
329    }
330
331    /**
332     * 
333     * @treatAsPrivate implementation detail
334     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
335     */
336    @Deprecated
337    @Override
338    public Effect impl_copy() {
339        BoxBlur bb = new BoxBlur(this.getWidth(), this.getHeight(), this.getIterations());
340        bb.setInput(this.getInput());
341        return bb;
342    }
343}