4

wmfを次のようなビットマップに変換する例はたくさんあります。 信頼性の高い.wmf/wmfからピクセルベースの画像変換

しかし、逆の操作が必要です。私はベクトライザーを探していません。wmf形式のビットやバイトを気にすることなく、wmfファイル内に画像を埋め込みたいだけです。できればC#で.NETのソリューションが必要です。

私は最初にこれが仕事をするだろうと思いました:

using (Image img = Image.FromFile (path)) {
    img.Save (myStream, System.Drawing.Imaging.ImageFormat.Wmf);
}

しかし、これは実行時にエンコーダーがnullであると文句を言います。そのようなエンコーダをどこで/どのように構築できますか?複雑なものは必要ありません。画像をwmfにラップするだけです。WMFでサポートされているフォーマットにいくつかの要件はありますか?pngとbmpがサポートされていると思いますが、gifもサポートされていますか?

4

4 に答える 4

7

Here is the full answer to the question including my modifications. Vincent's answer is fully correct. Only some definitions and one enum were missing. That is why I post here the "clean" working code in the hope it can be useful for someone else.

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

        private static int MM_ISOTROPIC = 7;
        private static 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);

        private static MemoryStream MakeMetafileStream (Bitmap image)
        {
            Metafile metafile = null;
            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);
            }
            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);
            return stream;
        }
于 2011-03-15T08:42:29.117 に答える
6

jdehaan が投稿したものの改良版 (彼と Vincent に敬意を表します)

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

    private static int MM_ISOTROPIC = 7;
    private static 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 MemoryStream MakeMetafileStream(System.Drawing.Bitmap image)
    {
        Metafile metafile = null;
        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);
        }
        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);
        DeleteEnhMetaFile(_hEmf);

        var stream = new MemoryStream();
        stream.Write(_buffer, 0, (int)_bufferSize);
        stream.Seek(0, 0);

        return stream;
    }

これは一時ファイルを残さず、_bufferSize を一時ファイルにコピーしてから別のバッファにコピーすることも避けます。みんなありがとう。

于 2014-12-04T01:44:37.600 に答える
6

ここから:

Save メソッドを使用してグラフィック イメージを Windows メタファイル形式 (WMF) または拡張メタファイル形式 (EMF) ファイルとして保存すると、結果のファイルは代わりにポータブル ネットワーク グラフィックス (PNG) ファイルとして保存されます。この現象は、.NET Framework の GDI+ コンポーネントに、ファイルを .wmf または .emf ファイルとして保存するために使用できるエンコーダーがないために発生します。

しかし、私はあなたがすでにそこまで到達したと思います:)

ここでは、誰かがビットマップを FileStream に入れています。

metafileStream = MakeMetafileStream(gdiBitmap);

MakeMetafileStream() は次のとおりです。

private static MemoryStream MakeMetafileStream(Bitmap image)
{
  Graphics graphics = null;
  Metafile metafile= null;
  var stream = new MemoryStream();
  try
  {
    using (graphics = Graphics.FromImage(image))
    {
      var hdc = graphics.GetHdc();
      metafile= new Metafile(stream, hdc);
      graphics.ReleaseHdc(hdc);
    }
    using (graphics = Graphics.FromImage(metafile))
    { graphics.DrawImage(image, 0, 0); }
  }
  finally
  {
    if (graphics != null)
    { graphics.Dispose(); }
    if (metafile!= null)
    { metafile.Dispose(); }
  }
  return stream;
}

興味深いもの。しかし、エンコーダーのことに関しては...

ここで、MS の Peter Huang がこの管理されていないアプローチを投稿しました。

        [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);
        private void button4_Click(object sender, System.EventArgs e)
        {
            Graphics g= this.CreateGraphics();
            IntPtr hDC = g.GetHdc();
            Metafile mf = new Metafile(hDC,EmfType.EmfOnly);
            g.ReleaseHdc(hDC);
            g.Dispose();
            g=Graphics.FromImage(mf);
            //Pen p = new Pen(Color.White,5);
            g.DrawArc(Pens.Black,0,0,200,200,0,360);
            //g.DrawImage(Bitmap.FromFile(@"c:\temp\test.bmp"),0,0);
            g.Dispose();
            IntPtr _hEmf= mf.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);
            CopyMetaFile(hmf, "C:\\ConvertedMetafile.wmf");
            DeleteMetaFile(hmf);
            DeleteEnhMetaFile(_hEmf);
        }

これがあなたをそこに連れて行くことを願っています:)

于 2011-03-11T09:08:12.520 に答える