Ajout programmatique D'Images au document RTF
j'essaie d'ajouter une image à un document RTF que je crée. Je préférerais ne pas utiliser les méthodes 'copier/coller' (qui impliquent de coller l'image dans une boîte de RichTextBox puis d'accéder à la .RTF propriété) qui purgent le bloc-notes (car ce sera un ennui et la confusion pour mes utilisateurs finaux).
le code que j'ai jusqu'à présent renvoie la chaîne qui doit être insérée dans le document RTF pour imprimer l'image. L'image saisie (située à $ path) est habituellement en bmp ou format jpeg, mais à ce stade Je ne suis pas concerné par la façon dont l'image est stockée dans le RTF que je peux le faire fonctionner.
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 = @"{pictpngblippicw" +
img.Width.ToString() + @"pich" + img.Height.ToString() +
@"picwgoa" + width.ToString() + @"pichgoa" + height.ToString() +
@"hex " + str + "}";
return mpic
}
cependant le problème est que ce code ne fonctionne pas parce que pour autant que je puisse dire, la string str ne possède pas la conversion correcte de la string pour fonctionner au sein de la RTF.
Edit: mon problème manquait un espace après le hex dans @ "hex " et aussi ne pas enlever les caractères "-" de la valeur retournée du BitConverter
4 réponses
essayez ces liens
- Spécification RTF (Rich Text Format), version 1.6
- Comment puis-je insérer une image dans une boîte RichTextBox?
- insérer L'Image dans le document rtf
vous devez changer "picwgoa" en "picwgoal" et "pichgoa" en "pichgoal "
string mpic = @"{\pict\pngblip\picw" +
img.Width.ToString() + @"\pich" + img.Height.ToString() +
@"\picwgoal" + width.ToString() + @"\pichgoal" + height.ToString() +
@"\bin " + str + "}";
ici vous avez un liste des formats d'image supportés
\emfblip Source of the picture is an EMF (enhanced metafile). \pngblip Source of the picture is a PNG. \jpegblip Source of the picture is a JPEG. \shppict Specifies a Word 97-2000 picture. This is a destination control word. \nonshppict Specifies that Word 97-2000 has written a {\pict destination that it will not read on input. This keyword is for compatibility with other readers. \macpict Source of the picture is QuickDraw. \pmmetafileN Source of the picture is an OS/2 metafile. The N argument identifies the metafile type. The N values are described in the \pmmetafile table below. \wmetafileN Source of the picture is a Windows metafile. The N argument identifies the metafile type (the default is 1). \dibitmapN Source of the picture is a Windows device-independent bitmap. The N argument identifies the bitmap type (must equal 0).The information to be included in RTF from a Windows device-independent bitmap is the concatenation of the BITMAPINFO structure followed by the actual pixel data. \wbitmapN Source of the picture is a Windows device-dependent bitmap. The N argument identifies the bitmap type (must equal 0).The information to be included in RTF from a Windows device-dependent bitmap is the result of the GetBitmapBits function.
a passé une journée à chercher des réponses sur Google. Assemblé des tidbits de tous les flux empilés et d'autres sources. Donnez à cette image une image, elle retournera la chaîne dont vous avez besoin pour ajouter à votre richtextbox.extension du format rtf. La largeur de l'image change et doit être calculée, la formule est donnée.
// 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;
}
les visiteurs ultérieurs de cette page (comme je l'étais il y a quelques jours) peuvent trouver le lien suivant utile: convertir une image en WMF avec .NET
on constatera que WordPad ignore toute image qui n'est pas stockée dans le format MetaFile Windows approprié. Ainsi, l'exemple précédent sur cette page n'apparaîtra pas du tout (même s'il fonctionne très bien dans OpenOffice et Word lui-même). Le format que WordPad prendra en charge est:
{/pict/wmetafile8/picw[largeur]/pich[hauteur]/picwgoal[scaledwidth]/pichgoal[scaledheight] [image-chaîne-de-octet hex-valeurs]} (avec des termes entre crochets remplacé par les données appropriées).
vous pouvez obtenir les "données appropriées" en suivant les procédures du lien ci-dessus. Pour ceux qui ont python à la recherche d'une solution, voici le début d'une solution (je crois que certains problèmes de mise à l'échelle dpi/restent). Cela nécessite PIL (ou oreiller ), ctypes , et clr (Python .NET) . Utilisez PIL / Pillow et ouvrez l'image en premier. Ici je l'ai ouvert comme "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)
j'ai trouvé que la plupart des boîtes RTF en utilisant le format suivant:
{\object\objemb{\*\objclass Paint.Picture}\objw2699\objh4799{\*\objdata [hex/bin]}}
quand [hex/bin]
est une grande quantité de chaînes hexadécimales représentant le format d'image. Cette façon de travailler à la fois pour Word rtf, et les deux pour la boîte RTF - donc il est plus efficace.
dans mon image d'ordinateur dans une taille de 180x320 pixels ont été convertis en 2699x4799 twips, ce qui signifie 1pix=15 twips, autant que je peux voir, il est comme ceci dans 3 ordinateurs que j'ai testé, entre eux WinXP prof, WinXP home et Win 7.