2015-06-23 2 views
2

Там старая ошибка в JavaFX, который позволяет сохранять изображения надлежащим образом с помощьюСохранить изображение без использования AWT

ImageIO.write(SwingFXUtils.fromFXImage(wi, null), "jpg", new File(fileName1)); 

Проблема возникает, когда вы берете снимок с узла и попытаться сохранить его как JPG файл , Это не происходит, когда вы загружаете jpg и изображение и сохраняете это изображение.

Прошло некоторое время, и оно все еще не исправлено. Есть ли подходящее решение для этого без использования awt?

Я знаю, что SwingFXUtils использует awt внутренне, но наличие его в вашем собственном проекте кажется неправильным.

Я проверил отчеты об ошибках. Они были закрыты с

Not an Issue и Fixed

Однако, это проблема, и она не является фиксированной.

Вот полный пример кода, пожалуйста, измените переменные имя_файла1 и 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:

enter image description here

Версия AWT:

enter image description here

+0

Может быть, я что-то не хватает, но это работает правильно для меня на Java 8u60 еа, OS X 10.9.5. Подобные проблемы также были исправлены для меня в Java 8u20 (см. Http://stackoverflow.com/questions/16721917/display-rtp-mjpeg).Обратите внимание, что при тестировании я прокомментировал ваш код моментального снимка, превратил переменную 'image' в член класса' ImageSave' и использовал 'fromFXImage (изображение, null)' вместо 'fromFXImage (wi, null)'. Не уверен, что эти изменения скомпрометировали ваш тест или то, что вы пытались продемонстрировать. Если вы все еще считаете, что это проблема, всегда есть: http://bugreport.java.com – jewelsea

+0

Метод моментального снимка является проблемой, поскольку он устанавливает PixelWriter.Type в INT_ARGB_PRE, поэтому после этого у вас есть альфа в вашем изображении (даже в изображении). И SwingFXUtils.fromFXImage() сделает все остальное, даже если вы попытаетесь добавить BufferedImage к методу с типом RGB. Метод не должен устанавливать альфа-файлы в jpeg-файлах! Он хочет добавить прозрачность к снимку. – NwDev

+0

@jewelsea: Я просто попробовал, ты прав. Так же NwDx. Метод моментальных снимков - проблема. Когда я загружаю изображение, а затем сохраняю его, все в порядке. Когда я делаю снимок изображения и сохраняю его, возникает проблема. – Roland

ответ

2

я сделал немного больше Reasearch и сделал пример, показывающий, неправильное обращение с некоторыми методами:

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

Если я запускаю этот код, я получить этот результат. Показывая слева, исходное считанное изображение, в середине скопированное из метода и справа созданное методом SwingFXUtils.fromFXImage. Итак, это для меня ошибка!

enter image description here

Update

На новый комментарий на ошибку:

Это, вероятно, не имеет отношения к проблеме в Thie JIRA, но Ниже ошибка в программе:

srcView.snapshot(parameters, insert); 

Вы не должны полагаться на моментальный снимок, фактически используя пройденный в образе. Это будет, если это возможно, но для правильности вам нужно использовать возвращаемое значение метода. Например:

insert = srcView.snapshot(parameters, insert); 

и они запланировали ошибка исправления для версии 9.

+0

Затем это png, проверьте первые символы файла в текстовом редакторе. Мне нужен jpg. – Roland

+0

Как вы уже сказали, jpeg не способен обрабатывать прозрачность. – NwDev

+0

Да, но ImageIO.write, похоже, не знает, что :-) – Roland

Смежные вопросы