【问题标题】:CollorAdjust with SwingX's ImageView?CollorAdjust 与 SwingX 的 ImageView?
【发布时间】:2015-02-27 00:08:30
【问题描述】:

我有一个关于调整从 swingx 库加载到 jXImageView 的图像的对比度、饱和度和色调的问题。

我有 ColorAdjust 方法。

ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setContrast(0.3);
colorAdjust.setHue(-0.03);
colorAdjust.setBrightness(0.2);
colorAdjust.setSaturation(0.2);

当用户单击“增强”按钮时,图像应该会发生一些变化,但如何做到这一点?记住:我使用的是 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);

...但没有成功。

【问题讨论】:

  • 虽然您可以将BufferedImageImage 相互转换,但我不知道ImageView 是否会将ColorAdjust 值直接应用于底层Image只是使用它们来改变它的绘制方式。您可以先查看SwingFXUtils,了解如何在两种图像格式之间进行转换
  • 啊,试试this
  • " 你是用java.awt.Image还是javafx.scene.image.Image
  • 现在我已经尝试使用javafx.scene.image.Image
  • 点击按钮时显示错误:Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Not on FX application thread; currentThread = AWT-EventQueue-0 似乎在这一行:imagem = SwingFXUtils.fromFXImage(imageView.snapshot(null, null), null);

标签: java image-processing netbeans javafx swingx


【解决方案1】:

示例解决方案

  • 左图为原图。
  • 右侧的图像是调整后的图像(已对颜色进行去饱和以使图像成为单色)。

此解决方案的工作原理:

  1. 将 Swing/AWT BufferedImage 转换为 JavaFX Image
  2. 使用 JavaFX ColorAdjust 效果修改图像。
  3. 采用经过颜色调整的图像的snapshot 来创建新的JavaFX 图像。
  4. 新的 JavaFX 映像是 converted 回到新的 Swing/AWT BufferedImage。

由于该解决方案混合了两个不同的工具包,因此在创建它时考虑了以下注意事项:

  1. 注意用于确保给定工具包调用使用正确类的导入;例如,JavaFX 和 Swing/AWT 都有 ColorImage 类,因此有必要确保在正确的上下文中使用给定工具包的完全限定类 - 将 Swing 图像直接传递给 JavaFX API 会是错误的,反之亦然。

  2. 注意线程规则。 JavaFX 场景的快照必须在 JavaFX 应用程序线程上制作。 Swing API 的执行必须在 Swing 事件调度线程上进行。各个工具包的各种实用程序(例如,SwingUtilities 和 JavaFX Platform 类)用于确保满足给定工具包的线程约束。

  3. JavaFX 工具包必须先初始化才能使用。通常,这是在您的应用程序扩展 JavaFX Application 类时隐式完成的。但是 Swing 应用程序不扩展 JavaFX 应用程序类。因此,在使用工具包之前,必须实例化 JFXPanel 以初始化 JavaFX 工具包,这可能有点违反直觉且记录不充分。

备注

  1. 此解决方案旨在满足问题的特定要求(这是一个 Swing 应用程序,需要进行一些颜色调整)。如果您只想在 JavaFX 中调整图像颜色而不使用 Swing,那么 more straight-forward solutions 存在并且是首选。

  2. 调用 System.exit 通常足以关闭 JavaFX 工具包。示例应用程序调用Platform.exit 来显式关闭JavaFX 工具包,但在这种情况下,可能不需要显式调用Platform.exit

这意味着解决方案中的 ColorAdjuster 可以在 Swing 程序中使用,而无需 Swing 程序显式导入任何 JavaFX 类(尽管在内部,ColorAdjuster 将导入这些类并且系统必须满足正常的最低要求才能运行这两个类) Swing 和 JavaFX 工具包)。尽可能减少每个类的单个工具包的导入混合是可取的,因为在一个混合 JavaFX/Swing 应用程序的单个类中混合导入是一个很好的乏味错误来源,因为潜在的名称冲突和线程相关的问题。

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";
}

【讨论】:

  • 现在,我真正感兴趣的是,当我尝试使用 Platform.runLater 时,它是如何克服“工具包未启动”异常的?
【解决方案2】:

您需要将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 框架,就像他们在电影中所说的那样,“不要越界!”

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();
        }
    }

}

接下来的事情是尝试弄清楚如何让它作为一个实用程序类工作......

【讨论】:

  • 首先,我非常感谢您!但是我的代码不起作用,我已经编辑了我的帖子以显示我尝试过的内容。
猜你喜欢
  • 1970-01-01
  • 2012-06-23
  • 2013-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多