图形容器如何工作? [英] How do graphic containers work?

查看:48
本文介绍了图形容器如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图弄清楚gdi +图形容器如何与不同的图形单元一起工作.看一下下面的代码.它会编译,您可以将其粘贴到新的新窗体中.

I'm trying to figure out how exactly gdi+ graphics containers works with different graphic units. Take a look at the below code. It compiles, you can paste it into a fresh new form.

void Form2_Paint(object sender, PaintEventArgs e)
{
    var gfx = e.Graphics;

    System.Diagnostics.Debug.WriteLine("DpiX={0}, DpiY={1}", gfx.DpiX, gfx.DpiY);

    gfx.PageUnit = GraphicsUnit.Inch;

    var pen = new Pen(Color.Black, 0.01f);

    // Create outer container, 2 inches in size with X and Y set to 0.1 inches
    var outerContainer = gfx.BeginContainer(
        new RectangleF(0.1f, 0.1f, 2, 2),
        new RectangleF(0, 0, 2, 2),
        GraphicsUnit.Pixel);

    // Draw the outer rectangle
    gfx.DrawRectangle(pen, new Rectangle(0, 0, 2, 2));

    // Create inner container, 1 inch in size with X and Y set to 0.1 inches
    var innerContainer = gfx.BeginContainer(
        new RectangleF(0.1f, 0.1f, 1, 1),
        new RectangleF(0, 0, 1, 1),
        GraphicsUnit.Pixel);

    // Draw the inner rectangle
    gfx.DrawRectangle(pen, new Rectangle(0, 0, 1, 1));

    gfx.EndContainer(innerContainer);

    gfx.EndContainer(outerContainer);
}

以上代码是嵌套图形容器的一个非常简单的示例,我没有使用缩放转换.当使用上面的绘制处理程序时,表单是这样的:

Above code is a pretty simple example of nested graphic containers, I used no scaling transformation. This is how the form looks like when above paint handler is used:

这很简单.现在,我将尝试描述问题所在.

It's pretty simple. Now, I will try to describe what the problem is.

这是 BeginContainer 方法的签名:

public GraphicsContainer BeginContainer(
    RectangleF dstrect,
    RectangleF srcrect,
    GraphicsUnit unit
)

我无法理解的 GraphicsUnit单位参数.

从MSDN:

GraphicsUnit枚举的成员,它指定容器的度量单位.

Member of the GraphicsUnit enumeration that specifies the unit of measure for the container.

这似乎是 not 是真的!

您可以在我的代码中看到,我使用的是英制单位,例如: gfx.PageUnit = GraphicsUnit.Inch .

As you can see in my code I'm using Inch units as such: gfx.PageUnit = GraphicsUnit.Inch.

但是,当我创建容器时,这就是作为单位参数传递给 BeginContainer 方法的内容: GraphicsUnit.Pixel .创建容器后会发生什么?正在使用英寸(英寸)(实际上是我想要的).但是,如果我将 GraphicsUnit.Inch (或毫米或其他其他参数)传递给参数,则会使用像素.因此,似乎为了完成我想要的(使用英寸),我必须指定像素?

But, when I'm creating containers this is what I'm passing as units argument to the BeginContainer method: GraphicsUnit.Pixel. What happens after the container is created? Inches are being used (what I actually want). But if I pass GraphicsUnit.Inch (or millimeters or anything else) to the argument, pixels are used. So, it seems that in order to accomplish what I want (use inches) I have to specify pixels?

这对我来说毫无意义.您可以尝试在上述代码的 BeginContainer 方法中更改单位,并观察到奇怪的结果.我已经阅读了MSDN以及可以收集到的所有信息,但我仍然一无所知.

This makes no sense to me. You can try changing units in BeginContainer methods in above code and observe strange results. I've read the MSDN and everything I could gather on this but I am still clueless.

我正在编写使用gdi +绘制大量内容的软件,并且它以毫米为单位进行打印-当我开始使用容器时,我很惊讶我显然需要指定像素为单位.我真的很怀疑任何提到 pixels 的打印代码.一定是我对此事有很大的误会.

I'm writing software which draws a lot of stuff using gdi+ and it's using millimeter units for printing purposes - when I started using containers I was quite surprised that I apparently need to specify pixels as units. I'm really suspicious of any printing code where pixels are mentioned. It must be that I have a big misunderstanding of this matter.

因此,考虑到以上所有问题,我的问题是:此方法中 unit 参数的目的是什么?

So, all above considered, my question is: what is the purpose of the unit argument in this method?

推荐答案

不幸的是,据我所知,GDI +是Windows中记录最差的API之一.很少有人真正使用它来进行网络浏览,而对您的问题一无所知.

Unfortunately, GDI+ is as far as I can tell one of the most poorly documented APIs in Windows. Some browsing on the web turns up very few people really using it much, and no insight into your question.

更不幸的是,基本上将GDI + API直接复制到了.NET Graphics 对象.即使是文档,大部分也只是逐字复制.请注意.NET Graphics.BeginContainer之间的相似之处方法(RectangleF,RectangleF,GraphicsUnit)和Windows

Even more unfortunately, the GDI+ API was basically copied straight over to the .NET Graphics object. Even the documentation was for the most part just copied verbatim. Note the similarities between the .NET Graphics.BeginContainer Method (RectangleF, RectangleF, GraphicsUnit) and the Windows Graphics.BeginContainer(const RectF, const RectF, Unit) method pages.

进一步复杂化的是,此博客条目令人着迷地读取:

To further complicate matters, there is this blog entry which tantalizingly reads:

另一个示例是Graphics类中的Save和BeginContainer方法,它们的执行方式非常不同,但是具有相同的MSDN文档,无法区分这两个调用

Another example is the Save and BeginContainer methods in Graphics class, which perform very differently, yet have the same MSDN documentation that fails to differentiate between the two calls

…但没有详细介绍这两种方法实际上有何不同.

…but fails to go into any detail as to how these two methods are in fact different.

现在,所有这些,通过一些实验,我认为我已经解码了参数和行为:

Now, all that said, with some experimentation, I think I've decoded the parameters and behavior:

  • unit 参数似乎用于指定用于 srcrect 参数
  • 的单位
  • dstrect 参数是以 Graphics 对象的当前使用单位指定的.
  • 新容器将其 Graphics.PageUnit 设置回默认值 GraphicsUnit.Display
  • The unit parameter appears to be used to specify the units used for the srcrect parameter
  • The dstrect parameters is specified in the units currently in use for the Graphics object
  • The new container winds up with its Graphics.PageUnit set back to the default value of GraphicsUnit.Display

我在文档中找不到上面前两点的任何提示.只是通过实验和仔细观察,我才知道了这一点,并且坦率地说,没有实际的文档来支持我的结论,我仍然不确定100%.

I could not find any hint of the first two points above in the documentation. It was only through experimentation and careful observation that I learned that, and frankly without actual documentation to back my conclusion up, I'm still not 100% sure about it.

BeginContainer()方法文档中第三点的提示:

There is a hint of the third point in the documentation of the BeginContainer() method:

通过BeginContainer方法建立的图形状态包括默认图形状态的呈现质量;调用该方法时存在的任何渲染质量状态更改都将重置为默认值.

The graphics state established by the BeginContainer method includes the rendering qualities of the default graphics state; any rendering-quality state changes existing when the method is called are reset to the default values.

乍一看,这句话似乎是在说只有渲染质量状态改变"才被重设.但是仔细阅读后会发现,状态的一部分特别是被简单地调用了,因为它在所有重置的状态中都包含.当然,更仔细的阅读不会使自己获得任何额外的理解:(,但是至少有人可以看到该句子不应被视为一切上的最后一句话.重置.

At first glance, this sentence seems to be saying that only the "rendering-quality state changes" are reset. But reading more carefully, one sees that part of the state is simply being called out in particular, as it is included in all of the state that is reset. Granted, a more careful reading does not gain oneself any additional understanding :(, but at least one can see the sentence shouldn't be taken as the last word on everything that's reset.


因此,使事情正常运行的关键是在每个步骤中指定您要使用的单位(例如 GraphicsUnit.Inch ):在创建容器之前的初始设置中,在对 BeginContainer()的调用中(但在这里,仅用于控制 srcrect 的解释方式),然后最终在 BeginContainer(),再次设置 Graphics.PageUnit 属性.


So the key to getting things to work correctly would be to specify the units you want to work in (e.g. GraphicsUnit.Inch) at every step of the way: in the initial settings before you create a container, in the call to BeginContainer() (but here, only to control the way srcrect is being interpreted), and then finally just after BeginContainer(), setting the Graphics.PageUnit property again.

当我这样做的时候,我能够使用我想绘制的任何单位.我什至可以混合和匹配,尽管与我绘制的矩形相比,当然会导致一些非直觉的值传递给容器矩形.

When I did it that way, I was able to use whatever units I wanted to drawing. I could even mix and match, though of course that resulted in some non-intuitive values being passed for the container rectangles as compared to the rectangles I was drawing.

作为一个示例,下面是一个片段,其中我将英寸表示为 Graphics 的初始状态,并将毫米表示为容器:

As an example, here's a snippet where I use inches for the initial Graphics state, and millimeters for the container:

gfx.PageUnit = GraphicsUnit.Inch;

using (Pen blackPen = new Pen(Color.Black, 0.01f))
using (Pen redPen = new Pen(Color.Red, 0.01f))
{
    gfx.DrawRectangle(blackPen, .25f, .25f, 2, 2);

    var outerContainer = gfx.BeginContainer(
        new RectangleF(.25f, .25f, 2, 2),
        new RectangleF(0, 0, 2 * 25.4f, 2 * 25.4f),
        GraphicsUnit.Millimeter);

    gfx.PageUnit = GraphicsUnit.Millimeter;
    gfx.DrawRectangle(redPen, .25f * 25.4f, .25f * 25.4f, 1.5f * 25.4f, 1.5f * 25.4f);

    gfx.EndContainer(outerContainer);
}

产生此图像:

因此,我能够在容器外部绘制2x2英寸的矩形,然后在容器内部绘制1.5x1.5英寸的矩形,但是使用毫米(在参数中进行显式转换,只是为了使其更清晰)对自己来说,我在做什么).

So I'm able to draw a 2x2 inch rectangle outside the container, and then inside the container I draw a 1.5x1.5 inch rectangle, but do so using millimeters (converting explicitly in the parameters, just to make it clearer to myself what I'm doing).

这篇关于图形容器如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆