2013-03-01 98 views
3

當我加載並用以下結果上的梯度背景上顯示透明的PNG被丟失,加上它看起來像的背景:JavaFX的圖像(PNG)透明度脆度渲染

enter image description here

不知何故,JavaFX的使圖像脆鬆,我擔心這可能是在我的應用,圖像和它只是最v時的問題在這種特殊情況下是明智的。

在這裏被提取表示我怎樣加載這個特定圖像的代碼:

ImageView imgDownload = new ImageView(this.getClass().getResource("/img/docstore/document_downloaded_btn.png").toExternalForm()); 
imgDownload.setFitWidth(59); 
imgDownload.setFitHeight(32); 
GridPane.setHalignment(imgDownload, HPos.CENTER); 
grid_item.add(imgDownload, 3, 0); 

作爲參考,here is a link to the original image

我在尋找一個答案突出一個可能的原因發生這種情況

+0

看起來它試圖做子像素放置,也許只是一點點拉伸。 – 2013-03-01 14:57:38

+0

這是我可以關閉的東西嗎?或以其他方式解決? – Dreen 2013-03-01 15:16:53

+0

我試着把它設置爲true或false,但它沒有幫助:http://docs.oracle.com/javafx/2/api/javafx/scene/layout/Region.html#snapToPixelProperty – Dreen 2013-03-01 15:23:09

回答

9

更新

JavaFX的圖像中的Java 8,現在在所有情況下清脆呈現。

問題中描述的原始問題已得到解決。

Dreen針對此行爲提出的錯誤RT-28765 Incorrect subpixel placement for an Image已作爲RT-19282 [StackPane] unwanted blur with ImageView的副本關閉。對於Java 8,RT-19282已關閉。

我在Windows 7上測試了Java 8 build 108。此答案中的示例應用程序現在正確顯示(沒有模糊圖像有時在x或y方向上偏移半個像素)。


這是一個很好的問題和非常好奇的行爲。

我整理了一個示例程序,它提供了一個可能的解釋和解決方法。

運行該程序並拖動邊框稍微調整大小後,此程序的輸出如下所示。左邊的模糊雲是放置在GridPane中的標準ImageView。右側的清晰雲是一個ImageView包裹在我的解決方法修復程序類(CenteredRegion)中,放置在相同的GridPane中。

fuzzyAndCrispClouds

在顯示上述的圖像,該程序的輸出結果是:

Layout SnapToPixel: true 
... 
fuzzy: New Bounds: BoundingBox [minX:14.5, minY:12.5, minZ:0.0, width:59.0, height:32.0, depth:0.0, maxX:73.5, maxY:44.5, maxZ:0.0] 
fuzzy: xDisplacement: 0.5, yDisplacement: 0.5 
crisp: New Bounds: BoundingBox [minX:84.0, minY:13.0, minZ:0.0, width:59.0, height:32.0, depth:0.0, maxX:143.0, maxY:45.0, maxZ:0.0] 
crisp: xDisplacement: 0.0, yDisplacement: 0.0 

正如可以看到的,模糊圖像尚未像素對準,並且由半象素偏移在x和y方向,導致它看起來模糊。儘管網格區域具有snapToPixel,但設置爲true

由於包含佈局的舞臺是動態調整大小的,所以模糊圖像將在像素對齊而不是像素對齊(取決於場景的寬度和高度的奇怪或均勻性)之間交替。由於模糊圖像在模糊和清晰之間不斷交替,所以在調整舞臺邊框的大小時會產生惱人的閃爍效果。

當父容器上的snapToPixel設置爲true時,模糊圖像的行爲似乎是一個錯誤,所以我建議filing a bug against the JavaFX runtime project並鏈接回該堆棧溢出問題的bug並將鏈接放置到在評論中創建了錯誤。

清晰的版本保持清晰,因爲它位於自定義區域實現中,以確保像素對齊。

測試系統爲win7 + jdk8b77 + ATI HD4600顯卡。

import javafx.application.Application; 
import static javafx.application.Application.launch; 
import javafx.beans.value.*; 
import javafx.geometry.*; 
import javafx.scene.Node; 
import javafx.scene.Scene; 
import javafx.scene.image.*; 
import javafx.scene.layout.*; 
import static javafx.scene.layout.Region.USE_PREF_SIZE; 
import javafx.stage.Stage; 

public class TransparentPngSample extends Application { 
    public static final String IMAGE_LOC = "http://i.imgur.com/byY8whh.png"; 

    @Override public void start(Stage stage) { 
    Pane layout = createSceneContent(); 
    stage.setScene(new Scene(layout)); 
    stage.show(); 

    System.out.println("Layout SnapToPixel: " + layout.snapToPixelProperty().get()); 
    } 

    private Pane createSceneContent() { 
    final Image cloudImage = new Image(IMAGE_LOC); 
    final ImageView fuzzyCloud = new ImageView(cloudImage); 
    final CenteredRegion crispCloud = new CenteredRegion(new ImageView(cloudImage)); 

    GridPane layout = new GridPane(); 
    layout.setHgap(10); 
    layout.setVgap(10); 
    layout.addRow(0, fuzzyCloud, crispCloud); 
    layout.setAlignment(Pos.CENTER); 
    layout.setStyle("-fx-padding: 10px; -fx-background-color: slategrey;"); 

    fuzzyCloud.boundsInParentProperty().addListener(new BoundsReporter("fuzzy")); 
    crispCloud.boundsInParentProperty().addListener(new BoundsReporter("crisp")); 

    return layout; 
    } 

    class CenteredRegion extends Region { 
    private Node content; 

    CenteredRegion(Node content) { 
     this.content = content; 
     getChildren().add(content); 
    } 

    @Override protected void layoutChildren() { 
     content.relocate(
     Math.round(getWidth()/2 - content.prefWidth(USE_PREF_SIZE)/2), 
     Math.round(getHeight()/2 - content.prefHeight(USE_PREF_SIZE)/2) 
    ); 

     System.out.println("crisp content relocated to: " + 
     getLayoutX() + "," + getLayoutY() 
    ); 
    } 

    public Node getContent() { 
     return content; 
    } 
    } 

    class BoundsReporter implements ChangeListener<Bounds> { 
    final String logPrefix; 

    BoundsReporter(String logPrefix) { 
     this.logPrefix = logPrefix; 
    } 

    @Override public void changed(ObservableValue<? extends Bounds> ov, Bounds oldBounds, Bounds newBounds) { 
     System.out.println(logPrefix + ": " + 
     "New Bounds: " + newBounds 
    ); 
     double xDisplacement = newBounds.getMinX() - Math.floor(newBounds.getMinX()); 
     double yDisplacement = newBounds.getMinY() - Math.floor(newBounds.getMinY()); 
     System.out.println(logPrefix + ": " + 
     "xDisplacement: " + xDisplacement + ", " + 
     "yDisplacement: " + yDisplacement 
    ); 
    } 
    }   

    public static void main(String[] args) { launch(args); } 
} 
+0

聽起來好像它可能是由於某人忘記他們在維基中使用'dimension/2'而導致的浮點上下文或其他人將類型從整數切換到浮點(其目的是修復其他內容)。這種微妙的問題將是一個真正的經典! – 2013-03-03 07:19:02

+0

感謝jewelsea的回答,我會盡快接受它,希望今天能實施並測試它。 – Dreen 2013-03-04 09:58:08

+0

有用!將盡快報告錯誤Jira幻想來臨... – Dreen 2013-03-04 11:31:55