本文介绍了渲染时会丢失JavaFX Image(PNG)透明性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在渐变背景上加载并显示透明的PNG,结果如下:

I am loading and displaying a transparent PNG on a gradient background with the following result:

如果我在Paint.NET中打开相同的文件,请添加看起来像这样的背景:

If I open the same file in Paint.NET, add the background it looks like that:

以某种方式,JavaFX使图像变得松脆,我担心这可能是我应用程序中所有图像的问题,并且在特定情况下它最明显.

Somehow, JavaFX makes the image loose crispness, I fear this may be an issue for ALL images in my app and its just that its most visible in this particular case.

以下是提取的代码,显示了我如何加载此特定图像:

Here is extracted code showing how I load this particular image:

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

作为参考,此处是指向原始图像的链接.

我正在寻找一个答案,以突出显示发生这种情况的可能原因

推荐答案

更新

现在,在所有情况下,Java 8中的JavaFX图像都可以清晰呈现.

JavaFX images in Java 8 are now rendered crisply in all cases.

问题中描述的原始问题已解决.

The original issue described in the question has been addressed.

Dreen针对此行为提交的错误 RT-28765图像的亚像素位置不正确作为 RT-19282 [StackPane]不必要的模糊与ImageView . RT-19282已针对Java 8修复为关闭状态.

The bug Dreen filed regarding this behaviour, RT-28765 Incorrect subpixel placement for an Image, was closed as a duplicate of RT-19282 [StackPane] unwanted blur with ImageView. RT-19282 was closed as fixed for Java 8.

我在Windows 7上测试了 Java 8 build 108 .正确显示(有时没有模糊图像在x或y方向上偏移半个像素).

I tested Java 8 build 108 on Windows 7. The sample application in this answer now displays correctly (no fuzzy image sometimes offset by half a pixel in the x or y direction).

这是一个很好的问题,而且行为也很好奇.

This is an excellent question and very curious behaviour.

我整理了一个示例程序,提供了可能的解释和解决方法.

I put together a sample program which offers a possible explanation and a workaround.

运行该程序并将其拖动一点点以调整其大小后,该程序的输出如下.左侧的模糊云是放置在GridPane中的标准ImageView.右侧的浮云是包裹在我的解决方法修复类(CenteredRegion)中的ImageView,放置在同一GridPane中.

The output of this program after running it and dragging the border around a little to resize it, is as below. The fuzzy cloud on the left is a standard ImageView placed in a GridPane. The crisp cloud on the right is an ImageView wrapped in my workaround fix class (CenteredRegion), placed in the same GridPane.

显示上面的图像时,程序的输出为:

While the above image is displayed, the output of the program is:

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.

As you can see, the fuzzy image has not been pixel aligned and is offset by half a pixel in the x and y direction, causing it to look fuzzy. This is despite the grid region having it's snapToPixel setting as true.

随着包含布局的舞台的动态调整大小,模糊图像将在像素对齐与像素对齐之间交替变化(取决于场景的宽度和高度的奇数或均匀性).由于模糊图像在模糊和清晰之间不断交替,因此在调整舞台边框大小时,这会产生令人讨厌的闪烁效果.

As the stage containing the layout is dynamically resized, the fuzzy image will alternate between being pixel aligned and not being pixel aligned (depending on the oddness or evenness of the width and height of the scene). This creates an an annoying shimmering effect as you resize the stage borders, due to the fuzzy image continuously alternating between being fuzzy and clear.

当在父容器上将snapToPixel设置为true时,模糊图像的行为似乎是一个错误,因此我建议针对JavaFX运行时项目提交错误,并链接回该错误中的此堆栈溢出问题,并在注释中放置指向已创建的错误的链接.

The behaviour of the fuzzy image would seem to be a bug when snapToPixel is set to true on the parent container, so I'd advise filing a bug against the JavaFX runtime project and linking back to this stack overflow question in the bug and placing a link to the created bug in a comment.

清晰版本保持清晰,因为它位于可确保像素对齐的自定义区域实现中.

The crisp version remains crisp because it is housed in a custom region implementation which ensures pixel alignment.

测试系统为win7 + jdk8b77 + ATI HD4600显卡.

Test system was win7 + jdk8b77 + ATI HD4600 graphics card.

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

这篇关于渲染时会丢失JavaFX Image(PNG)透明性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-28 17:27