Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在富文本框中的光标位置插入图像_C#_Winforms_Image_Richtextbox - Fatal编程技术网

C# 在富文本框中的光标位置插入图像

C# 在富文本框中的光标位置插入图像,c#,winforms,image,richtextbox,C#,Winforms,Image,Richtextbox,我知道有很多这样的问题,但我问这些问题是因为我不明白所有的答案。我有RichTextBox,我希望用户能够在当前光标位置插入图像 我曾尝试使用剪贴板设置图像,然后将其粘贴到富文本框中。这是可行的,但有人告诉我它的坏习惯,因为它在没有通知用户的情况下更改剪贴板中的数据 这就是我尝试过的 private bool CheckIfImage(string filename) { if (filename.EndsWith(".jpeg")) { return true;

我知道有很多这样的问题,但我问这些问题是因为我不明白所有的答案。我有
RichTextBox
,我希望用户能够在当前光标位置插入图像

我曾尝试使用
剪贴板设置图像,然后将其粘贴到富文本框中。这是可行的,但有人告诉我它的坏习惯,因为它在没有通知用户的情况下更改剪贴板中的数据

这就是我尝试过的

    private bool CheckIfImage(string filename)
    {
        if (filename.EndsWith(".jpeg")) { return true; }
        else if (filename.EndsWith(".jpg")) { return true; }
        else if (filename.EndsWith(".png")) { return true; }
        else if (filename.EndsWith(".ico")) { return true; }
        else if (filename.EndsWith(".gif")) { return true; }
        else if (filename.EndsWith(".bmp")) { return true; }
        else if (filename.EndsWith(".emp")) { return true; }
        else if (filename.EndsWith(".wmf")) { return true; }
        else if (filename.EndsWith(".tiff")) { return true; }
        else { return false; }
    }

    private void openFileDialog2_FileOk(object sender, CancelEventArgs e)
    {
        if (CheckIfImage(openFileDialog2.FileName.ToLower()) == true)
        {
            Image img = Image.FromFile(openFileDialog2.FileName);
            string setData = (String)Clipboard.GetData(DataFormats.Rtf);

            Clipboard.SetImage(img);
            rtbType.Paste();

            Clipboard.SetData(DataFormats.Rtf, setData);
        }
        else
        {
            MessageBox.Show("Invalid Image File Selected");
        } 
    }

有没有更好的方法可以做到这一点?

RichTextBox对OLE(对象链接和嵌入)的支持是一个历史性的意外。OLE是一种过时的技术,多年来一直受到严重的抨击。它的死亡丧钟肯定是.NET完全不支持它的。从本机RichEdit控件中删除OLE支持是明智的,但它会破坏太多古老的应用程序。.NET RichTextBox类本身只是本机组件的一个小包装器,不会从该组件中添加或删除功能

因此,在.NET中使用OLE api没有任何简单的方法。通过剪贴板进行复制/粘贴仍然有效,这只是一个意外,.NET与该操作无关,因此无法停止该操作


因此,是的,它仍然可以通过剪贴板工作,是使用该功能的唯一体面方式。当然还有更好的选择,像WebBrowser或Word interop这样的东西给了您更大的灵活性。PDF包装器很流行。WPF很好地支持复合文档。等等。

您可以尝试使用WPF RichTextBox并将其托管在WinForms窗口中。使用WPF,您将能够非常轻松地在光标位置插入图像。

我已经为您准备了一个使用RTF power发布的解决方案的完整功能示例

正如汉斯·帕桑(Hans Passant)所写:解决方案相当棘手,有一些有效的替代方案可以实现

顺便说一句,这是你的代码(重写):

这是
embedImage
方法:

    private void embedImage(Image img)
    {
        var rtf = new StringBuilder();

        // Append the RTF header
        rtf.Append(@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033");
        // Create the font table using the RichTextBox's current font and append
        // it to the RTF string
        rtf.Append(GetFontTable(this.Font));
        // Create the image control string and append it to the RTF string
        rtf.Append(GetImagePrefix(img));
        // Create the Windows Metafile and append its bytes in HEX format
        rtf.Append(getRtfImage(img));
        // Close the RTF image control string
        rtf.Append(@"}");
        richTextBox1.SelectedRtf = rtf.ToString();
    }
以下是所有必要的方法:

    private enum EmfToWmfBitsFlags
    {
        EmfToWmfBitsFlagsDefault = 0x00000000,
        EmfToWmfBitsFlagsEmbedEmf = 0x00000001,
        EmfToWmfBitsFlagsIncludePlaceable = 0x00000002,
        EmfToWmfBitsFlagsNoXORClip = 0x00000004
    };

    private struct RtfFontFamilyDef
    {
        public const string Unknown = @"\fnil";
        public const string Roman = @"\froman";
        public const string Swiss = @"\fswiss";
        public const string Modern = @"\fmodern";
        public const string Script = @"\fscript";
        public const string Decor = @"\fdecor";
        public const string Technical = @"\ftech";
        public const string BiDirect = @"\fbidi";
    }

    [DllImport("gdiplus.dll")]
    private static extern uint GdipEmfToWmfBits(IntPtr _hEmf,
      uint _bufferSize, byte[] _buffer,
      int _mappingMode, EmfToWmfBitsFlags _flags);


    private string GetFontTable(Font font)
    {
        var fontTable = new StringBuilder();
        // Append table control string
        fontTable.Append(@"{\fonttbl{\f0");
        fontTable.Append(@"\");
        var rtfFontFamily = new HybridDictionary();
        rtfFontFamily.Add(FontFamily.GenericMonospace.Name, RtfFontFamilyDef.Modern);
        rtfFontFamily.Add(FontFamily.GenericSansSerif, RtfFontFamilyDef.Swiss);
        rtfFontFamily.Add(FontFamily.GenericSerif, RtfFontFamilyDef.Roman);
        rtfFontFamily.Add("UNKNOWN", RtfFontFamilyDef.Unknown);

        // If the font's family corresponds to an RTF family, append the
        // RTF family name, else, append the RTF for unknown font family.
        fontTable.Append(rtfFontFamily.Contains(font.FontFamily.Name) ? rtfFontFamily[font.FontFamily.Name] : rtfFontFamily["UNKNOWN"]);
        // \fcharset specifies the character set of a font in the font table.
        // 0 is for ANSI.
        fontTable.Append(@"\fcharset0 ");
        // Append the name of the font
        fontTable.Append(font.Name);
        // Close control string
        fontTable.Append(@";}}");
        return fontTable.ToString();
    }

    private string GetImagePrefix(Image _image)
    {
        float xDpi, yDpi;
        var rtf = new StringBuilder();
        using (Graphics graphics = CreateGraphics())
        {
            xDpi = graphics.DpiX;
            yDpi = graphics.DpiY;
        }
        // Calculate the current width of the image in (0.01)mm
        var picw = (int)Math.Round((_image.Width / xDpi) * 2540);
        // Calculate the current height of the image in (0.01)mm
        var pich = (int)Math.Round((_image.Height / yDpi) * 2540);
        // Calculate the target width of the image in twips
        var picwgoal = (int)Math.Round((_image.Width / xDpi) * 1440);
        // Calculate the target height of the image in twips
        var pichgoal = (int)Math.Round((_image.Height / yDpi) * 1440);
        // Append values to RTF string
        rtf.Append(@"{\pict\wmetafile8");
        rtf.Append(@"\picw");
        rtf.Append(picw);
        rtf.Append(@"\pich");
        rtf.Append(pich);
        rtf.Append(@"\picwgoal");
        rtf.Append(picwgoal);
        rtf.Append(@"\pichgoal");
        rtf.Append(pichgoal);
        rtf.Append(" ");

        return rtf.ToString();
    }

    private string getRtfImage(Image image)
    {
        // Used to store the enhanced metafile
        MemoryStream stream = null;
        // Used to create the metafile and draw the image
        Graphics graphics = null;
        // The enhanced metafile
        Metafile metaFile = null;
        try
        {
            var rtf = new StringBuilder();
            stream = new MemoryStream();
            // Get a graphics context from the RichTextBox
            using (graphics = CreateGraphics())
            {
                // Get the device context from the graphics context
                IntPtr hdc = graphics.GetHdc();
                // Create a new Enhanced Metafile from the device context
                metaFile = new Metafile(stream, hdc);
                // Release the device context
                graphics.ReleaseHdc(hdc);
            }

            // Get a graphics context from the Enhanced Metafile
            using (graphics = Graphics.FromImage(metaFile))
            {
                // Draw the image on the Enhanced Metafile
                graphics.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height));
            }

            // Get the handle of the Enhanced Metafile
            IntPtr hEmf = metaFile.GetHenhmetafile();
            // A call to EmfToWmfBits with a null buffer return the size of the
            // buffer need to store the WMF bits.  Use this to get the buffer
            // size.
            uint bufferSize = GdipEmfToWmfBits(hEmf, 0, null, 8, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
            // Create an array to hold the bits
            var buffer = new byte[bufferSize];
            // A call to EmfToWmfBits with a valid buffer copies the bits into the
            // buffer an returns the number of bits in the WMF.  
            uint _convertedSize = GdipEmfToWmfBits(hEmf, bufferSize, buffer, 8, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
            // Append the bits to the RTF string
            foreach (byte t in buffer)
            {
                rtf.Append(String.Format("{0:X2}", t));
            }
            return rtf.ToString();
        }
        finally
        {
            if (graphics != null)
                graphics.Dispose();
            if (metaFile != null)
                metaFile.Dispose();
            if (stream != null)
                stream.Close();
        }
    }

我建议您将其包装到您自己的
UserControl

可能的副本:@DmitryBychenko该链接用于
vb.net
…因此,基本上,他应该创建自己的文本框(或RichTextBox)包装器。@Precious1tj实际上您想要的东西可以解决,但它相当复杂,这是供您进一步研究的链接这几乎是我的答案,但当我这样添加图像时,图像边缘的质量似乎有所下降。不知道你是否能说出为什么会发生这种情况。我发现,如果我使用bmp instread png,我可以获得更好的质量
    private enum EmfToWmfBitsFlags
    {
        EmfToWmfBitsFlagsDefault = 0x00000000,
        EmfToWmfBitsFlagsEmbedEmf = 0x00000001,
        EmfToWmfBitsFlagsIncludePlaceable = 0x00000002,
        EmfToWmfBitsFlagsNoXORClip = 0x00000004
    };

    private struct RtfFontFamilyDef
    {
        public const string Unknown = @"\fnil";
        public const string Roman = @"\froman";
        public const string Swiss = @"\fswiss";
        public const string Modern = @"\fmodern";
        public const string Script = @"\fscript";
        public const string Decor = @"\fdecor";
        public const string Technical = @"\ftech";
        public const string BiDirect = @"\fbidi";
    }

    [DllImport("gdiplus.dll")]
    private static extern uint GdipEmfToWmfBits(IntPtr _hEmf,
      uint _bufferSize, byte[] _buffer,
      int _mappingMode, EmfToWmfBitsFlags _flags);


    private string GetFontTable(Font font)
    {
        var fontTable = new StringBuilder();
        // Append table control string
        fontTable.Append(@"{\fonttbl{\f0");
        fontTable.Append(@"\");
        var rtfFontFamily = new HybridDictionary();
        rtfFontFamily.Add(FontFamily.GenericMonospace.Name, RtfFontFamilyDef.Modern);
        rtfFontFamily.Add(FontFamily.GenericSansSerif, RtfFontFamilyDef.Swiss);
        rtfFontFamily.Add(FontFamily.GenericSerif, RtfFontFamilyDef.Roman);
        rtfFontFamily.Add("UNKNOWN", RtfFontFamilyDef.Unknown);

        // If the font's family corresponds to an RTF family, append the
        // RTF family name, else, append the RTF for unknown font family.
        fontTable.Append(rtfFontFamily.Contains(font.FontFamily.Name) ? rtfFontFamily[font.FontFamily.Name] : rtfFontFamily["UNKNOWN"]);
        // \fcharset specifies the character set of a font in the font table.
        // 0 is for ANSI.
        fontTable.Append(@"\fcharset0 ");
        // Append the name of the font
        fontTable.Append(font.Name);
        // Close control string
        fontTable.Append(@";}}");
        return fontTable.ToString();
    }

    private string GetImagePrefix(Image _image)
    {
        float xDpi, yDpi;
        var rtf = new StringBuilder();
        using (Graphics graphics = CreateGraphics())
        {
            xDpi = graphics.DpiX;
            yDpi = graphics.DpiY;
        }
        // Calculate the current width of the image in (0.01)mm
        var picw = (int)Math.Round((_image.Width / xDpi) * 2540);
        // Calculate the current height of the image in (0.01)mm
        var pich = (int)Math.Round((_image.Height / yDpi) * 2540);
        // Calculate the target width of the image in twips
        var picwgoal = (int)Math.Round((_image.Width / xDpi) * 1440);
        // Calculate the target height of the image in twips
        var pichgoal = (int)Math.Round((_image.Height / yDpi) * 1440);
        // Append values to RTF string
        rtf.Append(@"{\pict\wmetafile8");
        rtf.Append(@"\picw");
        rtf.Append(picw);
        rtf.Append(@"\pich");
        rtf.Append(pich);
        rtf.Append(@"\picwgoal");
        rtf.Append(picwgoal);
        rtf.Append(@"\pichgoal");
        rtf.Append(pichgoal);
        rtf.Append(" ");

        return rtf.ToString();
    }

    private string getRtfImage(Image image)
    {
        // Used to store the enhanced metafile
        MemoryStream stream = null;
        // Used to create the metafile and draw the image
        Graphics graphics = null;
        // The enhanced metafile
        Metafile metaFile = null;
        try
        {
            var rtf = new StringBuilder();
            stream = new MemoryStream();
            // Get a graphics context from the RichTextBox
            using (graphics = CreateGraphics())
            {
                // Get the device context from the graphics context
                IntPtr hdc = graphics.GetHdc();
                // Create a new Enhanced Metafile from the device context
                metaFile = new Metafile(stream, hdc);
                // Release the device context
                graphics.ReleaseHdc(hdc);
            }

            // Get a graphics context from the Enhanced Metafile
            using (graphics = Graphics.FromImage(metaFile))
            {
                // Draw the image on the Enhanced Metafile
                graphics.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height));
            }

            // Get the handle of the Enhanced Metafile
            IntPtr hEmf = metaFile.GetHenhmetafile();
            // A call to EmfToWmfBits with a null buffer return the size of the
            // buffer need to store the WMF bits.  Use this to get the buffer
            // size.
            uint bufferSize = GdipEmfToWmfBits(hEmf, 0, null, 8, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
            // Create an array to hold the bits
            var buffer = new byte[bufferSize];
            // A call to EmfToWmfBits with a valid buffer copies the bits into the
            // buffer an returns the number of bits in the WMF.  
            uint _convertedSize = GdipEmfToWmfBits(hEmf, bufferSize, buffer, 8, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
            // Append the bits to the RTF string
            foreach (byte t in buffer)
            {
                rtf.Append(String.Format("{0:X2}", t));
            }
            return rtf.ToString();
        }
        finally
        {
            if (graphics != null)
                graphics.Dispose();
            if (metaFile != null)
                metaFile.Dispose();
            if (stream != null)
                stream.Close();
        }
    }