Javafx 无需使用awt即可保存图像
JavaFX中有一个老错误,它阻止您使用Javafx 无需使用awt即可保存图像,javafx,Javafx,JavaFX中有一个老错误,它阻止您使用 ImageIO.write(SwingFXUtils.fromFXImage( wi, null), "jpg", new File( fileName1)); 当您从节点获取快照并尝试将其保存为jpg文件时,就会出现此问题。当您将jpg加载到和图像并保存该图像时,不会发生这种情况 已经有一段时间了,它还没有修好。在不使用awt的情况下,是否有适当的解决方法 我知道SwingFXUtils在内部使用awt,但在您自己的项目中使用它感觉是错误的 我检查了
ImageIO.write(SwingFXUtils.fromFXImage( wi, null), "jpg", new File( fileName1));
当您从节点获取快照并尝试将其保存为jpg文件时,就会出现此问题。当您将jpg加载到和图像并保存该图像时,不会发生这种情况
已经有一段时间了,它还没有修好。在不使用awt的情况下,是否有适当的解决方法
我知道SwingFXUtils在内部使用awt,但在您自己的项目中使用它感觉是错误的
我检查了错误报告。他们的关系密切
和
然而,这是一个问题,它不是固定的
以下是完整的示例代码,请更改fileName1和fileName2变量以匹配您的路径:
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
public class ImageSave extends Application {
String fileName1 = "c:/temp/1.jpg"; // TODO: change filepath
String fileName2 = "c:/temp/2.jpg"; // TODO: change filepath
ImageView imageView;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Image Crop");
BorderPane root = new BorderPane();
Button button = new Button( "Save");
button.setOnAction(e -> save());
root.setTop(button);
// container for image layers
ScrollPane scrollPane = new ScrollPane();
// image layer: a group of images
Group imageLayer = new Group();
// load the image
// Image image = new Image( getClass().getResource( "cat.jpg").toExternalForm());
Image image = new Image("https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Gatto_europeo4.jpg/1024px-Gatto_europeo4.jpg");
// the container for the image as a javafx node
imageView = new ImageView( image);
// add image to layer
imageLayer.getChildren().add( imageView);
// use scrollpane for image view in case the image is large
scrollPane.setContent(imageLayer);
// put scrollpane in scene
root.setCenter(scrollPane);
primaryStage.setScene(new Scene(root, 1024, 768));
primaryStage.show();
}
private void save() {
SnapshotParameters parameters = new SnapshotParameters();
// parameters.setFill(Color.TRANSPARENT);
WritableImage wi = new WritableImage( (int) imageView.getBoundsInLocal().getWidth(), (int) imageView.getBoundsInLocal().getHeight());
imageView.snapshot(parameters, wi);
// save image
// !!! has bug because of transparency (use approach below) !!!
// --------------------------------
try {
ImageIO.write(SwingFXUtils.fromFXImage( wi, null), "jpg", new File( fileName1));
System.out.println( "Image saved to " + fileName1);
} catch (IOException e) {
e.printStackTrace();
}
// save image (without alpha)
// --------------------------------
BufferedImage bufImageARGB = SwingFXUtils.fromFXImage(wi, null);
BufferedImage bufImageRGB = new BufferedImage(bufImageARGB.getWidth(), bufImageARGB.getHeight(), BufferedImage.OPAQUE);
Graphics2D graphics = bufImageRGB.createGraphics();
graphics.drawImage(bufImageARGB, 0, 0, null);
try {
ImageIO.write(bufImageRGB, "jpg", new File( fileName2));
System.out.println( "Image saved to " + fileName2);
} catch (IOException e) {
e.printStackTrace();
}
graphics.dispose();
}
}
JavaFX版本:
awt版本:
我做了更多的研究,并举例说明了某些方法的错误处理:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.IntBuffer;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.SplitPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelReader;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.image.WritablePixelFormat;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
public class WritableImageDemo extends Application {
private Image src;
private int width;
private int height;
ImageView srcView;
ImageView srcView2;
ImageView srcView3;
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Image");
src = new Image("http://www.gnu.org/graphics/gnu-head.jpg");
width = (int) src.getWidth();
height = (int) src.getHeight();
srcView = new ImageView(src);
srcView2 = new ImageView();
srcView3 = new ImageView();
ScrollPane scrollPane = new ScrollPane();
ScrollPane scrollPane2 = new ScrollPane();
ScrollPane scrollPane3 = new ScrollPane();
scrollPane.setContent(srcView);
scrollPane2.setContent(srcView2);
scrollPane3.setContent(srcView3);
SplitPane root = new SplitPane(scrollPane, scrollPane2, scrollPane3);
primaryStage.setScene(new Scene(root, 800, 600));
primaryStage.show();
srcView2.setImage(writeToFile());
}
private WritableImage writeToFile() {
WritableImage insert = new WritableImage(width, height);
WritableImage newimage = new WritableImage(width, height);
SnapshotParameters parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
// make a snapshot
srcView.snapshot(parameters, insert);
PixelReader reader = insert.getPixelReader();
PixelWriter writer = newimage.getPixelWriter();
WritablePixelFormat<IntBuffer> format = WritablePixelFormat.getIntArgbInstance();
System.out.println("WritablePixelFormat.getType(): " + format.getType());
// the following normally creates an exact copy of the original
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int recWidth = 1;
int recHeight = 1;
int[] buffer = new int[recWidth * recHeight];
reader.getPixels(x, y, recWidth, recHeight, format, buffer, 0, recWidth);
int alpha = 0;
int red = 0;
int green = 0;
int blue = 0;
for (int color : buffer) {
alpha += (color >>> 24);
red += (color >>> 16 & 0xFF);
green += (color >>> 8 & 0xFF);
blue += (color & 0xFF);
}
alpha = alpha / recWidth / recHeight;
red = red / recWidth / recHeight;
green = green / recWidth / recHeight;
blue = blue / recWidth / recHeight;
int color = (alpha << 24) + (red << 16) + (green << 8) + blue;
Arrays.fill(buffer, color);
writer.setPixels(x, y, recWidth, recHeight, format, buffer, 0, recWidth);
}
}
System.out.println("Reader Type: " + reader.getPixelFormat().getType());
System.out.println("Writer Type: " + writer.getPixelFormat().getType());
try {
BufferedImage bf = SwingFXUtils.fromFXImage(newimage, null);
ImageIO.write(bf, "jpg", new File("C:\\temp\\test1.jpg"));
} catch (IOException ex) {
Logger.getLogger(WritableImageDemo.class.getName()).
log(Level.SEVERE, null, ex);
}
try {
Image img = new Image(new FileInputStream(new File("C:\\temp\\test1.jpg")));
srcView3.setImage(img);
} catch (IOException ex) {
Logger.getLogger(WritableImageDemo.class.getName()).log(Level.SEVERE, null, ex);
}
return newimage;
}
public static void main(String[] args) {
launch(args);
}
}
您不能依赖实际使用传入映像的快照。信息技术
如果可以的话,将使用,但是为了正确,您需要使用返回值
对方法的改进。例如:
insert = srcView.snapshot(parameters, insert);
他们已经为版本9安排了错误修复。然后是png,在文本编辑器中检查文件的第一个字符。我需要一个jpg。正如你已经说过的,jpeg不能处理透明度。是的,但是ImageIO.write似乎不知道:-)我刚刚读了错误报告。嗯,这是2012年报道的,也许你会再次尝试报道。JavaFX现在是JRE/JDK的一部分,因此将其设置为“无问题”的参数已经不存在了。我已经报告了这个错误,review id:JI-9021748可能我遗漏了一些东西,但这在Java8U60 ea、OSX10.9.5上对我来说是正确的。类似这样的问题在Java8U20中也得到了解决(请参阅:)。注意:在测试时,我注释掉了快照代码,使
image
变量成为ImageSave
类的成员,并使用fromFXImage(image,null)
而不是fromFXImage(wi,null)
。不确定这些修改是否影响了您的测试或您试图演示的内容。如果您仍然认为这是一个问题,那么问题总是存在的:snapshot方法就是问题所在,因为它将PixelWriter.Type设置为INT_ARGB_PRE,因此在这之后,您的图像中(甚至在图像中)会有一个alpha。而SwingFXUtils.fromFXImage()将完成其余的工作,即使您尝试使用RGB类型向方法添加BuffereImage。该方法不应在jpeg文件上设置alpha!他想给快照增加透明度。@jewelsea:我刚才试过了,你说得对。NwDx也是如此。快照方法就是问题所在。当我加载图像并保存它时,一切正常。当我快照图像并保存它时,问题就出现了。@NwDX:我不想添加透明度。我希望快照和保存到jpg正常工作。@Roland感谢您解决此问题。
insert = srcView.snapshot(parameters, insert);