- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
情况
我有一个带有圆形的图像,该图像填充了从白色到黑色/透明度的径向渐变。它用作粒子,需要在其生命周期内着色。
问题
我正在使用 ColorAdjust 将不同的颜色应用于图像。问题是颜色不是我想要的样子。如果我使用绿色作为目标颜色,我会得到一个粉红色的球。
问题
如何计算 ColorAdjust 的色调值以匹配给定的目标颜色?或者有没有更好的方法来为图像着色?我不能使用形状本身,因为使用 ImageView 比使用形状快得多。
代码
这是代码。问题很可能是色调只是与当前颜色的差异:
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
HBox root = new HBox();
// create alpha masked image
Image image = createImage(createAlphaMaskedBall(200));
// create original imageview
ImageView original = new ImageView( image);
// create imageview with color adjustment
ImageView modified = new ImageView( image);
// colorAdjust effect
ColorAdjust colorAdjust = new ColorAdjust();
// set saturation to 1, otherwise hue won't have an effect
colorAdjust.setSaturation(1);
// define target color
Color targetColor = Color.GREEN;
// calculate hue: map from [0,360] to [-1,1]; TODO: here's the problem
double hue = map( targetColor.getHue(), 0, 360, -1, 1);
colorAdjust.setHue(hue);
// apply color adjustment
modified.setEffect(colorAdjust);
root.getChildren().addAll( original, modified);
Scene scene = new Scene(root,1024,500, Color.BLACK);
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* Snapshot an image out of a node, consider transparency.
* @param node
* @return
*/
public static Image createImage( Node node) {
WritableImage wi;
SnapshotParameters parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
int imageWidth = (int) node.getBoundsInLocal().getWidth();
int imageHeight = (int) node.getBoundsInLocal().getHeight();
wi = new WritableImage( imageWidth, imageHeight);
node.snapshot(parameters, wi);
return wi;
}
/**
* Create an alpha masked ball with gradient colors from White to Black/Transparent. Used e. g. for particles.
*
* @param radius
* @return
*/
public static Node createAlphaMaskedBall( double radius) {
Circle ball = new Circle(radius);
RadialGradient gradient1 = new RadialGradient(0,
.1,
0,
0,
radius,
false,
CycleMethod.NO_CYCLE,
new Stop(0, Color.WHITE.deriveColor(1,1,1,1)),
new Stop(1, Color.BLACK.deriveColor(1,1,1,0)));
ball.setFill(gradient1);
return ball;
}
public static double map(double value, double start, double stop, double targetStart, double targetStop) {
return targetStart + (targetStop - targetStart) * ((value - start) / (stop - start));
}
public static void main(String[] args) {
launch(args);
}
}
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.Slider;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Callback;
/**
* Modify ColorAdjust so that a given target color is matched.
*/
public class Main extends Application {
Color[] presetColors = new Color[] {Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, Color.MAGENTA, Color.CYAN, Color.DODGERBLUE, Color.LIGHTGREY, Color.DARKGRAY, Color.BLACK, Color.WHITE, Color.BROWN};
Color targetColor;
Rectangle referenceColorRectangle; // display target color as reference (rgb)
ColorAdjust colorAdjust;
Slider redSlider;
Slider greenSlider;
Slider blueSlider;
ComboBox<Color> colorComboBox;
@Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
// content
// -------------------------
HBox content = new HBox();
content.setStyle("-fx-background-color:black");
// create alpha masked image
Image image = createImage(createAlphaMaskedBall(100));
// create original imageview
ImageView original = new ImageView( image);
// create imageview with color adjustment
ImageView modified = new ImageView( image);
// colorAdjust effect
colorAdjust = new ColorAdjust();
modified.setEffect(colorAdjust);
content.getChildren().addAll( original, modified);
// toolbar
// -------------------------
GridPane toolbar = new GridPane();
// presets: show colors as rectangles in the combobox list, as hex color in the combobox selection
colorComboBox = new ComboBox<>();
colorComboBox.getItems().addAll( presetColors);
colorComboBox.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
updateSliders();
}
});
colorComboBox.setCellFactory(new Callback<ListView<Color>, ListCell<Color>>() {
@Override
public ListCell<Color> call(ListView<Color> p) {
return new ListCell<Color>() {
private final Rectangle rectangle;
{
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
rectangle = new Rectangle(100, 10);
}
@Override
protected void updateItem(Color item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
} else {
rectangle.setFill(item);
setGraphic(rectangle);
}
}
};
}
});
// sliders, value is initialized later
redSlider = createSlider( 0,255, 0);
greenSlider = createSlider( 0,255, 0);
blueSlider = createSlider( 0,255, 0);
// reference rectangle in rgb
referenceColorRectangle = new Rectangle( 0, 0, 100, 100);
referenceColorRectangle.setStroke(Color.BLACK);
// listener: get new target color from sliders and apply it
ChangeListener<Number> listener = new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
updateColor();
}
};
redSlider.valueProperty().addListener(listener);
greenSlider.valueProperty().addListener(listener);
blueSlider.valueProperty().addListener(listener);
// add nodes to gridpane
toolbar.addRow(0, new Label( "Preset"), colorComboBox);
toolbar.addRow(1, new Label( "Red"), redSlider);
toolbar.addRow(2, new Label( "Green"), greenSlider);
toolbar.addRow(3, new Label( "Blue"), blueSlider);
toolbar.add(referenceColorRectangle, 2, 0, 1, 4);
// margin for all gridpane nodes
for( Node node: toolbar.getChildren()) {
GridPane.setMargin(node, new Insets(5,5,5,5));
}
// layout
root.setTop(toolbar);
root.setCenter(content);
// create scene
Scene scene = new Scene(root,800,400, Color.BLACK);
primaryStage.setScene(scene);
primaryStage.show();
// set height of combobox list
colorComboBox.lookup(".list-view").setStyle("-fx-pref-height: 200");
// select 1st color and implicitly initialize the sliders and colors
colorComboBox.getSelectionModel().selectFirst();
}
private void updateColor() {
// create target color
targetColor = Color.rgb( (int) redSlider.getValue(), (int) greenSlider.getValue(), (int) blueSlider.getValue());
// update reference
referenceColorRectangle.setFill(targetColor);
// update colorAdjust
// see http://stackoverflow.com/questions/31587092/how-to-use-coloradjust-to-set-a-target-color
double hue = map( (targetColor.getHue() + 180) % 360, 0, 360, -1, 1);
colorAdjust.setHue(hue);
// use saturation as it is
double saturation = targetColor.getSaturation();
colorAdjust.setSaturation(saturation);
// we use WHITE in the masked ball creation => inverse brightness
double brightness = map( targetColor.getBrightness(), 0, 1, -1, 0);
colorAdjust.setBrightness(brightness);
// System.out.println("Target color: " + targetColor + ", hue 0..360: " + targetColor.getHue() + ", hue 0..1: " + hue);
}
private void updateSliders() {
Color referenceColor = colorComboBox.getValue();
redSlider.setValue( map( referenceColor.getRed(), 0, 1, 0, 255));
greenSlider.setValue( map( referenceColor.getGreen(), 0, 1, 0, 255));
blueSlider.setValue( map( referenceColor.getBlue(), 0, 1, 0, 255));
}
private Slider createSlider( double min, double max, double value) {
Slider slider = new Slider( min, max, value);
slider.setPrefWidth(600);
slider.setShowTickLabels(true);
slider.setShowTickMarks(true);
return slider;
}
/**
* Snapshot an image out of a node, consider transparency.
* @param node
* @return
*/
public static Image createImage( Node node) {
WritableImage wi;
SnapshotParameters parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
int imageWidth = (int) node.getBoundsInLocal().getWidth();
int imageHeight = (int) node.getBoundsInLocal().getHeight();
wi = new WritableImage( imageWidth, imageHeight);
node.snapshot(parameters, wi);
return wi;
}
/**
* Create an alpha masked ball with gradient colors from White to Black/Transparent. Used e. g. for particles.
*
* @param radius
* @return
*/
public static Node createAlphaMaskedBall( double radius) {
Circle ball = new Circle(radius);
RadialGradient gradient1 = new RadialGradient(0,
0,
0,
0,
radius,
false,
CycleMethod.NO_CYCLE,
new Stop(0, Color.WHITE.deriveColor(1,1,1,1)),
new Stop(1, Color.WHITE.deriveColor(1,1,1,0)));
ball.setFill(gradient1);
return ball;
}
public static double map(double value, double start, double stop, double targetStart, double targetStop) {
return targetStart + (targetStop - targetStart) * ((value - start) / (stop - start));
}
public static void main(String[] args) {
launch(args);
}
}
double hue = map( (targetColor.getHue() + 180) % 360, 0, 360, -1, 1);
colorAdjust.setHue(hue);
// use saturation as it is
double saturation = targetColor.getSaturation();
colorAdjust.setSaturation(saturation);
// we use WHITE in the masked ball creation => inverse brightness
double brightness = map( targetColor.getBrightness(), 0, 1, -1, 0);
colorAdjust.setBrightness(brightness);
最佳答案
如果您查看圆圈中心的颜色(纯白色,100% 不透明度),作为应用 ColorAdust
的结果效果,你有洋红色 #ff00ffff
.
您正在应用的颜色的色调值为 120 ( Color.GREEN.getHue()
),如果您创建此颜色:
Color color = Color.hsb(120,1,1);
System.out.println(color);
#00ff00ff
,它是绿色(100% 不透明度),在 R、G、B 方面正好是相反的颜色。
targetColor = Color.web("#ff00ffff");
double hue = map( targetColor.getHue()+180, 0, 360, -1, 1);
关于javafx - 如何使用 ColorAdjust 设置目标颜色?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31587092/
情况 我有一个带有圆形的图像,该图像填充了从白色到黑色/透明度的径向渐变。它用作粒子,需要在其生命周期内着色。 问题 我正在使用 ColorAdjust 将不同的颜色应用于图像。问题是颜色不是我想要的
我真的希望有人能够提供帮助...我已经两次、三次和四次检查 Pixastic 库是否正在加载。 这是我的 HTML 代码: 在 标签: 在 标签: 这是 jQuery。我省略了计算 RGB
应用颜色调整效果并重新绘制 Canvas 后, Canvas 没有被清除,以便我可以用其他图像更新 Canvas ,图像重叠。 我有一个包含滚动 Pane 的边框 Pane 来调整大图像滚动 Pane
我只是制作了一个类,让我可以使用 ColorAjust 类修改图像,例如饱和度、亮度、对比度和色调。 但我不知道如何在进行这些修改后保存该图像。 代码如下: final Stage imageProc
我正在尝试将彩色图像转换为可用的单色图像,但没有“锯齿状”边缘。 来自类似的问题asking to convert an image from color to black and white ,其中
我是一名优秀的程序员,十分优秀!