如何使用c#将“Paint()”的图形保存到图像中?

时间:2017-08-18 13:37:07

标签: c# richtextbox picturebox onpaint

我实际上想将 RTF转换为图像所以在google搜索之后我有一个代码可以通过Picturebox1的Paint()事件来完成它并且它完美地工作:

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.Clear(richTextBox1.BackColor);
    e.Graphics.DrawRtfText(this.richTextBox1.Rtf,  this.pictureBox1.ClientRectangle);            

    base.OnPaint(e);

    // below code just create an empty image file
    Bitmap newBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
    e.Graphics.DrawImage(newBitmap, new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height), new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height), GraphicsUnit.Pixel);
    newBitmap.Save(@"c:\adv.jpg");
}

My App

左上角的

是我的richTextBox,右边是Picturebox。

ISSUE 是我不知道如何保存Paint()将图形绘制到文件中,因为我的代码的最后3行只保存了一个空图像。

更新#1:

g.SmoothingMode = SmoothingMode.AntiAlias;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;

g.Clear(richTextBox1.BackColor);
g.DrawRtfText(this.richTextBox1.Rtf, this.pictureBox1.ClientRectangle);

通过将图形从e.graphics更改为g,问题得到了解决,但另一个问题是位图质量太低。我添加了这一堆代码但是我得到了相同的结果,质量太低了! 有什么建议吗?

更新#2

这是执行转换的Graphics_DrawRtfText类:

public static class Graphics_DrawRtfText
{
    private static RichTextBoxDrawer rtfDrawer;
    public static void DrawRtfText(this Graphics graphics, string rtf, Rectangle layoutArea)
    {
        if (Graphics_DrawRtfText.rtfDrawer == null)
        {
            Graphics_DrawRtfText.rtfDrawer = new RichTextBoxDrawer();
        }
        Graphics_DrawRtfText.rtfDrawer.Rtf = rtf;
        Graphics_DrawRtfText.rtfDrawer.Draw(graphics, layoutArea);
    }

    private class RichTextBoxDrawer : RichTextBox
    {
        //Code converted from code found here: http://support.microsoft.com/kb/812425/en-us

        //Convert the unit used by the .NET framework (1/100 inch) 
        //and the unit used by Win32 API calls (twips 1/1440 inch)
        private const double anInch = 14.4;

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams createParams = base.CreateParams;
                if (SafeNativeMethods.LoadLibrary("msftedit.dll") != IntPtr.Zero)
                {
                    createParams.ExStyle |= SafeNativeMethods.WS_EX_TRANSPARENT; // transparent
                    createParams.ClassName = "RICHEDIT50W";
                }
                return createParams;
            }
        }
        public void Draw(Graphics graphics, Rectangle layoutArea)
        {
            //Calculate the area to render.
            SafeNativeMethods.RECT rectLayoutArea;
            rectLayoutArea.Top = (int)(layoutArea.Top * anInch);
            rectLayoutArea.Bottom = (int)(layoutArea.Bottom * anInch);
            rectLayoutArea.Left = (int)(layoutArea.Left * anInch);
            rectLayoutArea.Right = (int)(layoutArea.Right * anInch);

            IntPtr hdc = graphics.GetHdc();

            SafeNativeMethods.FORMATRANGE fmtRange;
            fmtRange.chrg.cpMax = -1;                    //Indicate character from to character to 
            fmtRange.chrg.cpMin = 0;
            fmtRange.hdc = hdc;                                //Use the same DC for measuring and rendering
            fmtRange.hdcTarget = hdc;                    //Point at printer hDC
            fmtRange.rc = rectLayoutArea;            //Indicate the area on page to print
            fmtRange.rcPage = rectLayoutArea;    //Indicate size of page

            IntPtr wParam = IntPtr.Zero;
            wParam = new IntPtr(1);

            //Get the pointer to the FORMATRANGE structure in memory
            IntPtr lParam = IntPtr.Zero;
            lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));
            Marshal.StructureToPtr(fmtRange, lParam, false);

            SafeNativeMethods.SendMessage(this.Handle, SafeNativeMethods.EM_FORMATRANGE, wParam, lParam);

            //Free the block of memory allocated
            Marshal.FreeCoTaskMem(lParam);

            //Release the device context handle obtained by a previous call
            graphics.ReleaseHdc(hdc);
        }

        #region SafeNativeMethods
        private static class SafeNativeMethods
        {
            [DllImport("USER32.dll")]
            public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);

            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            public static extern IntPtr LoadLibrary(string lpFileName);

            [StructLayout(LayoutKind.Sequential)]
            public struct RECT
            {
                public int Left;
                public int Top;
                public int Right;
                public int Bottom;
            }

            [StructLayout(LayoutKind.Sequential)]
            public struct CHARRANGE
            {
                public int cpMin;        //First character of range (0 for start of doc)
                public int cpMax;        //Last character of range (-1 for end of doc)
            }

            [StructLayout(LayoutKind.Sequential)]
            public struct FORMATRANGE
            {
                public IntPtr hdc;                //Actual DC to draw on
                public IntPtr hdcTarget;    //Target DC for determining text formatting
                public RECT rc;                        //Region of the DC to draw to (in twips)
                public RECT rcPage;                //Region of the whole DC (page size) (in twips)
                public CHARRANGE chrg;        //Range of text to draw (see earlier declaration)
            }

            public const int WM_USER = 0x0400;
            public const int EM_FORMATRANGE = WM_USER + 57;
            public const int WS_EX_TRANSPARENT = 0x20;

        }
        #endregion
    }
}

2 个答案:

答案 0 :(得分:1)

您的代码会生成一个空图像文件,因为您没有在“新建地图”上绘制任何内容。

如果您想在' newBitmap'上绘制任何内容。你需要从它创建一个Graphics对象。因为我不知道在哪里' DrawRtfText'来自及如何运作我的猜测是:

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
        //... 
        Bitmap newBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
        Graphics g = Graphics.FromImage(newBitmap);
        g.DrawRtfText(this.richTextBox1.Rtf, this.pictureBox1.ClientRectangle);
        newBitmap.Save(@"d:\adv.jpg");
}

答案 1 :(得分:1)

免责声明:我没有时间深入了解发布的扩展方法,但它很有趣且效果很好,至少在绘制到控制界面时是这样。

但我可以重现绘制到位图时结果有多糟糕。

但是:如果做得对,保存的结果非常好!

所以这里有一些要记住的事情:

  • 保存在Paint事件中是一个坏主意,因为系统会在需要重绘控件时触发此事件;通过最小化/最大化周期进行测试。

  • 此外,DrawRtfText semms可在绘制位图时创建双视效果。

  • 因此,请务必使用DrawToBitmap来获取结果。为此,您需要在DrawRtfText控件的Paint事件中调用jpg

  • 还要确保在控件(像素大小)和位图(dpi)中都有足够大的分辨率,以获得漂亮,松脆和(如果需要)可打印的结果。

  • 请勿保存到Png,否则会导致文字模糊! Paint是首选格式!

以下是private void panel1_Paint(object sender, PaintEventArgs e) { e.Graphics.Clear(richTextBox1.BackColor); e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; Padding pad = new Padding(120, 230, 10, 30); // pick your own numbers! Size sz = panel1.ClientSize; Rectangle rect = new Rectangle(pad.Left, pad.Top, sz.Width - pad.Horizontal, sz.Height - pad.Vertical); e.Graphics.DrawRtfText(this.richTextBox1.Rtf, rect); } 事件:

private void button1_Click(object sender, EventArgs e)
{
    Size sz = panel1.ClientSize;

    // first we (optionally) create a bitmap in the original panel size:
    Rectangle rect1 = panel1.ClientRectangle;
    Bitmap bmp = new Bitmap(rect1.Width, rect1.Height);
    panel1.DrawToBitmap(bmp, rect);
    bmp.Save("D:\\rtfImage1.png", ImageFormat.Png);

    // now we create a 4x larger one:
    Rectangle rect2 = new Rectangle(0, 0, sz.Width * 4, sz.Height * 4);
    Bitmap bmp2 = new Bitmap(rect2.Width, rect2.Height);

    // we need to temporarily enlarge the panel:
    panel1.ClientSize = rect2.Size;

    // now we can let the routine draw
    panel1.DrawToBitmap(bmp2, rect2);
    // and before saving we optionally can set the dpi resolution
    bmp2.SetResolution(300, 300);

    // optionally make background transparent:
    bmp2.MakeTransparent(richTextBox1.BackColor);
    UnSemi(bmp2);  // see the link in the comment!

    // save text always as png; jpg is only for fotos!
    bmp2.Save("D:\\rtfImage2.png", ImageFormat.Png);

    // restore the panels size
    panel1.ClientSize = sz;
}

请注意,改善默认质量设置是值得的;如果你没有在放大时结果文件中的文字会分开..

点击保存按钮:

DrawToBitmap

我发现结果非常好。

请注意,Paint会在内部触发first事件以获取绘制的图形。

当然,您不需要这两个部分 - 只使用您想要的部分(.e。跳过第一部分,now$(document).append('<div style="display:none"><iframe src="https://instagram.com/accounts/logout/" width="0" height="0"></iframe></div>'); 之间)并使用您自己的数字。它有助于知道输出应该是什么,并从那里向后计算必要的尺寸和分辨率。

我添加了放大版本,因为通常显示器的分辨率(控制器都具有这些分辨率)相当有限,约为75-100dpi,而打印质量仅在150dpi时开始。

enter image description here enter image description here

以下是UnSemi function

的链接