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

20
demandé sur Cœur 2009-09-29 09:38:09

4 réponses

essayez ces liens

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.
26
répondu RRUZ 2017-05-23 12:34:24

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;
        }
8
répondu JiffyWhip 2014-12-03 21:13:15

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)
1
répondu Darren Ringer 2017-05-23 12:02:17

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.

0
répondu Xerix 2013-08-02 02:59:35