All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.scenario.effect.Blend Maven / Gradle / Ivy

There is a newer version: 24-ea+15
Show newest version
/*
 * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.scenario.effect;

import com.sun.javafx.geom.Point2D;
import com.sun.javafx.geom.Rectangle;
import com.sun.javafx.geom.transform.BaseTransform;
import com.sun.scenario.effect.impl.state.RenderState;

/**
 * An effect that blends the two inputs together using one of the
 * pre-defined {@code Mode}s.
 */
public class Blend extends CoreEffect {

    /**
     * A blending mode that defines the manner in which the inputs
     * are composited together.
     * Each {@code Mode} describes a mathematical equation that
     * combines premultiplied inputs to produce some premultiplied result.
     */
    public enum Mode {
        /**
         * The top input is blended over the bottom input.
         * (Equivalent to the Porter-Duff "source over destination" rule.)
         * 

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      Cr = Ctop + Cbot*(1-Atop)
         * 
*/ SRC_OVER, /** * The part of the top input lying inside of the bottom input * is kept in the resulting image. * (Equivalent to the Porter-Duff "source in destination" rule.) *

* Thus: *

         *      Ar = Atop*Abot
         *      Cr = Ctop*Abot
         * 
*/ SRC_IN, /** * The part of the top input lying outside of the bottom input * is kept in the resulting image. * (Equivalent to the Porter-Duff "source held out by destination" * rule.) *

* Thus: *

         *      Ar = Atop*(1-Abot)
         *      Cr = Ctop*(1-Abot)
         * 
*/ SRC_OUT, /** * The part of the top input lying inside of the bottom input * is blended with the bottom input. * (Equivalent to the Porter-Duff "source atop destination" rule.) *

* Thus: *

         *      Ar = Atop*Abot + Abot*(1-Atop) = Abot
         *      Cr = Ctop*Abot + Cbot*(1-Atop)
         * 
*/ SRC_ATOP, /** * The color and alpha components from the top input are * added to those from the bottom input. * The result is clamped to 1.0 if it exceeds the logical * maximum of 1.0. *

* Thus: *

         *      Ar = min(1, Atop+Abot)
         *      Cr = min(1, Ctop+Cbot)
         * 
*

* Notes: *

    *
  • This mode is commutative (ordering of inputs * does not matter). *
  • This mode is sometimes referred to as "linear dodge" in * imaging software packages. *
*/ ADD, /** * The color components from the first input are multiplied with those * from the second input. * The alpha components are blended according to * the {@link #SRC_OVER} equation. *

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      Cr = Ctop * Cbot
         * 
*

* Notes: *

    *
  • This mode is commutative (ordering of inputs * does not matter). *
  • This mode is the mathematical opposite of * the {@link #SCREEN} mode. *
  • The resulting color is always at least as dark as either * of the input colors. *
  • Rendering with a completely black top input produces black; * rendering with a completely white top input produces a result * equivalent to the bottom input. *
*/ MULTIPLY, /** * The color components from both of the inputs are * inverted, multiplied with each other, and that result * is again inverted to produce the resulting color. * The alpha components are blended according * to the {@link #SRC_OVER} equation. *

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      Cr = 1 - ((1-Ctop) * (1-Cbot))
         * 
*

* Notes: *

    *
  • This mode is commutative (ordering of inputs * does not matter). *
  • This mode is the mathematical opposite of * the {@link #MULTIPLY} mode. *
  • The resulting color is always at least as light as either * of the input colors. *
  • Rendering with a completely white top input produces white; * rendering with a completely black top input produces a result * equivalent to the bottom input. *
*/ SCREEN, /** * The input color components are either multiplied or screened, * depending on the bottom input color. * The alpha components are blended according * to the {@link #SRC_OVER} equation. *

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      REMIND: not sure how to express this succinctly yet...
         * 
*

* Notes: *

    *
  • This mode is a combination of {@link #SCREEN} and * {@link #MULTIPLY}, depending on the bottom input color. *
  • This mode is the mathematical opposite of * the {@link #HARD_LIGHT} mode. *
  • In this mode, the top input colors "overlay" the bottom input * while preserving highlights and shadows of the latter. *
*/ OVERLAY, /** * REMIND: cross check this formula with OpenVG spec... * * The darker of the color components from the two inputs are * selected to produce the resulting color. * The alpha components are blended according * to the {@link #SRC_OVER} equation. *

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      Cr = min(Ctop, Cbot)
         * 
*

* Notes: *

    *
  • This mode is commutative (ordering of inputs * does not matter). *
  • This mode is the mathematical opposite of * the {@link #LIGHTEN} mode. *
*/ DARKEN, /** * REMIND: cross check this formula with OpenVG spec... * * The lighter of the color components from the two inputs are * selected to produce the resulting color. * The alpha components are blended according * to the {@link #SRC_OVER} equation. *

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      Cr = max(Ctop, Cbot)
         * 
*

* Notes: *

    *
  • This mode is commutative (ordering of inputs * does not matter). *
  • This mode is the mathematical opposite of * the {@link #DARKEN} mode. *
*/ LIGHTEN, /** * The bottom input color components are divided by the inverse * of the top input color components to produce the resulting color. * The alpha components are blended according * to the {@link #SRC_OVER} equation. *

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      Cr = Cbot / (1-Ctop)
         * 
*/ COLOR_DODGE, /** * The inverse of the bottom input color components are divided by * the top input color components, all of which is then inverted * to produce the resulting color. * The alpha components are blended according * to the {@link #SRC_OVER} equation. *

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      Cr = 1-((1-Cbot) / Ctop)
         * 
*/ COLOR_BURN, /** * The input color components are either multiplied or screened, * depending on the top input color. * The alpha components are blended according * to the {@link #SRC_OVER} equation. *

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      REMIND: not sure how to express this succinctly yet...
         * 
*

* Notes: *

    *
  • This mode is a combination of {@link #SCREEN} and * {@link #MULTIPLY}, depending on the top input color. *
  • This mode is the mathematical opposite of * the {@link #OVERLAY} mode. *
*/ HARD_LIGHT, /** * REMIND: this is a complicated formula, TBD... */ SOFT_LIGHT, /** * The darker of the color components from the two inputs are * subtracted from the lighter ones to produce the resulting color. * The alpha components are blended according * to the {@link #SRC_OVER} equation. *

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      Cr = abs(Ctop-Cbot)
         * 
*

* Notes: *

    *
  • This mode is commutative (ordering of inputs * does not matter). *
  • This mode can be used to invert parts of the bottom input * image, or to quickly compare two images (equal pixels will result * in black). *
  • Rendering with a completely white top input inverts the * bottom input; rendering with a completely black top input produces * a result equivalent to the bottom input. *
*/ DIFFERENCE, /** * The color components from the two inputs are multiplied and * doubled, and then subtracted from the sum of the bottom input * color components, to produce the resulting color. * The alpha components are blended according * to the {@link #SRC_OVER} equation. *

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      Cr = Ctop + Cbot - (2*Ctop*Cbot)
         * 
*

* Notes: *

    *
  • This mode is commutative (ordering of inputs * does not matter). *
  • This mode can be used to invert parts of the bottom input. *
  • This mode produces results that are similar to those of * {@link #DIFFERENCE}, except with lower contrast. *
  • Rendering with a completely white top input inverts the * bottom input; rendering with a completely black top input produces * a result equivalent to the bottom input. *
*/ EXCLUSION, /** * The red component of the bottom input is replaced with the * red component of the top input; the other color components * are unaffected. * The alpha components are blended according * to the {@link #SRC_OVER} equation. *

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      Rr = Rtop
         *      Gr = Gbot
         *      Br = Bbot
         * 
*/ RED, /** * The green component of the bottom input is replaced with the * green component of the top input; the other color components * are unaffected. * The alpha components are blended according * to the {@link #SRC_OVER} equation. *

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      Rr = Rbot
         *      Gr = Gtop
         *      Br = Bbot
         * 
*/ GREEN, /** * The blue component of the bottom input is replaced with the * blue component of the top input; the other color components * are unaffected. * The alpha components are blended according * to the {@link #SRC_OVER} equation. *

* Thus: *

         *      Ar = Atop + Abot*(1-Atop)
         *      Rr = Rbot
         *      Gr = Gbot
         *      Br = Btop
         * 
*/ BLUE, } private Mode mode; private float opacity; /** * Constructs a new {@code Blend} effect with the given mode and the * default opacity (1.0). * Either or both inputs may be {@code null} to indicate that the default * input should be used. * * @param mode the blending mode * @param bottomInput the bottom input * @param topInput the top input * @throws IllegalArgumentException if {@code mode} is null */ public Blend(Mode mode, Effect bottomInput, Effect topInput) { super(bottomInput, topInput); setMode(mode); setOpacity(1f); } /** * Returns the bottom input for this {@code Effect}. * * @return the bottom input for this {@code Effect} */ public final Effect getBottomInput() { return getInputs().get(0); } /** * Sets the bottom input for this {@code Effect} to a specific * {@code Effect} or to the default input if {@code input} is * {@code null}. * * @param bottomInput the bottom input for this {@code Effect} */ public void setBottomInput(Effect bottomInput) { setInput(0, bottomInput); } /** * Returns the top input for this {@code Effect}. * * @return the top input for this {@code Effect} */ public final Effect getTopInput() { return getInputs().get(1); } /** * Sets the top input for this {@code Effect} to a specific * {@code Effect} or to the default input if {@code input} is * {@code null}. * * @param topInput the top input for this {@code Effect} */ public void setTopInput(Effect topInput) { setInput(1, topInput); } /** * Returns the {@code Mode} used to blend the two inputs together. * * @return the {@code Mode} used to blend the two inputs together. */ public Mode getMode() { return mode; } /** * Sets the {@code Mode} used to blend the two inputs together. *
     *       Min: n/a
     *       Max: n/a
     *   Default: Mode.SRC_OVER
     *  Identity: n/a
     * 
* * @param mode the blending mode * @throws IllegalArgumentException if {@code mode} is null */ public void setMode(Mode mode) { if (mode == null) { throw new IllegalArgumentException("Mode must be non-null"); } Blend.Mode old = this.mode; this.mode = mode; updatePeerKey("Blend_" + mode.name()); } /** * Returns the opacity value, which is modulated with the top input * prior to blending. * * @return the opacity value */ public float getOpacity() { return opacity; } /** * Sets the opacity value, which is modulated with the top input prior * to blending. *
     *       Min: 0.0
     *       Max: 1.0
     *   Default: 1.0
     *  Identity: 1.0
     * 
* * @param opacity the opacity value * @throws IllegalArgumentException if {@code opacity} is outside the * allowable range */ public void setOpacity(float opacity) { if (opacity < 0f || opacity > 1f) { throw new IllegalArgumentException("Opacity must be in the range [0,1]"); } float old = this.opacity; this.opacity = opacity; } /** * Transform the specified point {@code p} from the coordinate space * of the primary content input to the coordinate space of the effect * output. * In essence, this method asks the question "Which output coordinate * is most affected by the data at the specified coordinate in the * primary source input?" *

* The {@code Blend} effect delegates this operation to its {@code top} * input, or the {@code defaultInput} if the {@code top} input is * {@code null}. * * @param p the point in the coordinate space of the primary content * input to be transformed * @param defaultInput the default input {@code Effect} to be used in * all cases where a filter has a null input * @return the transformed point in the coordinate space of the result */ @Override public Point2D transform(Point2D p, Effect defaultInput) { return getDefaultedInput(1, defaultInput).transform(p, defaultInput); } /** * Transform the specified point {@code p} from the coordinate space * of the output of the effect into the coordinate space of the * primary content input. * In essence, this method asks the question "Which source coordinate * contributes most to the definition of the output at the specified * coordinate?" *

* The {@code Blend} effect delegates this operation to its {@code top} * input, or the {@code defaultInput} if the {@code top} input is * {@code null}. * * @param p the point in the coordinate space of the result output * to be transformed * @param defaultInput the default input {@code Effect} to be used in * all cases where a filter has a null input * @return the untransformed point in the coordinate space of the * primary content input */ @Override public Point2D untransform(Point2D p, Effect defaultInput) { return getDefaultedInput(1, defaultInput).untransform(p, defaultInput); } @Override public RenderState getRenderState(FilterContext fctx, BaseTransform transform, Rectangle outputClip, Object renderHelper, Effect defaultInput) { // A blend operation operates on its inputs pixel-by-pixel // with no expansion or contraction. // RT-27563 // TODO: The RenderSpaceRenderState object uses the output clip unchanged // for its inputs, but we could further restrict the amount we ask for // each input to the intersection of the two input bounds, but for now we // will simply let it pass along the output clip as the input clip. return RenderState.RenderSpaceRenderState; } @Override public boolean reducesOpaquePixels() { final Effect bottomInput = getBottomInput(); final Effect topInput = getTopInput(); switch (getMode()) { case SRC_IN: case SRC_OUT: return true; case SRC_ATOP: return bottomInput != null && bottomInput.reducesOpaquePixels(); case SRC_OVER: case ADD: case MULTIPLY: case SCREEN: case OVERLAY: case DARKEN: case LIGHTEN: case COLOR_DODGE: case COLOR_BURN: case HARD_LIGHT: case SOFT_LIGHT: case DIFFERENCE: case EXCLUSION: case RED: case GREEN: case BLUE: return topInput != null && topInput.reducesOpaquePixels() && bottomInput != null && bottomInput.reducesOpaquePixels(); } return true; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy