如何保存绘制的"Paint()"图形?使用C#进入图像? [英] How to save drew Graphics of "Paint()" into image using c#?

查看:152
本文介绍了如何保存绘制的"Paint()"图形?使用C#进入图像?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我实际上想将 RTF转换为图像,因此在进行了很多搜索之后,我有了一个可以通过Picturebox1的Paint()事件执行此操作的代码,它可以完美运行:

I actually wanted to Convert RTF into Image so after googling a lot I've got a code that does it by Paint() Event of Picturebox1 and it works perfectly :

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");
}

在左上方的图片中是我的richTextBox,而右侧是图片框.

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

the ISSUE is I don't know how to save Paint() drew graphic into a file because the 3 last lines of my code just save an empty image.

更新#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);

通过将图形从egraphics更改为g,可以解决此问题,但另一个问题是位图的质量太低.我已经添加了这些代码,但是结果还是一样,质量太低了! 有什么建议吗?

by changing the graphics from e.graphics to g the issue is resolved but with one other issue that the quality of bitmap is too low. I've Added this bunch of code but I've got same result, the quality is too low! Any suggestions?

更新#2

这是执行转换的Graphics_DrawRtfText类:

here is the Graphics_DrawRtfText class that does the conversion :

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
    }
}

推荐答案

免责声明:我没有时间去研究发布的扩展方法,但是它很有趣并且效果很好,至少在绘制到控制表面时是这样.

Disclaimer: I don't have the time to dig into the posted extension method but it is interesting and works well, at least when drawing onto a control surface.

但是我可以重现绘制成位图时的结果有多糟糕.

But I could reproduce how bad the results are when drawing into a bitmap..

但是:正确完成后,保存的结果非常好!

But: When done right the saved results are excellent!

因此,这里需要牢记以下几点:

So here here are a few things to keep in mind:

  • 保存Paint事件不是一个好主意,因为只要需要重画控件,系统都会触发该事件.通过执行最小化/最大化循环进行测试.

  • Saving in the Paint event is a bad idea, as this event will be triggered by the system whenever it needs to redraw the control; test by doing a minimize/maximize cycle.

此外,当绘制到位图时,DrawRtfText会创建双视效果.

In addition the DrawRtfText semms to create a double-vision effect when drawing into a bitmap.

因此,请确保使用DrawToBitmap来获取结果.为此,您需要在控件的Paint事件中放置对DrawRtfText的调用!

So make sure you use DrawToBitmap to grab the results. For this you need to place the call to DrawRtfText in the Paint event of a control!

还要确保在控件(像素大小)和位图(dpi)中都具有足够大的分辨率,以得到美观,清晰的图像(如果需要)和可打印的结果.

Also make sure to have large enough resolutions both in the control (pixel size) and the Bitmap (dpi) to get nice, crispy and (if needed) printable results.

请勿保存到jpg,因为这势必会导致文本模糊! Png是选择的格式!

Do not save to jpg as this is bound to result in blurry text! Png is the format of choice!

这是一个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);            

}

请注意,需要改进默认质量设置;如果不这样做,则放大后的结果文件中的文本会分开.

Note that it pays to improve on the default quality settings; if you don't the text in the resulting file will break apart when zooming in..

这里是一个保存按钮,单击:

Here is a Save button click:

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事件以获取绘制的图形.

Note that DrawToBitmap will internally trigger the Paint event to grab the drawn graphics.

当然,您不需要两个部分-仅使用所需的部分(例如,跳过第一部分,在firstnow之间),并使用自己的数字.它有助于知道输出将是什么,并从那里向后计算必要的尺寸和分辨率.

Of course you don't need both parts - use only the one you want (.e. skip the 1st part, between first and now ) and do use your own numbers. It helps to know what the output shall be and calculate the necessary sizes and resolutions backward from there.

我添加了放大版本,因为通常显示器的分辨率(所有控件的分辨率都非常有限)在75-100dpi左右,而打印质量仅在150dpi时开始.

I added the enlarged version because usually the monitor resolution, which is what the controls all have, is rather limited, around 75-100dpi, while print quality starts only at 150dpi..

这里是半功能

这篇关于如何保存绘制的"Paint()"图形?使用C#进入图像?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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