【问题标题】:WinRT: How do I ensure Images are drawn in a pixel-perfect way on a Canvas?WinRT:如何确保在 Canvas 上以像素完美的方式绘制图像?
【发布时间】:2013-09-26 09:27:51
【问题描述】:

我在 Windows 运行时环境中将 Image 实例添加到 Canvas 中,当在 140 和 180 比例分辨率显示时,我的图像不断放大,它在比例分辨率 100 时看起来很完美。我尝试创建 3 个 PNG 图像,每个比例尺都有一个:100、140、180,但它仍然按比例放大它们,它们看起来很模糊。我在青色背景上创建了一个带有 4 个黑色像素的测试图像,然后从模拟器中截取了一张截图,看看图像是如何模糊的,我的原始图像只有 4 个完美的黑色像素:

我尝试更改我的 Image 对象的拉伸模式,但它什么也没做。我正在使用此代码在运行时添加图像:

var bitmapImage = new BitmapImage();
StorageFile bitmapFile = await StorageFile.GetFileFromApplicationUriAsync(imageUri);
await bitmapImage.SetSourceAsync(await bitmapFile.OpenReadAsync());

Image image = new Image{ Source = bitmapImage};
image.SetValue(Canvas.LeftProperty, x);
image.SetValue(Canvas.TopProperty, y);
canvas.Children.Add(image);

如何让图像在画布中完美地绘制像素而不进行缩放,并且在我想要的确切 x/y 坐标处?

【问题讨论】:

标签: c# image canvas windows-runtime winrt-xaml


【解决方案1】:

我发现这个问题也很成问题。我正在创建自定义位图并将它们绘制在画布上的不同位置。我在 XAML 中找不到方法,但我找到了使用 Direct2D 的方法。设置 D2DContext 时,有一个名为 SetUnitMode() 的函数。默认单位模式是“DIPS”,这会导致所有图形都被缩放。通过切换到 PIXELS 模式,系统会停止缩放绘图并以 1:1 的比例进行所有操作。

m_d2dContext->SetUnitMode(D2D1_UNIT_MODE_PIXELS);

【讨论】:

    【解决方案2】:

    还有一些事情可能对您的解决方案有所帮助。

    1. 在您的图片上使用UseLayoutRounding="False"
    2. 把你的Canvas全屏Viewbox,然后将CanvasWidthHeight设置为屏幕分辨率。在这种情况下,您将使用未缩放的 Canvas.Left/Top 值。
    3. 使用 Direct2D/Direct3D 进行渲染。

    祝你好运。

    【讨论】:

    • 哎哟。这就是答案。不是在公园里散步。
    • 前几天我实际上遇到了同样的问题。我最终放弃了。希望超高分辨率的屏幕能让这一切变得无关紧要。
    • 我尝试了 Viewbox,但无法正常工作...我将不得不联系 Microsoft 寻求帮助...
    【解决方案3】:

    这是一段xaml代码

    您始终可以使用后面代码中的缩放变换来将图像缩放到适当的数量,无论是少还是多。

    <Image  Canvas.Left="150"  Height="170" Width="170" Visibility="Visible" Stretch="None">
                    <Image.Source >
                        <BitmapImage UriSource="ms-appx:///Assets/rollingDieSprite.png"></BitmapImage>
                    </Image.Source>
    
                    <Image.RenderTransform>
                        <ScaleTransform ScaleX="4" ScaleY="4" x:Name="scaleTfDie"></ScaleTransform>
                    </Image.RenderTransform>
                </Image>
    

    在后面的c#代码中你可以去以下

    ScaleTransform sc = new ScaleTransform();
                sc.ScaleX = 0.9;
                sc.ScaleY = 0.9;
                imgDieRolling.RenderTransform = sc;
    

    这将控制缩放。尝试使用 fill=none 。让我知道它是否有效。

    【讨论】:

    • 这行不通,我根本不想要任何缩放。使用 ScaleTransform 并不能消除模糊问题。我不想要任何缩放我只想将我的图像绘制到屏幕上而不以任何方式缩放它们。
    【解决方案4】:

    我想我有一个解决方法,但它需要两个步骤:

    首先,我必须使用更标准的方式加载图像,而无需像这样获取文件路径。

    var bitmapImage = new BitmapImage(imageUri);
    

    这必须以某种方式在内部保留更多信息,即该图像来自具有当前显示的相应 ResolutionScale 的文件。因此,当它被画布绘制时,它根本没有缩放。然而,这只解决了一半的问题。

    下一个问题是用于指定图像绘制位置的 x、y 坐标正在缩放,因此图像绘制在错误的位置,比我想要的位置更远。我唯一能做的就是先像这样取消缩放它们:

    var resScale = DisplayInformation.GetForCurrentView().ResolutionScale;
    Image image = new Image{ Source = bitmapImage};
    image.SetValue(Canvas.LeftProperty, (x * 100.0) / (int)resScale);
    image.SetValue(Canvas.TopProperty, (y * 100.0) / (int)resScale);
    canvas.Children.Add(image);
    

    整个事情看起来有点疯狂,但到目前为止它似乎工作......谁有更好的解决方案或解释为什么这一切都是必要的?似乎 Canvas 类需要一个不影响图像或不同分辨率显示器坐标的未缩放模式。

    更新:这并不完美,使用双精度值存储会导致精度损失,有时还会出现抗锯齿伪影。如果您想要像素完美的图形,这是不可接受的。我仍在寻找完美的解决方案。

    【讨论】:

    • 你只是在改变相对于画布的 X 和 Y。它甚至如何帮助像素完美?就像为网格内的图像添加边距一样。你还做了什么??它只会解决像在哪里设置 Image 这样的小问题。但是缩放呢?是的,我们可以减少或增加它以隐藏像素损失但真正的像素损失。你有没有其他方法请添加它然后:)
    • (new BitmapImage()).PixelHeight(new BitmapImage()).PixelWidth 做些事情,让他们决定图像控件或您正在使用的画布的高度。我希望这会有所帮助:)
    【解决方案5】:

    您可以将Stretch 属性更改为"None",如果您的图像仍然是网格化的:

    您应该查看它保存在什么 DPI 上。 WPF 尝试独立于 DPI,因此它尝试在每个相同尺寸的显示器上绘制 5"x5" 的图像。即使分辨率更高,它仍应为 5"x5",只有高分辨率才能以更高质量渲染(光栅化)图像。

    这里有一些信息:http://www.wpflearningexperience.com/?p=41

    How do I convert a WPF size to physical pixels?

    【讨论】:

    • 您的回答似乎与 WPF 有关,但我对 Windows 应用商店应用程序开发很感兴趣。我尝试将 Stretch 设置为 None,但没有效果。我知道你在谈论 5" 缩放是什么,我不希望这种情况发生在我的应用上,因为我想自己处理它,这样我就可以做到像素完美。
    猜你喜欢
    • 2019-05-10
    • 2019-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-16
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    相关资源
    最近更新 更多