5

グラデーションの背景に透明なPNGを読み込んで表示すると、次の結果が得られます。

ここに画像の説明を入力してください

Paint.NETで同じファイルを開くと、次のような背景を追加します。

ここに画像の説明を入力してください

どういうわけか、JavaFXは画像の鮮明さを緩めます。これは私のアプリのすべての画像の問題であり、この特定のケースで最も目立つのではないかと心配しています。

この特定の画像をロードする方法を示す抽出されたコードは次のとおりです。

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

参考までに、元の画像へのリンクを示します

私はこれが起こっている考えられる理由を強調する答えを探しています

4

1 に答える 1

10

アップデート

Java 8のJavaFXイメージは、すべての場合に鮮明にレンダリングされるようになりました。

質問で説明されている元の問題は解決されました。

この動作に関してDreenが提起したバグ、RT-28765の画像のサブピクセル配置が正しくないことは、ImageViewでのRT-19282[StackPane]の不要なぼかしの複製としてクローズされました 。RT-19282は、Java8の修正としてクローズされました。

Windows7でJava8ビルド108をテストしました。この回答のサンプルアプリケーションは正しく表示されるようになりました(xまたはy方向に0.5ピクセルオフセットされることがあるファジー画像はありません)。


これは素晴らしい質問であり、非常に奇妙な行動です。

可能な説明と回避策を提供するサンプルプログラムをまとめました。

このプログラムを実行し、境界線を少しドラッグしてサイズを変更した後のこのプログラムの出力は、次のとおりです。左側のファジークラウドは、にImageView配置された標準GridPaneです。右側の鮮明なクラウドは、同じに配置されたImageView回避策修正クラス()でラップされています。CenteredRegionGridPane

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方向に0.5ピクセルオフセットされているため、ファジーに見えます。これは、グリッド領域がsnapToPixelとして設定されているにもかかわらずtrueです。

レイアウトを含むステージのサイズが動的に変更されると、ファジー画像はピクセル整列と非ピクセル整列を交互に繰り返します(シーンの幅と高さの奇数または均一性によって異なります)。これにより、ステージの境界線のサイズを変更するときに、ファジーな画像がファジーとクリアの間で連続的に交互に現れるため、迷惑なきらめき効果が作成されます。

snapToPixel親コンテナでがtrueに設定されている場合、ファジーイメージの動作はバグのように見えるため、JavaFXランタイムプロジェクトに対してバグを報告し、バグ内のこのスタックオーバーフローの質問にリンクしてリンクを配置することをお勧めします。コメントで作成されたバグに。

鮮明なバージョンは、ピクセルの位置合わせを保証するカスタム領域の実装に収容されているため、鮮明なままです。

テストシステムはwin7+jdk8b77 +ATIHD4600グラフィックカードでした。

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); }
}
于 2013-03-01T20:48:37.073 に答える