【问题标题】:Flip the GraphicsPath that draws the text/string翻转绘制文本/字符串的 GraphicsPath
【发布时间】:2019-04-10 10:27:12
【问题描述】:

我的文本类中有这个方法,但我似乎无法翻转整个文本。
我正在使用矩阵来转换用于绘制字符串的GraphicsPath

这是我使用@Jimi 回答后的代码:

    public LayerClass DrawString(LayerClass.Type _text, string text, RectangleF rect, Font _fontStyle, Brush brush, float angle, PaintEventArgs e)
    {
        using (StringFormat string_format = new StringFormat())
        {
            SizeF stringSize = e.Graphics.MeasureString(text, _fontStyle);
            rect.Location = new PointF(Shape.center.X - (rect.Width / 2), Shape.center.Y - (rect.Height / 2));
            GraphicsContainer gc = e.Graphics.BeginContainer();
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
            //e.Graphics.DrawRectangle(Pens.Red, Rectangle.Round(rect));

            RectangleF r = new RectangleF(rect.Location, rect.Size);
            GraphicsPath path = new GraphicsPath();
            if (text == "" || text == " ")
                path.Dispose(); //Disposes the path to prevent OutOfMemoryExcetption
            else
            {
                path.AddString(text, _fontStyle.FontFamily, Convert.ToInt32(_fontStyle.Style), _fontStyle.Height, new Point(0,0), string_format);
                RectangleF text_rectf = path.GetBounds();
                PointF[] target_pts = {
                            new PointF(r.Left, r.Top),
                            new PointF(r.Right, r.Top),
                            new PointF(r.Left, r.Bottom)};
                //e.Graphics.DrawRectangle(Pens.Red, Rectangle.Round(r));
                using (Matrix m = new Matrix(text_rectf, target_pts)) 
                using (Matrix rotate = new Matrix())
                using (Matrix FlipXMatrix = new Matrix(-1, 0, 0, 1, 0, 0)) 
                using (Matrix FlipYMatrix = new Matrix(1, 0, 0, -1, 0, 0))
                using (Matrix TransformMatrix = new Matrix())
                {
                    TransformMatrix.Multiply(m);
                    m.RotateAt(angle, new PointF(0 + (stringSize.Width / 2), +(r.Height * 2)));
                    rotate.RotateAt(angle, new PointF(r.X, r.Y));
                    TransformMatrix.Multiply(rotate);
                    if (flipped)
                    {
                        TransformMatrix.Multiply(FlipXMatrix);
                    }
                    path.Transform(TransformMatrix);

                    if (flipY)
                    {
                        TransformMatrix.Multiply(FlipYMatrix);
                        path.Transform(TransformMatrix);
                    }

                    //Checks if the user wants the text filled or outlined
                    if (!isOutlined)
                        e.Graphics.FillPath(Brushes.Red, path);
                    else
                        e.Graphics.DrawPath(Pens.Red, path);
                } 
            }
        e.Graphics.EndContainer(gc);
        }
        this._Text = text;
        this._TextRect = rect;
        this.brush = brush;
        this._Angle = angle;
        return new LayerClass(_text, this, text, rect);
    }

现在的问题是,它超出了图片框的中心。

【问题讨论】:

    标签: c# .net winforms gdi+ graphicspath


    【解决方案1】:

    有一种更简单的方法翻转Graphics 对象。
    创建一个Matrix,它是需要应用于指定对象的所有转换的Matrix multiplication 的结果。

    矩阵变换可以应用于GraphicsPath 对象或Graphics 对象。或者,当需要按顺序执行多个转换时。

    .Net System.Drawing.Drawing2D Matrix 类没有预先构建的Flip(镜像)转换,但是这个 Matrix 结构已经众所周知(我不确定这是为什么没有Matrix类中的具体方法):

    | 1 | 0 | 0 |       |-1 | 0 | 0 |       | 1 | 0 | 0 |
    | 0 | 1 | 0 |       | 0 | 1 | 0 |       | 0 |-1 | 0 |
    | 0 | 0 | 1 |       | 0 | 0 | 1 |       | 0 | 0 | 1 |
    
       Identity         Mirror X-Axis       Mirror Y-Axis
        Matrix              Matrix             Matrix
    

    您可以注意到(在文档中也有报道)第 3 列始终相同,因此,在构建新 Matrix 时,第 3 列值是隐含的,由 Matrix 类初始化提供,因此我们仅指定前 2 列中的元素。

    重要说明,直接来自 Matrix 类文档:

    注意
    复合变换的顺序很重要。一般来说,旋转,然后缩放,然后平移是不一样的 缩放,然后旋转,然后平移。同样,矩阵的顺序 乘法很重要。一般来说,ABC和BAC是不一样的

    使用 GraphicsPath.AddString() 方法Panel 上绘制的字符串示例。
    GraphicsPath 对象添加了两个矩阵变换:
    一个Flip-X 和一个Flip-Y,使用Matrix.Multiply() 方法组合:

    Flip-XFlip-Y 矩阵的构建包括 XY 转换,应用于每个 Matrix 的第三行。 翻译值由 Canvas 尺寸决定。
    例如,Flip-X 矩阵:

    使用[Canvas].Width = 100 =>:
    旋转元素:在原点Point(0, 0) 上将 X 轴旋转 180°(-1 弧度)。
    平移元素:将X 位置100 图形单元向右平移(正值)。

    | -1  |  0  |  0  |
    |  0  |  1  |  0  |
    | 100 |  0  |  1  |
    
       Mirror X-Axis
      Translate X +100
          Matrix 
    

    效果的视觉表示。
    代码中引用的控件与您可以在此处看到的相同(如果您需要重现它)。

    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Drawing.Text;
    
    bool flipX = false;
    bool flipY = false;
    bool outlined = false;
    float sampleFontEmSize = 28f;
    string sampleText = "Sample Text to Flip";
    FontFamily sampleFont = new FontFamily("Segoe UI");
    
    private void panel1_Paint(object sender, PaintEventArgs e)
    {
        Panel panel = sender as Panel;
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    
        using (var path = new GraphicsPath())
        using (var format = new StringFormat(StringFormatFlags.NoClip | StringFormatFlags.NoWrap))
        {
            format.Alignment = StringAlignment.Center;
            format.LineAlignment = StringAlignment.Center;
            path.AddString(sampleText, sampleFont, (int)FontStyle.Regular, sampleFontEmSize, panel.ClientRectangle, format);
    
            using (var flipXMatrix = new Matrix(-1, 0, 0, 1, panel.Width, 0))
            using (var flipYMatrix = new Matrix(1, 0, 0, -1, 0, panel.Height))
            using (var transformMatrix = new Matrix())
            {
                if (flipX) {
                    transformMatrix.Multiply(flipXMatrix);
                }
                if (flipY) {
                    transformMatrix.Multiply(flipYMatrix);
                }
                path.Transform(transformMatrix);
                //Or e.Graphics.Transform = TransformMatrix;
    
                if (outlined) {
                    e.Graphics.DrawPath(Pens.LawnGreen, path);
                }
                else {
                    e.Graphics.FillPath(Brushes.Orange, path);
                }
            }
        }
    }
    
    private void btnFlipX_Click(object sender, EventArgs e)
    {
        flipX = !flipX;
        panel1.Invalidate();
    }
    
    private void btnFlipY_Click(object sender, EventArgs e)
    {
        flipY = !flipY;
        panel1.Invalidate();
    }
    
    private void chkOutlined_CheckedChanged(object sender, EventArgs e)
    {
        outlined = chkOutlined.Checked;
        panel1.Invalidate();
    }
    

    【讨论】:

    • 我正在使用复选框进行翻转,但是当我使用您的 sn-p 并修改控件时,文本会更改它的位置。
    • @TerribleDog 如上一条评论所述。尝试使用此处显示的代码自行实现。当您测试了它的工作原理后,将这些转换应用到您拥有的代码中。阅读注释和文档。这些矩阵变换是堆叠的。如果您没有以正确的顺序使用它们,它们可能会以不同的方式工作。此外,与往常一样,如果您的代码产生不同的结果,您需要更新您的问题并显示您实际使用的内容,否则一切都不清楚并且无法修复。
    • 更新问题
    • 我修正了错误 Jimi,因为我正在绘制图片框,所以我使用图片框的大小作为矩阵的 dX 和 dY。再次感谢@Jimi
    • 为了您的优势,我链接了有关矩阵的那些文档。你应该阅读它们。红色背景中的一段警告:注意复合转换的顺序很重要。一般来说,旋转,然后缩放,然后平移与缩放,然后旋转,然后平移是不同的。同样,矩阵乘法的顺序也很重要。一般来说,ABC 与 BAC 不同。 遵循那里的简单示例,知道序列是相关的。在之前的评论中:这些矩阵转换是堆叠的.......
    猜你喜欢
    • 2019-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多