2013-08-02 13 views
5

So che ci sono varie domande come questa ma la sto chiedendo perché non riuscivo a capire tutte le risposte date. Ho RichTextBox e voglio che l'utente sia in grado di inserire un'immagine nella posizione corrente del cursore.Inserisci immagine nella posizione del cursore nella casella Rich Text

Ho provato a utilizzare l'Clipboard per impostare l'immagine e incollarla nella casella di testo RTF. Funziona, ma mi è stato detto che è una cattiva pratica in quanto cambia i dati in un cliboard senza avvisare l'utente.

Questo è quello che ho cercato

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 c'è un modo migliore per fare questo?

+0

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

+0

@DmitryBychenko Quel collegamento è per 'vb.net' ... –

risposta

5

Ho preparato un esempio completamente funzionale per l'utente che utilizza la soluzione pubblicata here sfruttando la potenza RTF.

Come scrisse Hans Passant: la soluzione è piuttosto complicata e ci sono alcune valide alternative per raggiungerlo.

BTW, questo è il codice (riscritti):

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

Questo è il metodo 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(); 
    } 

Qui ci sono tutti i metodi necessari:

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 suggerire di avvolgere questo nel proprio UserControl.

+0

Complesso abbastanza Grazie. Ha funzionato.Comprenderò presto –

+0

Questa è stata quasi la mia risposta, ma le immagini sembrano perdere qualità attorno ai bordi quando le aggiungo in questo modo. Non sono sicuro di poter dire perché questo potrebbe accadere. Esempio http://imgur.com/6TCzKkv – Natzely

2

Il supporto di RichTextBox per OLE (Object Linking and Embedding) è un incidente storico. OLE è una tecnologia morta ed è stata pesantemente deprecata per molti anni. È sicuramente la fine di .NET che .NET non ha supportato. Rimuovere il supporto OLE dal controllo nativo di RichEdit sarebbe stato saggio ma avrebbe rotto troppe app antiche. La classe .NET RichTextBox è di per sé solo un piccolo wrapper per il componente nativo e non aggiunge o sottrae funzionalità da quel componente.

Di conseguenza, non esiste un modo semplice per utilizzare l'API OLE in .NET. Il fatto che copia/incolla negli appunti funzioni ancora è solo un caso, .NET non è coinvolto in tale operazione, quindi è altrimenti impotente a fermarlo.

Quindi sì, funziona ancora negli appunti ed è l'unico modo decente per utilizzare la funzione. Ci sono sicuramente alternative migliori, qualcosa come WebBrowser o Word interop ti offre molta più flessibilità. I wrapper PDF sono popolari. WPF supporta bene i documenti composti. Eccetera.

+0

Fondamentalmente, dovrebbe creare il proprio wrapper TextBox (o RichTextBox). – KappaG3

+0

Ok .. grazie per le informazioni –

+1

@ Precious1tj in realtà quello che vuoi può essere risolto ma è abbastanza complicato, ecco il link per la tua ricerca più http://www.codeproject.com/Articles/4544/Insert- Plain-Text-and-Images-into-RichTextBox-at-R –

0

Puoi provare a utilizzare il RichTextBox di WPF e ospitarlo nella finestra di WinForms. Potrai facilmente inserire un'immagine nella posizione del cursore con WPF.