kayler-renslow / arma-dialog-creator

A dialog/GUI creation tool for Arma 3.
MIT License
76 stars 12 forks source link

Images with transparency don't blend correctly with text color #1

Closed kayler-renslow closed 7 years ago

kayler-renslow commented 7 years ago

An image with some transparency and a non white text color for the control blends correctly on the image, but it applies the blend over the transparency as well.

Current effect (ignore jpeg compression): http://i.imgur.com/4Zd8wa0.jpg

Desired effect (ignore jpeg compression): http://i.imgur.com/XwEC6Oi.jpg

kayler-renslow commented 7 years ago

Although this doesn't fix the problem, this seems to be a better implementation than the current one.

int x = /*x position of image*/;
int y = /*y position of image*/;
int w = /*width of image (can be smaller or larger than actual image width)*/;
int h = /*height of image (can be smaller or larger than actual image height)*/;
Image img = /*JavaFX Image object*/;
Color multColor = /*JavaFX Color used to tint the image*/;

PerspectiveTransform imgTrans = new PerspectiveTransform(x, y, x+w, y, x+w, y+h, x, y+h);
imgTrans.setInput(new ImageInput(img));
gc.setEffect(new Blend(
    BlendMode.MULTIPLY,
    imgTrans,
    new ColorInput(x, y, w, h, multColor)
    )
);
gc.setFill(Color.TRANSPARENT);
gc.fillRect(x, y, w, h);
gc.setEffect(null); //clear the effect so any succeeding renders don't use it

How it works:

  1. Scales the image to the needed width and height, as well as positions it (the fillRect() doesn't position the effect output).
  2. Creates a Blend with Multiply blend mode with the bottom input being the color to tint image and the top input being the transformed image.
  3. The fillRect() call then just makes sure the effect is painted.
kayler-renslow commented 7 years ago

Actual solution to this issue:

int x = /*x position of image*/;
int y = /*y position of image*/;
int w = /*width of image (can be smaller or larger than actual image width)*/;
int h = /*height of image (can be smaller or larger than actual image height)*/;
Image img = /*JavaFX Image object*/;
Color multColor = /*JavaFX Color used to tint the image*/;

PerspectiveTransform imgTrans = new PerspectiveTransform(x, y, x+w, y, x+w, y+h, x, y+h);
imgTrans.setInput(new ImageInput(img));
gc.setEffect(
    new Blend(
        BlendMode.MULTIPLY,
        imgTrans,
        new Blend(
            BlendMode.SRC_ATOP,
            imgTrans,
            new ColorInput(x, y, w, h, multColor)
        ) 
    )
);
gc.setFill(Color.TRANSPARENT);
gc.fillRect(x, y, w, h);
gc.setEffect(null); //clear the effect so any succeeding renders don't use it

How it works:

  1. Scales the image to the needed width and height, as well as positions it (the fillRect() doesn't position the effect output).
  2. Creates a Blend with Multiply blend mode with the bottom input being the transformed image and the top input being a new Blend (let's call this top_blend for reference).
    • The ouput of top_blend will be a "cut out" of color. This is like using the image as a "cookie cutter" on a color rectangle and then returning that cut out color.
  3. The cut out color returned from top_blend will then be used to tint the image.
  4. The fillRect() call then just makes sure the effect is painted.
kayler-renslow commented 7 years ago

Applied the fix to controls in commit https://github.com/kayler-renslow/arma-dialog-creator/commit/becbb1bd15ae230be126b6c8a89b96271589dd71