ColorAdjust 与 SwingX 的 ImageView?
CollorAdjust with SwingX's ImageView?
我有一个关于调整从 swingx 库加载到 jXImageView 的图像的对比度、饱和度和色调的问题。
我有 ColorAdjust 方法。
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setContrast(0.3);
colorAdjust.setHue(-0.03);
colorAdjust.setBrightness(0.2);
colorAdjust.setSaturation(0.2);
当用户点击 "Enhancement" 按钮时,图像应该会发生一点变化,但如何做到这一点呢?记住:我使用的是 jXImageView。
我已经使用以下代码增加了对比度:
float brightenFactor = 1.5f;
BufferedImage imagem = (BufferedImage) jXImageView2.getImage();
RescaleOp op = new RescaleOp(brightenFactor, 0, null);
imagem = op.filter(imagem, imagem);
jXImageView2.updateUI();
编辑
我试过:
BufferedImage imagem = (BufferedImage) jXImageView2.getImage();
Image image = SwingFXUtils.toFXImage(imagem, null);//<--ERROR on that line (incompatible types: writable image cannot be converted to Image)
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setContrast(0.3);
colorAdjust.setHue(-0.03);
colorAdjust.setBrightness(0.2);
colorAdjust.setSaturation(0.2);
ImageView imageView = new ImageView(image);//<--ERROR on taht line no suitable constructor for ImageView(java.awt.Image)
imageView.setFitWidth(imagem.getWidth());
imageView.setPreserveRatio(true);
imagem = SwingFXUtils.fromFXImage(imageView.snapshot(null, null), null);
jXImageView2.setImage(imagem);
...但没有成功。
您需要将 BufferedImage
转换为 javafx.scene.image.Image
,您可以使用诸如...
Image image = SwingFXUtils.toFXImage(imagem, null);
然后你可以申请 ColorAdjust
...
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setContrast(0.1);
colorAdjust.setHue(-0.05);
colorAdjust.setBrightness(0.1);
colorAdjust.setSaturation(0.2);
ImageView imageView = new ImageView(image);
imageView.setFitWidth(image.getWidth());
imageView.setPreserveRatio(true);
imageView.setEffect(colorAdjust);
然后再转换回来...
imagem = SwingFXUtils.fromFXImage(imageView.snapshot(null, null), null);
这个想法是从 jewelsea / SaveAdjustedImage.java 偷来的。我不知道的是,如果 ImageView
需要首先在屏幕上实现,那么...
已更新
请注意,您正在跨越两个不同的 UI 框架,就像他们在电影中所说的那样,"don't cross the streams!"
JavaFX 比 Swing 有更严格的控制要求,这既是好事也是坏事。
您必须做的是在事件线程中将 JavaFX 代码获取到 运行。这比听起来更棘手(而且似乎需要如此),例如...
原创 |颜色调整(取自JavaDocs example)|单色...
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
public class Test extends Application {
public static void main(String[] args) {
Application.launch();
}
@Override
public void start(Stage stage) throws Exception {
try {
System.out.println("Load image...");
BufferedImage imagem = ImageIO.read(new File("..."));
Image image = SwingFXUtils.toFXImage(imagem, null);
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setHue(0);
colorAdjust.setSaturation(-1);
colorAdjust.setBrightness(0);
colorAdjust.setContrast(0);
// colorAdjust.setHue(-0.05);
// colorAdjust.setSaturation(0.2);
// colorAdjust.setBrightness(0.1);
// colorAdjust.setContrast(0.1);
ImageView imageView = new ImageView(image);
imageView.setFitWidth(image.getWidth());
imageView.setPreserveRatio(true);
imageView.setEffect(colorAdjust);
System.out.println("Convert and save...");
imagem = SwingFXUtils.fromFXImage(imageView.snapshot(null, null), null);
ImageIO.write(imagem, "png", new File("ColorAdjusted.png"));
} catch (IOException exp) {
exp.printStackTrace();
} finally {
Platform.exit();
}
}
}
接下来要弄清楚如何让它作为实用程序工作class...
示例解决方案
- 左图为原图。
- 右边的图片是调整后的图片(已降低颜色饱和度,使图片成为单色)。
此解决方案适用于:
- 正在转换 Swing/AWT BufferedImage into a JavaFX Image。
- 使用JavaFX ColorAdjust效果修改图片。
- A snapshot 颜色调整后的图像被用来创建一个新的 JavaFX 图像。
- 新的 JavaFX 图像 converted 回到新的 Swing/AWT BufferedImage。
由于该解决方案混合了两个不同的工具包,因此在创建它时考虑了以下注意事项:
注意用于确保给定工具包调用使用正确 class 的导入;例如,JavaFX 和 Swing/AWT 都有 Color
和 Image
class,因此有必要确保使用给定工具包的完全限定 class在正确的上下文中 - 将 Swing Image 直接传递给 JavaFX API 是错误的,反之亦然。
注意线程规则。 JavaFX 场景的快照必须在 JavaFX 应用程序线程上创建。必须在 Swing 事件调度线程上执行 Swing APIs。各个工具包的各种实用程序(例如 SwingUtilities
and the JavaFX Platform
class)用于确保满足给定工具包的线程约束。
- JavaFX 工具包必须先初始化才能使用。通常这是在您的应用程序扩展 JavaFX 时隐式完成的
Application
class. However Swing applications do not extend the JavaFX application class. So, perhaps somewhat counter-intuitively and poorly documented, a JFXPanel
必须在使用工具包之前实例化以初始化 JavaFX 工具包。
备注
这个解决方案是为满足问题的特定要求而设计的(这是一个需要进行一些颜色调整的 Swing 应用程序)。如果您只想从 JavaFX 中调整图像颜色而不使用 Swing,那么 more straight-forward solutions 存在并且是首选。
调用 System.exit
通常足以关闭 JavaFX 工具包。示例应用程序调用 Platform.exit
以显式关闭 JavaFX 工具包,但在这种情况下,可能不需要显式调用 Platform.exit
。
这意味着解决方案中的 ColorAdjuster 可以从 Swing 程序使用,而无需 Swing 程序显式导入任何 JavaFX classes(尽管在内部,ColorAdjuster 将导入那些 classes并且系统必须满足 运行 Swing 和 JavaFX 工具包的正常最低要求)。在可能的情况下减少每个 class 对单个工具包的混合导入是可取的,因为对于混合的 JavaFX/Swing 应用程序,在单个 class 中混合导入是一个很好的乏味错误来源,由于潜在的名称冲突和线程相关的问题。
ColorAdjuster.java
图像颜色调整实用程序。
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.SnapshotParameters;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javax.swing.SwingUtilities;
import java.awt.image.BufferedImage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/** Uses JavaFX to adjust the color of an AWT/Swing BufferedImage */
public class ColorAdjuster {
// Instantiation of a JFXPanel is necessary otherwise the JavaFX toolkit is not initialized.
// The JFXPanel doesn't actually need to be used, instantiating it in the constructor is enough to trigger toolkit initialization.
private final JFXPanel fxPanel;
public ColorAdjuster() {
// perhaps this check is not necessary, but I feel a bit more comfortable if it is there.
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalArgumentException(
"A ColorAdjuster must be created on the Swing Event Dispatch thread. " +
"Current thread is " + Thread.currentThread()
);
}
fxPanel = new JFXPanel();
}
/**
* Color adjustments to the buffered image are performed with parameters in the range -1.0 to 1.0
*
* @return a new BufferedImage which has colors adjusted from the original image.
**/
public BufferedImage adjustColor(
BufferedImage originalImage,
double hue,
double saturation,
double brightness,
double contrast
) throws ExecutionException, InterruptedException {
// This task will be executed on the JavaFX thread.
FutureTask<BufferedImage> conversionTask = new FutureTask<>(() -> {
// create a JavaFX color adjust effect.
final ColorAdjust monochrome = new ColorAdjust(0, -1, 0, 0);
// convert the input buffered image to a JavaFX image and load it into a JavaFX ImageView.
final ImageView imageView = new ImageView(
SwingFXUtils.toFXImage(
originalImage, null
)
);
// apply the color adjustment.
imageView.setEffect(monochrome);
// snapshot the color adjusted JavaFX image, convert it back to a Swing buffered image and return it.
SnapshotParameters snapshotParameters = new SnapshotParameters();
snapshotParameters.setFill(Color.TRANSPARENT);
return SwingFXUtils.fromFXImage(
imageView.snapshot(
snapshotParameters,
null
),
null
);
});
Platform.runLater(conversionTask);
return conversionTask.get();
}
}
ColorAdjustingSwingAppUsingJavaFX.java
测试工具:
import javafx.application.Platform;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutionException;
public class ColorAdjustingSwingAppUsingJavaFX {
private static void initAndShowGUI() {
try {
// This method is invoked on Swing thread
JFrame frame = new JFrame();
// read the original image from a URL.
URL url = new URL(
IMAGE_LOC
);
BufferedImage originalImage = ImageIO.read(url);
// use JavaFX to convert the original image to monochrome.
ColorAdjuster colorAdjuster = new ColorAdjuster();
BufferedImage monochromeImage = colorAdjuster.adjustColor(
originalImage,
0, -1, 0, 0
);
// add the original image and the converted image to the Swing frame.
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(
new JLabel(
new ImageIcon(originalImage)
)
);
frame.getContentPane().add(
new JLabel(
new ImageIcon(monochromeImage)
)
);
// set a handler to close the application on request.
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
// shutdown the JavaFX runtime.
Platform.exit();
// exit the application.
System.exit(0);
}
});
// display the Swing frame.
frame.pack();
frame.setLocation(400, 300);
frame.setVisible(true);
} catch (IOException | InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(
ColorAdjustingSwingAppUsingJavaFX::initAndShowGUI
);
}
// icon source: http://www.iconarchive.com/artist/aha-soft.html
// icon license: Free for non-commercial use, commercial usage: Not allowed
private static final String IMAGE_LOC =
"http://icons.iconarchive.com/icons/aha-soft/desktop-buffet/128/Pizza-icon.png";
}
我有一个关于调整从 swingx 库加载到 jXImageView 的图像的对比度、饱和度和色调的问题。
我有 ColorAdjust 方法。
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setContrast(0.3);
colorAdjust.setHue(-0.03);
colorAdjust.setBrightness(0.2);
colorAdjust.setSaturation(0.2);
当用户点击 "Enhancement" 按钮时,图像应该会发生一点变化,但如何做到这一点呢?记住:我使用的是 jXImageView。
我已经使用以下代码增加了对比度:
float brightenFactor = 1.5f;
BufferedImage imagem = (BufferedImage) jXImageView2.getImage();
RescaleOp op = new RescaleOp(brightenFactor, 0, null);
imagem = op.filter(imagem, imagem);
jXImageView2.updateUI();
编辑
我试过:
BufferedImage imagem = (BufferedImage) jXImageView2.getImage();
Image image = SwingFXUtils.toFXImage(imagem, null);//<--ERROR on that line (incompatible types: writable image cannot be converted to Image)
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setContrast(0.3);
colorAdjust.setHue(-0.03);
colorAdjust.setBrightness(0.2);
colorAdjust.setSaturation(0.2);
ImageView imageView = new ImageView(image);//<--ERROR on taht line no suitable constructor for ImageView(java.awt.Image)
imageView.setFitWidth(imagem.getWidth());
imageView.setPreserveRatio(true);
imagem = SwingFXUtils.fromFXImage(imageView.snapshot(null, null), null);
jXImageView2.setImage(imagem);
...但没有成功。
您需要将 BufferedImage
转换为 javafx.scene.image.Image
,您可以使用诸如...
Image image = SwingFXUtils.toFXImage(imagem, null);
然后你可以申请 ColorAdjust
...
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setContrast(0.1);
colorAdjust.setHue(-0.05);
colorAdjust.setBrightness(0.1);
colorAdjust.setSaturation(0.2);
ImageView imageView = new ImageView(image);
imageView.setFitWidth(image.getWidth());
imageView.setPreserveRatio(true);
imageView.setEffect(colorAdjust);
然后再转换回来...
imagem = SwingFXUtils.fromFXImage(imageView.snapshot(null, null), null);
这个想法是从 jewelsea / SaveAdjustedImage.java 偷来的。我不知道的是,如果 ImageView
需要首先在屏幕上实现,那么...
已更新
请注意,您正在跨越两个不同的 UI 框架,就像他们在电影中所说的那样,"don't cross the streams!"
JavaFX 比 Swing 有更严格的控制要求,这既是好事也是坏事。
您必须做的是在事件线程中将 JavaFX 代码获取到 运行。这比听起来更棘手(而且似乎需要如此),例如...
原创 |颜色调整(取自JavaDocs example)|单色...
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
public class Test extends Application {
public static void main(String[] args) {
Application.launch();
}
@Override
public void start(Stage stage) throws Exception {
try {
System.out.println("Load image...");
BufferedImage imagem = ImageIO.read(new File("..."));
Image image = SwingFXUtils.toFXImage(imagem, null);
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setHue(0);
colorAdjust.setSaturation(-1);
colorAdjust.setBrightness(0);
colorAdjust.setContrast(0);
// colorAdjust.setHue(-0.05);
// colorAdjust.setSaturation(0.2);
// colorAdjust.setBrightness(0.1);
// colorAdjust.setContrast(0.1);
ImageView imageView = new ImageView(image);
imageView.setFitWidth(image.getWidth());
imageView.setPreserveRatio(true);
imageView.setEffect(colorAdjust);
System.out.println("Convert and save...");
imagem = SwingFXUtils.fromFXImage(imageView.snapshot(null, null), null);
ImageIO.write(imagem, "png", new File("ColorAdjusted.png"));
} catch (IOException exp) {
exp.printStackTrace();
} finally {
Platform.exit();
}
}
}
接下来要弄清楚如何让它作为实用程序工作class...
示例解决方案
- 左图为原图。
- 右边的图片是调整后的图片(已降低颜色饱和度,使图片成为单色)。
此解决方案适用于:
- 正在转换 Swing/AWT BufferedImage into a JavaFX Image。
- 使用JavaFX ColorAdjust效果修改图片。
- A snapshot 颜色调整后的图像被用来创建一个新的 JavaFX 图像。
- 新的 JavaFX 图像 converted 回到新的 Swing/AWT BufferedImage。
由于该解决方案混合了两个不同的工具包,因此在创建它时考虑了以下注意事项:
注意用于确保给定工具包调用使用正确 class 的导入;例如,JavaFX 和 Swing/AWT 都有
Color
和Image
class,因此有必要确保使用给定工具包的完全限定 class在正确的上下文中 - 将 Swing Image 直接传递给 JavaFX API 是错误的,反之亦然。注意线程规则。 JavaFX 场景的快照必须在 JavaFX 应用程序线程上创建。必须在 Swing 事件调度线程上执行 Swing APIs。各个工具包的各种实用程序(例如
SwingUtilities
and the JavaFXPlatform
class)用于确保满足给定工具包的线程约束。- JavaFX 工具包必须先初始化才能使用。通常这是在您的应用程序扩展 JavaFX 时隐式完成的
Application
class. However Swing applications do not extend the JavaFX application class. So, perhaps somewhat counter-intuitively and poorly documented, aJFXPanel
必须在使用工具包之前实例化以初始化 JavaFX 工具包。
备注
这个解决方案是为满足问题的特定要求而设计的(这是一个需要进行一些颜色调整的 Swing 应用程序)。如果您只想从 JavaFX 中调整图像颜色而不使用 Swing,那么 more straight-forward solutions 存在并且是首选。
调用
System.exit
通常足以关闭 JavaFX 工具包。示例应用程序调用Platform.exit
以显式关闭 JavaFX 工具包,但在这种情况下,可能不需要显式调用Platform.exit
。
这意味着解决方案中的 ColorAdjuster 可以从 Swing 程序使用,而无需 Swing 程序显式导入任何 JavaFX classes(尽管在内部,ColorAdjuster 将导入那些 classes并且系统必须满足 运行 Swing 和 JavaFX 工具包的正常最低要求)。在可能的情况下减少每个 class 对单个工具包的混合导入是可取的,因为对于混合的 JavaFX/Swing 应用程序,在单个 class 中混合导入是一个很好的乏味错误来源,由于潜在的名称冲突和线程相关的问题。
ColorAdjuster.java
图像颜色调整实用程序。
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.SnapshotParameters;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javax.swing.SwingUtilities;
import java.awt.image.BufferedImage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/** Uses JavaFX to adjust the color of an AWT/Swing BufferedImage */
public class ColorAdjuster {
// Instantiation of a JFXPanel is necessary otherwise the JavaFX toolkit is not initialized.
// The JFXPanel doesn't actually need to be used, instantiating it in the constructor is enough to trigger toolkit initialization.
private final JFXPanel fxPanel;
public ColorAdjuster() {
// perhaps this check is not necessary, but I feel a bit more comfortable if it is there.
if (!SwingUtilities.isEventDispatchThread()) {
throw new IllegalArgumentException(
"A ColorAdjuster must be created on the Swing Event Dispatch thread. " +
"Current thread is " + Thread.currentThread()
);
}
fxPanel = new JFXPanel();
}
/**
* Color adjustments to the buffered image are performed with parameters in the range -1.0 to 1.0
*
* @return a new BufferedImage which has colors adjusted from the original image.
**/
public BufferedImage adjustColor(
BufferedImage originalImage,
double hue,
double saturation,
double brightness,
double contrast
) throws ExecutionException, InterruptedException {
// This task will be executed on the JavaFX thread.
FutureTask<BufferedImage> conversionTask = new FutureTask<>(() -> {
// create a JavaFX color adjust effect.
final ColorAdjust monochrome = new ColorAdjust(0, -1, 0, 0);
// convert the input buffered image to a JavaFX image and load it into a JavaFX ImageView.
final ImageView imageView = new ImageView(
SwingFXUtils.toFXImage(
originalImage, null
)
);
// apply the color adjustment.
imageView.setEffect(monochrome);
// snapshot the color adjusted JavaFX image, convert it back to a Swing buffered image and return it.
SnapshotParameters snapshotParameters = new SnapshotParameters();
snapshotParameters.setFill(Color.TRANSPARENT);
return SwingFXUtils.fromFXImage(
imageView.snapshot(
snapshotParameters,
null
),
null
);
});
Platform.runLater(conversionTask);
return conversionTask.get();
}
}
ColorAdjustingSwingAppUsingJavaFX.java
测试工具:
import javafx.application.Platform;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutionException;
public class ColorAdjustingSwingAppUsingJavaFX {
private static void initAndShowGUI() {
try {
// This method is invoked on Swing thread
JFrame frame = new JFrame();
// read the original image from a URL.
URL url = new URL(
IMAGE_LOC
);
BufferedImage originalImage = ImageIO.read(url);
// use JavaFX to convert the original image to monochrome.
ColorAdjuster colorAdjuster = new ColorAdjuster();
BufferedImage monochromeImage = colorAdjuster.adjustColor(
originalImage,
0, -1, 0, 0
);
// add the original image and the converted image to the Swing frame.
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(
new JLabel(
new ImageIcon(originalImage)
)
);
frame.getContentPane().add(
new JLabel(
new ImageIcon(monochromeImage)
)
);
// set a handler to close the application on request.
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
// shutdown the JavaFX runtime.
Platform.exit();
// exit the application.
System.exit(0);
}
});
// display the Swing frame.
frame.pack();
frame.setLocation(400, 300);
frame.setVisible(true);
} catch (IOException | InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(
ColorAdjustingSwingAppUsingJavaFX::initAndShowGUI
);
}
// icon source: http://www.iconarchive.com/artist/aha-soft.html
// icon license: Free for non-commercial use, commercial usage: Not allowed
private static final String IMAGE_LOC =
"http://icons.iconarchive.com/icons/aha-soft/desktop-buffet/128/Pizza-icon.png";
}