29

作成しているRTFドキュメントに画像を追加しようとしています。クリップボードを削除する「コピー/貼り付け」メソッド(RichTextBox内に画像を貼り付けてから.RTFプロパティにアクセスする方法)は使用しない方がよいでしょう(これはエンドユーザーにとって煩わしく混乱するためです)。

これまでのコードは、画像を印刷するためにRTFドキュメントに挿入する必要のある文字列を返します。入力された画像($ 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
}

ただし、問題は、このコードが機能しないことです。これは、私が知る限り、文字列strには、RTF内で機能する正しい文字列変換がないためです。

編集:私の問題は、@ "\hex"の\hexの後にスペースがなく、BitConverterの戻り値から「-」文字が削除されていないことでした。

4

5 に答える 5

33

これらのリンクを試してください

「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です。
\ shppictWord97-2000の画像を指定します。これは宛先制御ワードです。
\ nonshppictWord97-2000が入力時に読み取らない{\pict宛先を書き込んだことを指定します。このキーワードは、他のリーダーとの互換性のためです。
\macpict画像のソースはQuickDrawです。
\pmmetafileN画像のソースはOS/2メタファイルです。N引数は、メタファイルタイプを識別します。N値は、以下の\pmmetafileテーブルで説明されています。
\wmetafileN画像のソースはWindowsメタファイルです。N引数は、メタファイルタイプを識別します(デフォルトは1です)。
\ dibitmapN画像のソースは、Windowsデバイスに依存しないビットマップです。N引数は、ビットマップタイプを識別します(0に等しい必要があります)。Windowsデバイスに依存しないビットマップからRTFに含まれる情報は、BITMAPINFO構造体とそれに続く実際のピクセルデータの連結です。    
\ wbitmapN画像のソースは、Windowsデバイスに依存するビットマップです。N引数は、ビットマップタイプを識別します(0に等しい必要があります)。Windowsデバイスに依存するビットマップからRTFに含まれる情報は、GetBitmapBits関数の結果です。
于 2009-09-29T05:57:22.630 に答える
19

これに対する1日かそこらのグーグルの答えを過ごしました。スタックオーバーフローやその他のソース全体からのちょっとした情報をつなぎ合わせました。これに画像をフィードすると、richtextbox.rtf拡張子に追加する必要のある文字列が返されます。画像の幅が変化するため、計算する必要があります。式が示されています。

    // 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;
        }
于 2014-12-03T21:13:15.310 に答える
5

後でこのページにアクセスすると(数日前のように)、次のリンクが役立つ場合があります。.NETを使用して画像をWMFに変換する

ワードパッドは、適切なWindowsメタファイル形式で保存されていない画像を無視することがわかります。したがって、このページの前の例はまったく表示されません(OpenOfficeとWord自体では問題なく機能しますが)。ワードパッドがサポートする形式は次のとおりです。

{/ pict / wmetafile8 / picw [width] / pich [height] / picwgoal [scaledwidth] / pichgoal [scaledheight] [image-as-string-of-byte-hex-values]}(角括弧内の用語は適切なデータ)。

「適切なデータ」を取得するには、上記のリンクの手順に従います。解決策を探しているPythonを使用している場合は、ここから始めます(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)
于 2014-09-07T08:40:33.913 に答える
2

ほとんどのRTFボックスが次の形式を使用していることがわかりました。

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

[hex/bin]画像形式を表す16進文字列が大量にある場合。このように、Word rtfとRTFボックスの両方で機能するため、より効率的です。

180x320ピクセルのサイズの私のコンピューターイメージでは、2699x4799 twipsに変換されます。これは、私が見る限り、1pix = 15 twipsを意味します。これは、私がテストした3台のコンピューターで、WinXP教授、WinXPの間でこのようになっています。ホームと勝利7。

于 2013-08-02T02:28:59.343 に答える
2

RRUZとJiffyWhipからの回答をマージし、コードをクリーンアップしました。

これで、画像をPNGまたはWMFとして挿入できます。

また、WMFは不透明度をサポートしていないため、透明度を白色に置き換えました。

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;
}
于 2020-01-31T17:07:32.397 に答える