web-dev-qa-db-fra.com

Ajout d'images programmatiques à RTF Document

J'essaie d'ajouter une image à un document RTF que je crée. Je préférerais ne pas utiliser les méthodes de copie/coller '(qui impliquent le colonant de l'image dans une richtextbox, puis accédant à la propriété .RTF) qui purge le presse-papiers (comme cela sera une prise et une 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 entrée (située à $ PATH) est généralement au format BMP ou JPEG, mais à ce stade, je ne suis pas concerné par la manière dont l'image est stockée dans le RTF uniquement 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 = @"{\pict\pngblip\picw" + 
        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 car aussi loin que je peux le dire, la chaîne STR ne dispose pas de la conversion correcte des chaînes pour travailler dans la RTF.

EDIT: Mon problème manquait un espace après la\hex in @ "\ hex" et ne pas déshabiller les caractères "-" de la valeur retournée du bitconverter

25
DerX

essayez ces liens

vous devez changer "picwgoa" à "Picwgoal" et "Pichgoa" à "Pichgoal"

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

Ici vous avez une liste des formats d'image pris en charge

[.____]\emfblip Source de l'image est un EMF (Métafile amélioré). [ La source de la photo est un jpeg. 
\Shppict Spécifie un mot 97-2000 image. Ceci est un mot de contrôle de destination. [.____]\Nonshppict Spécifie que Word 97-2000 a écrit une "destination\\ pict qu'il ne sera pas lu sur l'entrée. Ce mot clé est destiné à la compatibilité avec d'autres lecteurs. [.____]\MacPict Source de la photo est QuickDraw. [.____]\PMMetafilen Source de la photo est un système d'exploitation/2 Métafile. le N argument identifie le type de métafichier. Les n valeurs sont décrites dans la table\PMMetafile ci-dessous. [.____]\WmetFilen Source de la photo est un métafiché Windows. L'argument N identifie le type de métafichier (la valeur par défaut est 1). [ .____]\dibitmapn Source de la photo est un bitmap indépendant du périphérique Windows. L'argument N identifie le type bitmap (doit être égal à 0). Les informations à inclure dans RTF d'un w Un bitmap indépendant des indications est la concaténation de la structure bitmapInfo, suivie des données de pixel réelles. [.____]\wbitmapn Source de la photo est un bitmap dépendant de l'appareil Windows. L'argument n identifie le type bitmap (doit être égal à 0) .Les informations à inclure RTF à partir d'un bitmap bitmap dépendant de l'appareil Windows sont le résultat de la fonction GetBitmapbits. [.____]
31
RRUZ

Passé une journée ou donc des réponses de Googling pour cela. Reconstitué les tisseries de tout sur empilementflow et d'autres sources. Nourrissez cette image, il retournera la chaîne dont vous avez besoin pour ajouter à votre extension Richtextbox.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;
        }
14
JiffyWhip

Les visiteurs ultérieurs de cette page (comme j'étais il y a quelques jours) peuvent trouver le lien suivant utile: Convertir une image en WMF avec .NET ==

On trouvera que Wordpad ignore toute image non stockée dans le format métafile de Windows approprié. Ainsi, l'exemple précédent sur cette page ne s'affichera pas du tout (même s'il fonctionne très bien dans OpenOffice et le mot lui-même). Le format que WordPad prendra supportera:

{/ pict/wmetafile8/picw [largeur]/pich [hauteur]/picwgoal [Scaltedwidth]/Pichgoal [Scaltedheight] [image-as-string-of-byte-hex-valeurs]} (avec des termes de supports carrés remplacés par le données appropriées).

Obtenir les "données appropriées" peut être effectuée en suivant les procédures de la liaison ci-dessus. Pour ceux avec python à la recherche d'une solution, voici le début d'un (je pense que certains problèmes de DPI/échelle restent). Cela nécessite [~ # ~ # ~ # # ~] (ou oreiller), CTTYPES, et CLR (Python .NET). Utilisez Pil/Oreiller et ouvrez d'abord l'image. 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)
3
Darren Ringer

J'ai trouvé que la plupart des RTF cases utilisant le format suivant:

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

Lorsque [hex/bin] est une grande quantité de chaînes hexagonales représentant le format d'image. De cette façon, travaillez à la fois pour Word RTF, et à la fois pour RTF BOX - il est donc plus efficace.

Dans mon ordinateur, une taille de 180x320 pixels a été convertie en Twips de 2699x4799, ce qui signifie 1pix = 15 Twips, autant que je sache, c'est comme ça dans 3 ordinateurs que j'ai testés, entre eux WinXP Prof, WinXP la maison et gagner 7.

1
Xerix

J'ai fusionné des réponses de Rruz et Jiffywhip et j'ai nettoyé le code.

Maintenant, vous pouvez insérer une image comme PNG ou comme WMF.

J'ai également remplacé la transparence avec la couleur blanche, car WMF ne supporte pas l'opacité.

private static string GetWidthAndHeight(Image image, float dpiX, float dpiY)
{
    float width = (float)image.Width / dpiX;
    float height = (float)image.Height / dpiY;

    int picw = (int)(width * 2540);
    int pich = (int)(height * 2540);

    int picwgoal = (int)(width * 1440);
    int pichgoal = (int)(height * 1440);

    return "\\picw" + picw + "\\pich" + pich + "\\picwgoal" + picwgoal + "\\pichgoal" + pichgoal;
}

public static string InsertPngImage(Image image)
{
    byte[] buffer;

    using (var stream = new MemoryStream())
    {
        image.Save(stream, ImageFormat.Png);
        buffer = stream.ToArray();
    }

    string hex = BitConverter.ToString(buffer, 0).Replace("-", string.Empty);

    string widthAndHeight = GetWidthAndHeight(image, image.HorizontalResolution, image.VerticalResolution);

    return "{\\pict\\pngblip" + widthAndHeight + " " + hex + "}";
}

[Flags]
enum EmfToWmfBitsFlags
{
    EmfToWmfBitsFlagsDefault = 0x00000000,
    EmfToWmfBitsFlagsEmbedEmf = 0x00000001,
    EmfToWmfBitsFlagsIncludePlaceable = 0x00000002,
    EmfToWmfBitsFlagsNoXORClip = 0x00000004
}

private static int MM_ANISOTROPIC = 8;

[DllImportAttribute("gdiplus.dll")]
private static extern uint GdipEmfToWmfBits(IntPtr hEmf, uint bufferSize, byte[] buffer, int mappingMode, EmfToWmfBitsFlags flags);

public static string InsertWmfImage(Image image)
{
    image = ReplaceTransparency(image, Color.White);

    Metafile metaFile;
    float dpiX;
    float dpiY;

    using (Graphics graphics = Graphics.FromImage(image))
    {
        IntPtr hdc = graphics.GetHdc();
        metaFile = new Metafile(hdc, EmfType.EmfOnly);
        graphics.ReleaseHdc(hdc);
    }

    using (Graphics graphics = Graphics.FromImage(metaFile))
    {
        graphics.DrawImage(image, 0, 0, image.Width, image.Height);
        dpiX = graphics.DpiX;
        dpiY = graphics.DpiY;
    }

    IntPtr hEmf = metaFile.GetHenhmetafile();

    uint bufferSize = GdipEmfToWmfBits(hEmf, 0, null, MM_ANISOTROPIC, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);

    byte[] buffer = new byte[bufferSize];

    uint convertedSize = GdipEmfToWmfBits(hEmf, bufferSize, buffer, MM_ANISOTROPIC, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);

    string hex = BitConverter.ToString(buffer, 0).Replace("-", string.Empty);

    string widthAndHeight = GetWidthAndHeight(image, dpiX, dpiY);

    return "{\\pict\\wmetafile8" + widthAndHeight + " " + hex + "}";
}

private static Image ReplaceTransparency(Image image, Color background)
{
    Bitmap bitmap = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb);

    using (Graphics graphics = Graphics.FromImage(bitmap))
    {
        graphics.Clear(background);
        graphics.CompositingMode = CompositingMode.SourceOver;
        graphics.DrawImage(image, 0, 0, image.Width, image.Height);
    }

    return bitmap;
}
0
Jinjinov