Aggiunta di immagini al documento RTF in modo programmatico

Sto cercando di aggiungere un’immagine a un documento RTF che sto creando. Preferirei non usare i metodi ‘copia / incolla’ (che implicano incollare l’immagine all’interno di un RichTextBox e quindi accedere alla proprietà .RTF) che eliminano gli appunti (poiché ciò costituirebbe un fastidio e una confusione per i miei utenti finali).

Il codice che ho finora restituisce la stringa che deve essere inserita nel documento RTF per stampare l’immagine. L’immagine immessa (che si trova in $ path) è in genere in formato bmp o jpeg, ma in questa fase non mi interessa come l’immagine viene archiviata nell’RTF solo per poterla far funzionare.

public string GetImage(string path, int width, int height) { MemoryStream stream = new MemoryStream(); string newPath = Path.Combine(Environment.CurrentDirectory, path); Image img = Image.FromFile(newPath); img.Save(stream, System.Drawing.Imaging.ImageFormat.Png); byte [] bytes = stream.ToArray(); string str = BitConverter.ToString(bytes, 0).Replace("-", string.Empty); //string str = System.Text.Encoding.UTF8.GetString(bytes); string mpic = @"{\pict\pngblip\picw" + img.Width.ToString() + @"\pich" + img.Height.ToString() + @"\picwgoa" + width.ToString() + @"\pichgoa" + height.ToString() + @"\hex " + str + "}"; return mpic } 

Tuttavia, il problema è che questo codice non funziona perché, per quanto posso dire, lo str string non ha la conversione di stringhe corretta per funzionare all’interno di RTF.

Modifica: il mio problema mancava uno spazio dopo \ hex in @ “\ hex” e inoltre non estrai i caratteri “-” dal valore restituito del BitConverter

prova questi link

  • Specifica RTF (Rich Text Format), versione 1.6
  • Come posso inserire un’immagine in un RichTextBox?
  • Inserisci immagine nel documento rtf

devi cambiare “picwgoa” in “picwgoal” e “pichgoa” in “pichgoal”

 string mpic = @"{\pict\pngblip\picw" + img.Width.ToString() + @"\pich" + img.Height.ToString() + @"\picwgoal" + width.ToString() + @"\pichgoal" + height.ToString() + @"\bin " + str + "}"; 

Qui hai una lista dei formati di immagine supportati

 \ emfblip La fonte dell'immagine è un EMF (metafile avanzato).
 \ pngblip La fonte dell'immagine è un PNG.
 \ jpegblip La fonte dell'immagine è un JPEG.
 \ shppict Specifica un'immagine di Word 97-2000.  Questa è una parola di controllo della destinazione.
 \ nonshppict Specifica che Word 97-2000 ha scritto una destinazione {\ pict che non leggerà in input.  Questa parola chiave è compatibile con altri lettori.
 \ macpict La fonte dell'immagine è QuickDraw.
 \ pmmetafileN La fonte dell'immagine è un metafile OS / 2.  L'argomento N identifica il tipo di metafile.  I valori N sono descritti nella tabella \ pmmetafile di seguito.
 \ wmetafileN La fonte dell'immagine è un metafile di Windows.  L'argomento N identifica il tipo di metafile (il valore predefinito è 1).
 \ dibitmapN La fonte dell'immagine è una bitmap indipendente dal dispositivo Windows.  L'argomento N identifica il tipo di bitmap (deve essere uguale a 0). Le informazioni da includere in RTF da una bitmap indipendente dalla periferica Windows sono la concatenazione della struttura BITMAPINFO seguita dai dati effettivi dei pixel.    
 \ wbitmapN La fonte dell'immagine è una bitmap dipendente dal dispositivo Windows.  L'argomento N identifica il tipo di bitmap (deve essere uguale a 0). Le informazioni da includere in RTF da una bitmap dipendente da dispositivo Windows sono il risultato della funzione GetBitmapBits.

Ho passato un giorno o così su Google risponde per questo. Unire insieme curiosità da tutto lo stackoverflow e da altre fonti. Feed questa immagine, restituirà la stringa che è necessario aggiungere all’estensione richtextbox.rtf. La larghezza dell’immagine cambia e deve essere calcasting, viene fornita la formula.

  // RTF Image Format // {\pict\wmetafile8\picw[A]\pich[B]\picwgoal[C]\pichgoal[D] // // A = (Image Width in Pixels / Graphics.DpiX) * 2540 // // B = (Image Height in Pixels / Graphics.DpiX) * 2540 // // C = (Image Width in Pixels / Graphics.DpiX) * 1440 // // D = (Image Height in Pixels / Graphics.DpiX) * 1440 [Flags] enum EmfToWmfBitsFlags { EmfToWmfBitsFlagsDefault = 0x00000000, EmfToWmfBitsFlagsEmbedEmf = 0x00000001, EmfToWmfBitsFlagsIncludePlaceable = 0x00000002, EmfToWmfBitsFlagsNoXORClip = 0x00000004 } const int MM_ISOTROPIC = 7; const int MM_ANISOTROPIC = 8; [DllImport("gdiplus.dll")] private static extern uint GdipEmfToWmfBits(IntPtr _hEmf, uint _bufferSize, byte[] _buffer, int _mappingMode, EmfToWmfBitsFlags _flags); [DllImport("gdi32.dll")] private static extern IntPtr SetMetaFileBitsEx(uint _bufferSize, byte[] _buffer); [DllImport("gdi32.dll")] private static extern IntPtr CopyMetaFile(IntPtr hWmf, string filename); [DllImport("gdi32.dll")] private static extern bool DeleteMetaFile(IntPtr hWmf); [DllImport("gdi32.dll")] private static extern bool DeleteEnhMetaFile(IntPtr hEmf); public static string GetEmbedImageString(Bitmap image) { Metafile metafile = null; float dpiX; float dpiY; using (Graphics g = Graphics.FromImage (image)) { IntPtr hDC = g.GetHdc (); metafile = new Metafile (hDC, EmfType.EmfOnly); g.ReleaseHdc (hDC); } using (Graphics g = Graphics.FromImage (metafile)) { g.DrawImage (image, 0, 0); dpiX = g.DpiX; dpiY = g.DpiY; } IntPtr _hEmf = metafile.GetHenhmetafile (); uint _bufferSize = GdipEmfToWmfBits (_hEmf, 0, null, MM_ANISOTROPIC, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); byte[] _buffer = new byte[_bufferSize]; GdipEmfToWmfBits (_hEmf, _bufferSize, _buffer, MM_ANISOTROPIC, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); IntPtr hmf = SetMetaFileBitsEx (_bufferSize, _buffer); string tempfile = Path.GetTempFileName (); CopyMetaFile (hmf, tempfile); DeleteMetaFile (hmf); DeleteEnhMetaFile (_hEmf); var stream = new MemoryStream (); byte[] data = File.ReadAllBytes (tempfile); //File.Delete (tempfile); int count = data.Length; stream.Write (data, 0, count); string proto = @"{\rtf1{\pict\wmetafile8\picw" + (int)( ( (float)image.Width / dpiX ) * 2540 ) + @"\pich" + (int)( ( (float)image.Height / dpiY ) * 2540 ) + @"\picwgoal" + (int)( ( (float)image.Width / dpiX ) * 1440 ) + @"\pichgoal" + (int)( ( (float)image.Height / dpiY ) * 1440 ) + " " + BitConverter.ToString(stream.ToArray()).Replace("-", "") + "}}"; return proto; } 

Più tardi i visitatori di questa pagina (come ero pochi giorni fa) potrebbero trovare utile il seguente link: Convertire un’immagine in WMF con .NET

Si scoprirà che WordPad ignora qualsiasi immagine non memorizzata nel formato Windows MetaFile appropriato. Quindi, l’esempio precedente in questa pagina non verrà mostrato (anche se funziona bene in OpenOffice e Word stesso). Il formato supportato da WordPad è:

{/ pict / wmetafile8 / picw [width] / pich [height] / picwgoal [scaledwidth] / pichgoal [scaledheight] [image-as-string-of-byte-hex-values]} (i termini tra parentesi quadre sostituiti con dati appropriati).

Ottenere i ‘dati appropriati’ può essere fatto seguendo le procedure nel link sopra. Per quelli con Python alla ricerca di una soluzione, ecco l’inizio di uno (credo che rimangano alcuni problemi di ridimensionamento / dpi). Ciò richiede PIL (o Pillow ), ctypes e clr (Python .NET) . Usa PIL / Pillow e apri prima l’immagine. Qui l’ho aperto come “canv”:

 from ctypes import * import clr clr.AddReference("System.IO") clr.AddReference("System.Drawing") from System import IntPtr from System.Drawing import SolidBrush from System.Drawing import Color from System.Drawing import Imaging from System.Drawing import Graphics from System.IO import FileStream from System.IO import FileMode from System.IO import MemoryStream from System.IO import File def byte_to_hex(bytefile): acc = '' b = bytefile.read(1) while b: acc+=("%02X" % ord(b)) b = bytefile.read(1) return acc.strip() #... in here is some code where 'canv' is created as the PIL image object, and #... 'template' is defined as a string with placeholders for picw, pich, #... picwgoal, pichgoal, and the image data mfstream = MemoryStream() offscrDC = Graphics.FromHwndInternal(IntPtr.Zero) imgptr = offscrDC.GetHdc() mfile = Imaging.Metafile(mfstream, imgptr, Imaging.EmfType.EmfOnly) gfx = Graphics.FromImage(mfile) width,height = canv.size pixels = canv.load() for x in range(width): for y in range(height): _r,_g,_b = pixels[x, y] c = Color.FromArgb(_r, _g, _b) brush = SolidBrush(c) gfx.FillRectangle(brush, x, y, 1, 1) gfx.Dispose() offscrDC.ReleaseHdc() _hEmf = mfile.GetHenhmetafile() GdipEmfToWmfBits = windll.gdiplus.GdipEmfToWmfBits _bufferSize = GdipEmfToWmfBits( int(str(_hEmf)), c_uint(0), None, c_int(8), # MM_ANISOTROPIC c_uint(0x00000000)) # Default flags _buffer = c_int * _bufferSize _buffer = _buffer(*[0 for x in range(_bufferSize)]) GdipEmfToWmfBits( int(str(_hEmf)), c_uint(_bufferSize), _buffer, c_int(8), # MM_ANISOTROPIC c_uint(0x00000000) ) # Default flags hmf = windll.gdi32.SetMetaFileBitsEx(c_uint(_bufferSize), _buffer) windll.gdi32.CopyMetaFileA(int(str(hmf)), "temp.wmf") windll.gdi32.DeleteMetaFile(int(str(hmf))) windll.gdi32.DeleteEnhMetaFile(int(str(_hEmf))) mfstream.Close() imgstr = open("temp.wmf", 'rb') imgstr = byte_to_hex(imgstr) with open('script-out.rtf','wb') as outf: template = template % (str(_cx),str(_cy),str(15*_cx),str(15*_cy),imgstr) outf.write(template) 

Ho trovato che la maggior parte delle caselle RTF utilizza il seguente formato:

 {\object\objemb{\*\objclass Paint.Picture}\objw2699\objh4799{\*\objdata [hex/bin]}} 

Quando [hex/bin] è una grande quantità di stringhe esadecimali che rappresentano il formato dell’immagine. In questo modo funziona sia per Word rtf, sia per RTF box, quindi è più efficiente.

Nell’immagine del mio computer in una dimensione di 180×320 pixel è stata convertita in twip 2699×4799, che significa 1 pixel = 15 twip, per quanto posso vedere, è come questo in 3 computer che ho testato, tra loro WinXP prof, WinXP casa e vinci 7.