Create an image-overlay mask in javafx

一个人想着一个人 提交于 2019-12-01 00:52:28

What you are Doing Wrong

The difference operator isn't a binary difference based on whether a pixel is set instead it is a difference in the RGB components, so instead of a solid red overlay, you will get a multi-colored overlay because the difference in the RGB components of the blended images differs between pixels.

Background

You are trying to do something similar to a masked bit-blit operation with blend modes (basically, an OR then an AND of pixel data based on a white on black mask). It is possible though a little tricky with the built-in blends in JavaFX 8.

You could create a feature request for additional support in the blend API for bit-blt style basics as well as exposing a full porter duff compositing implementation like Swing has so that the underlying blend engine has a bit more power and is possibly a little easier to use.

Alternatives

The preferred thing to do would be to pre-process your mask in an image editor like photoshop to convert the black part to an alpha channel - then you can just layer your mask on top of your original and the default compositing mode will take of it.

To make your alpha enabled mask red, you could just use mask.setBlendMode(BlendMode.RED) (or you could pre-color the mask in an image editor before using it in your program).

Another alternative is the PixelReader solution you have in your question (which I think is fine if you are unable to pre-convert your mask to use alpha).

The blend operations can be hardware accelerated on appropriate hardware. So potentially using a blend could be faster if you are doing it very often (but you would have to have many blends being run very quickly on large images to really notice any kind of performance difference).

Sample Solution Using Blend Operations

Sample Output

Input Images

original.jpg

stencil.jpg

Code

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.effect.BlendMode;
import javafx.scene.image.*;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class Blended extends Application {
    @Override
    public void start(Stage stage) {
        Image original = new Image(
            getClass().getResourceAsStream("original.jpg")
        );

        Image stencil = new Image(
            getClass().getResourceAsStream("stencil.jpg")
        );

        // first invert the stencil so that it is black on white rather than white on black.
        Rectangle whiteRect = new Rectangle(stencil.getWidth(), stencil.getHeight());
        whiteRect.setFill(Color.WHITE);
        whiteRect.setBlendMode(BlendMode.DIFFERENCE);

        Group inverted = new Group(
                new ImageView(stencil),
                whiteRect
        );

        // overlay the black portions of the inverted mask onto the image.
        inverted.setBlendMode(BlendMode.MULTIPLY);
        Group overlaidBlack = new Group(
                new ImageView(original),
                inverted
        );

        // create a new mask with a red tint (red on black).
        Rectangle redRect = new Rectangle(stencil.getWidth(), stencil.getHeight());
        redRect.setFill(Color.RED);
        redRect.setBlendMode(BlendMode.MULTIPLY);

        Group redStencil = new Group(
                new ImageView(stencil),
                redRect
        );

        // overlay the red mask on to the image.
        redStencil.setBlendMode(BlendMode.ADD);
        Group overlaidRed = new Group(
                overlaidBlack,
                redStencil
        );

        // display the original, composite image and stencil.
        HBox layout = new HBox(10);
        layout.getChildren().addAll(
                new ImageView(original),
                overlaidRed,
                new ImageView(stencil)
        );
        layout.setPadding(new Insets(10));
        stage.setScene(new Scene(layout));
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!