2013-08-02 17 views
5

Wiem, że są różne pytania, ale pytam, ponieważ nie mogłem zrozumieć wszystkich odpowiedzi. Mam RichTextBox i chcę, aby użytkownik mógł wstawić obraz w bieżącej pozycji kursora.Wstaw obraz w pozycji kursora w polu RTF

Próbowałem użyć Clipboard, aby ustawić obraz, a następnie wkleić go w polu tekstowym. To działa, ale powiedziano mi, że jest to zła praktyka, ponieważ zmienia dane w cliboard bez powiadamiania użytkownika.

To co próbowałem

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

Pls jest jakiś lepszy sposób to zrobić?

+0

możliwe dublicate: http://stackoverflow.com/questions/542850/how-can-i-insert-an-image-into-a-richtextbox –

+0

@DmitryBychenko Ten link jest dla 'vb.net' ... –

Odpowiedz

5

Mam przygotował przykład w pełni funkcjonalny dla ciebie używając roztworu pisał here wykorzystując moc RTF.

Hans Passant napisał: rozwiązanie jest dość skomplikowane i istnieje kilka ważnych alternatywy, aby go osiągnąć.

BTW, to jest twój kod (rewrited):

private bool CheckIfImage(string filename) 
{ 
     var valids = new[] {".jpeg", ".jpg", ".png", ".ico", ".gif", ".bmp", ".emp", ".wmf", ".tiff"}; 
     return valids.Contains(System.IO.Path.GetExtension(filename)); 
} 

private void openFileDialog2_FileOk(object sender, CancelEventArgs e) 
{ 
    if (CheckIfImage(openFileDialog2.FileName.ToLower()) == true) 
     embedImage(Image.FromFile(openFileDialog2.FileName)); 
    else 
     MessageBox.Show("Invalid Image File Selected"); 
} 

Jest to metoda 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(); 
    } 

Tutaj znajdują się wszystkie niezbędne metody:

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

I sugeruję, aby zawinąć to do własnego UserControl.

+0

Całkiem złożone Dzięki. Zadziałało.Wkrótce zrozumiem –

+0

To była prawie moja odpowiedź, ale zdjęcia wydają się tracić na jakości na krawędziach, gdy dodam je w ten sposób. Nie jestem pewien, czy mógłbyś powiedzieć, dlaczego tak się dzieje. Przykład http://imgur.com/6TCzKkv – Natzely

2

Obsługa RichTextBox dla OLE (linkowanie i osadzanie obiektów) jest historycznym wypadkiem. OLE to technologia martwa i od wielu lat jest mocno przestarzała. To z pewnością jest death-knell .NET całkowicie go nie wspiera. Usunięcie obsługi OLE z natywnego formantu RichEdit byłoby mądre, ale zepsułoby zbyt wiele starych aplikacji. Klasa .NET RichTextBox sama w sobie jest tylko małym opakowaniem komponentu natywnego i nie dodaje ani nie odejmuje funkcji tego komponentu.

W związku z tym nie ma żadnego prostego sposobu używania apletu OLE w .NET. Fakt, że kopiowanie/wklejanie w schowku wciąż działa, jest po prostu przypadkiem, .NET nie jest zaangażowany w tę operację, w przeciwnym razie jest bezsilny, aby go zatrzymać.

Tak, nadal działa przez schowek i jest to jedyny przyzwoity sposób korzystania z tej funkcji. Z pewnością istnieją lepsze alternatywy, takie jak WebBrowser lub Word Interop daje ci znacznie więcej elastyczności. Owijarki PDF są popularne. WPF dobrze obsługuje złożone dokumenty. Etcetera.

+0

Zasadniczo powinien on stworzyć własne opakowanie TextBox (lub RichTextBox). – KappaG3

+0

Ok .. dzięki za informacje –

+1

@ Precious1tj w rzeczywistości to, co chcesz, można rozwiązać, ale jest dość skomplikowane, tutaj jest link do badania więcej http://www.codeproject.com/Articles/4544/Insert- Zwykły tekst i obrazy do RichTextBox-at-R –

0

Możesz spróbować użyć RichTextBox WPF i umieścić go w oknie WinForm. Będziesz w stanie wstawić obraz w miejscu kursora z WPF bardzo łatwo.