2009-09-29 25 views
20

Estoy tratando de agregar una imagen a un documento RTF que estoy creando. Preferiría no usar métodos de "copiar/pegar" (que implican pegar la imagen dentro de un RichTextBox y luego acceder a la propiedad .RTF) que purga el portapapeles (ya que esto será una molestia y confusión para mis usuarios finales).Agregando imágenes programáticamente al documento RTF

El código que tengo hasta ahora devuelve la cadena que debe insertarse en el documento RTF para imprimir la imagen. La imagen ingresada (ubicada en $ path) suele estar en formato bmp o jpeg, pero en esta etapa no me preocupa cómo se almacena la imagen dentro del RTF, solo que puedo hacer que funcione.

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 
} 

Sin embargo, el problema es que este código no funciona porque por lo que yo puedo decir, la cadena str no tiene la conversión cadena correcta para trabajar dentro de la RTF.

Editar: Mi problema faltaba un espacio después del \ hexagonal en @ "\ hexagonal" y tampoco excluyendo los "-" caracteres del valor devuelto de la BitConverter

Respuesta

25

tratar estos enlaces

debe cambiar "picwgoa" a "picwgoal" y "pichgoa" a "pichgoal"

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

Aquí tienes una lista de los formatos de imagen compatibles

 
\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. 
+0

por encima de la cadena rtf (de la imagen) no se reconoce en Winform Rtf. ¿Alguien tiene idea de cómo proceder para Winform RTF? – JharPaat

0

He encontrado que la mayoría de las cajas RTF con el siguiente formato:

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

Cuando [hex/bin] es gran cantidad de cadenas hexadecimales que representan el formato de imagen. De esta forma, funciona tanto para Word rtf como para el cuadro RTF, por lo que es más eficiente.

En mi imagen de la computadora en un tamaño de 180x320 píxeles se han convertido a 2699x4799 twips, lo que significa 1pix = 15 twips, por lo que puedo ver, es así en 3 computadoras que he estado probando, entre ellos WinXP prof, hogar de WinXP y Win 7.

+0

Para aclarar, "un twip es * una vigésima parte de un punto *" ([fuente] (http://msdn.microsoft.com/en-us/library/aa140283%28office.10%29.aspx)). – 0b10011

+2

'Twips = Pixels/96 * 1440' es de donde proviene el factor 15, ya que una imagen suele tener 96 puntos por pulgada y un twip es 1/1440th inch. – Jens

1

Más tarde los visitantes a esta página (como lo estaba hace unos días) puede encontrar el siguiente enlace útil: Convert an image into WMF with .NET

Uno encontrará que WordPad ignora cualquier imagen que no está almacenado en el formato correcto de MetaFile de Windows. Por lo tanto, el ejemplo anterior en esta página no se mostrará en absoluto (a pesar de que funciona bien en OpenOffice y Word en sí). El formato compatible con WordPAD es:

{/ pict/wmetafile8/picw [width]/pich [height]/picwgoal [scale]/pichgoal [scaledheight] [image-as-string-of-byte-hex- values]} (con los términos entre corchetes reemplazados con los datos apropiados).

Obtener los 'datos apropiados' se puede hacer siguiendo los procedimientos en el enlace de arriba. Para aquellos con python que buscan una solución, aquí está el comienzo de una (creo que quedan algunos problemas de dpi/escalado).Esto requiere PIL (o Almohada), ctypes, y clr (Python .NET). Use PIL/Pillow y abra la imagen primero. Aquí lo tengo abierto como "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) 
8

Pasé un día o así googleando respuestas para esto. Pedazos recogidos de todo el stackoverflow y otras fuentes. Alimenta esta imagen, devolverá la cadena que necesitas agregar a tu extensión richtextbox.rtf. El ancho de la imagen cambia y debe calcularse, se da la fórmula.

// 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; 
     } 
Cuestiones relacionadas