以编程方式将图像添加到RTF文档
我正在尝试将图像添加到正在创build的RTF文档中。 我宁愿不使用清除剪贴板的“复制/粘贴”方法(涉及在RichTextBox中粘贴图像,然后访问.RTF属性)(因为这对我的最终用户来说是一个麻烦和困惑)。
我到目前为止的代码返回需要被插入到RTF文档来打印图像的string。 input的图像(位于$path)通常是BMP或JPEG格式,但在这个阶段,我不关心如何将图像存储在RTF中,只有我可以得到它的工作。
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 }
但问题是,这段代码不工作,因为据我所知,stringstr没有正确的string转换在RTF内工作。
编辑:我的问题是在\“hex@”\“hex”后缺less一个空格,也不剥离从BitConverter的返回值的“ – ”字符
尝试这些链接
- 富文本格式(RTF)规范,版本1.6
- 我如何插入一个图像到RichTextBox?
- 将图像插入rtf文件
您必须将“picwgoa”更改为“picwgoal”和“pichgoa”更改为“pichgoal”
string mpic = @"{\pict\pngblip\picw" + img.Width.ToString() + @"\pich" + img.Height.ToString() + @"\picwgoal" + width.ToString() + @"\pichgoal" + height.ToString() + @"\bin " + str + "}";
这里有一个支持的图像格式列表
\ emfblip图片的来源是EMF(增强型图元文件)。 \ pngblip图片的来源是一个PNG。 \ jpegblip图片的来源是一个JPEG。 \ shppict指定一个Word 97-2000图片。 这是一个目标控制字。 \ nonshppict指定Word 97-2000已经写了一个{\ pict目标,它不会在input上读取。 此关键字是为了与其他读者兼容。 \ macpict图片的来源是QuickDraw。 \ pmmetafileN图片的来源是一个OS / 2图元文件。 N参数标识图元文件types。 N值在下面的\ pmmetafile表中描述。 \ wmetafileN图片的来源是Windows图元文件。 N参数标识元文件types(默认值为1)。 \ dibitmapN图片的来源是Windows设备无关的位图。 N参数标识位图types(必须等于0)。从Windows设备无关位图中包含在RTF中的信息是BITMAPINFO结构和实际像素数据的串联。 \ wbitmapN图片的来源是Windows设备相关的位图。 N参数标识位图types(必须等于0)。从Windows设备相关的位图中包含在RTF中的信息是GetBitmapBits函数的结果。
花了一天左右的search结果。 从各地的计算器和其他来源加起来的花絮。 喂这个图像,它会返回你需要添加到你的richtextbox.rtf扩展名的string。 图像宽度变化,需要计算,公式给出。
// 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; }
稍后访问此页面的用户(例如我前几天)可能会发现以下链接有用: 使用.NET将图像转换为WMF
人们会发现,写字板忽略任何图像没有存储在适当的Windows MetaFile格式。 因此,这个页面上的例子根本就不会显示出来(即使它在OpenOffice和Word本身也能正常工作)。 写字板将支持的格式是:
{/ pict / wmetafile8 / picw [width] / pich [height] / picwgoal [scaledwidth] / pichgoal [scaledheight] [image-as-string-of-byte-hex-values]}(用方括号中的项代替适当的数据)。
通过遵循上述链接中的程序来获取“适当的数据”。 对于那些用python寻找解决scheme,这里是一个开始(我相信一些dpi /缩放问题仍然存在)。 这需要PIL (或Pillow ), ctypes和clr(Python .NET) 。 使用PIL / Pillow并首先打开图像。 在这里,我把它打开为“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)
我发现大多数RTF框使用以下格式:
{\object\objemb{\*\objclass Paint.Picture}\objw2699\objh4799{\*\objdata [hex/bin]}}
当[hex/bin]
表示图像格式的hexstring数量很大时。 这种方式既适用于Word rtf,也适用于RTF框 – 所以效率更高。
在我的计算机图像尺寸为180×320像素已被转换为2699×4799缇,这意味着1pix = 15缇,据我所知,这是在3台电脑,我已经testing,他们之间的WinXP教授,WinXP家和赢7。