gpt4 book ai didi

c# - 为什么所有的坐标和大小都很奇怪?

转载 作者:太空狗 更新时间:2023-10-30 00:44:16 24 4
gpt4 key购买 nike

这段代码产生了下图。

DrawingVisual visual = new DrawingVisual();
DrawingContext ctx = visual.RenderOpen();

FormattedText txt = new FormattedText("45", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Verdana"), 100, Brushes.Red);
ctx.DrawRectangle(Brushes.White, new Pen(Brushes.White, 10), new System.Windows.Rect(0, 0, 400, 400));
ctx.DrawText(txt, new System.Windows.Point((300 - txt.Width)/2, 10));
ctx.Close();

RenderTargetBitmap bity = new RenderTargetBitmap(300, 300, 40, 40, PixelFormats.Default);
bity.Render(visual);
BitmapFrame frame = BitmapFrame.Create(bity);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(frame);
MemoryStream ms = new MemoryStream();
encoder.Save(ms);

test image

如果位图是 300x300,为什么白色矩形 (0, 0, 400, 400) 只占其中的一小部分? 为什么文本不居中?

我什至不确定 Google 的条款。我寻求智慧。

最佳答案

注意:除了我原来的答案之外还提供了赏金之后添加这个

对于初学者来说,不需要 400x400 背景矩形,因为您只渲染 300x300 位图,所以这里是第一个更改:

ctx.DrawRectangle(Brushes.White, new Pen(Brushes.White, 10), new System.Windows.Rect(0, 0, 300, 300));

进行此更改后,输出将完全相同,但它简化了解释。

在可能且合乎逻辑的情况下,WPF 使用 DIP(与设备无关的像素)而不是像素作为度量单位。当您这样做时:

<Rectangle Width="100" Height="100"/>

您不一定会得到一个 100x100 物理像素的 Rectangle。如果您的设备每物理英寸的像素多于(或少于)96,那么您最终会得到不同数量的物理像素。我猜,每英寸 96 像素是一种行业标准。智能手机和平板电脑等现代设备每物理英寸的像素要多得多。如果 WPF 使用物理像素作为其度量单位,则上述 Rectangle 在此类设备上会呈现得更小。

现在,为了渲染位图(或 JPEG、PNG、GIF 等),必须使用设备相关像素,因为它是光栅化格式(不是矢量格式)。这就是您在调用 RenderTargetBitmap 构造函数时指定的内容。您告诉它您希望生成的位图为 300x300 物理像素,DPI 为 40。由于源的 DPI 为 96(假设您的显示器是行业标准)并且目标的 DPI 为 40,因此它必须缩小源以适应目标。因此,效果是渲染位图中缩小的图像。

现在您真正想要做的是确保源 DPI 和目标 DPI 匹配。它不像硬编码 96 那样简单,因为正如所讨论的那样,这只是一个标准——源实际上可能有比这更多或更少的 DPI。不幸的是,WPF 没有提供获取 DPI 的好方法,我认为这很荒谬。但是,您可以执行一些 p/invoke 操作来获取它:

public int Dpi
{
get
{
if (this.dpi == 0)
{
var desktopHwnd = new HandleRef(null, IntPtr.Zero);
var desktopDC = new HandleRef(null, SafeNativeMethods.GetDC(desktopHwnd));

this.dpi = SafeNativeMethods.GetDeviceCaps(desktopDC, 88 /*LOGPIXELSX*/);

if (SafeNativeMethods.ReleaseDC(desktopHwnd, desktopDC) != 1 /* OK */)
{
// log error
}
}

return this.dpi;
}
}

private static class SafeNativeMethods
{
[DllImport("User32.dll")]
public static extern IntPtr GetDC(HandleRef hWnd);

[DllImport("User32.dll")]
public static extern int ReleaseDC(HandleRef hWnd, HandleRef hDC);

[DllImport("GDI32.dll")]
public static extern int GetDeviceCaps(HandleRef hDC, int nIndex);
}

所以现在您可以将相关的代码行更改为:

RenderTargetBitmap bity = new RenderTargetBitmap(300, 300, this.Dpi, this.Dpi, PixelFormats.Default);

而且无论您在什么设备上运行,它都可以正常工作。您最终总是会得到一个 300x300 物理像素的位图,并且源总是会准确地填充它。

关于c# - 为什么所有的坐标和大小都很奇怪?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8287748/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com