将Brotli编译成DLL .NET可以参考

时间:2016-01-29 01:42:32

标签: c# python compression python.net brotli

所以我想利用Brotli,但我不熟悉Python和C ++ ..

我知道有人将其编译成Windows .exe。但是如何将其包装到DLL或.NET应用程序可以引用的内容中呢?我知道有IronPython,我是否只是将所有源文件引入IronPython项目并编写一个调用Brotli API并暴露它们的.NET适配器?但实际上,我甚至不确定Brotli API是Python还是C ++ ..

查看tools/bro.cc,它看起来像"条目"方法在encode.cdecode.c中定义为BrotliCompress()BrotliDecompressBuffer()BrotliDecompressStream()方法。所以我想可以从C ++类编译DLL。

3 个答案:

答案 0 :(得分:13)

为了避免使用Python,我在这里分发了原始的brotli源https://github.com/smourier/brotli并创建了一个可以与.NET一起使用的Windows DLL版本。 我添加了一个目录,其中包含一个带有两个项目的“WinBrotli”Visual Studio 2015解决方案:

  • WinBrotli :包含原始未更改的C / C ++ brotli代码的Windows DLL(x86和x64)。
  • Brotli :用C#编写的Windows控制台应用程序(任何Cpu),包含WinBrotli的P / Invoke互操作代码。

要重用Winbrotli DLL,只需复制WinBrotli.x64.dll和WinBrotli.x86.dll(您可以在 WinBrotli / binaries 文件夹中找到已构建的发行版本),除了.NET应用程序之外,并在您的C#项目中加入 BrotliCompression.cs 文件(如果C#不是您最喜欢的语言,则将其移植到VB或其他语言)。互操作代码将自动选择与当前进程的位数(X86或X64)相对应的正确DLL。

完成后,使用它非常简单(输入和输出可以是文件路径或标准.NET Streams):

        // compress
        BrotliCompression.Compress(input, output);

        // decompress
        BrotliCompression.Decompress(input, output);

要创建WinBrotli,这就是我所做的(对于其他想要使用其他Visual Studio版本的人)

  • 创建了一个标准的DLL项目,删除了预编译的头文件
  • 包含所有编码器和解码器原始brotli C / C ++文件(从未更改任何内容,因此我们可以在需要时更新原始文件)
  • 配置项目以删除对MSVCRT的依赖(因此我们不需要部署其他DLL)
  • 禁用4146警告(否则我们无法编译)
  • 添加了一个非常标准的dllmain.cpp文件,该文件没有什么特别之处
  • 添加了一个WinBrotli.cpp文件,该文件将brotli压缩和解压缩代码暴露给外部Windows世界(具有非常薄的适配层,因此在.NET中交互更容易)
  • 添加了导出4个函数的WinBrotli.def文件

答案 1 :(得分:5)

我将通过从.NET代码调用python本机库来展示一种方法。你需要什么:

  1. 你需要安装python 2.7(希望很明显)
  2. 您需要从源代码编译brotli。希望这很容易。首先安装Microsoft Visual C++ compiler for Python 2.7。然后通过git clone https://github.com/google/brotli.git克隆brotli存储库并使用python setup.py build_ext进行编译。完成后,在build\lib.win32-2.7目录中,您会找到brotli.pyd个文件。这是python c ++模块 - 我们稍后会需要它。

  3. 您需要下载pythonnet二进制文件或从源代码编译它。我们在这里使用pythonnet的原因,而不是Iron Python,因为Iron Python不支持本机(C \ C ++)python模块,这就是我们在这里需要的。因此,要从源代码编译,请通过git clone https://github.com/pythonnet/pythonnet.git进行克隆,然后通过python setup.py build进行编译。结果你会得到Python.Runtime.dll(在build\lib.win32-2.7目录中),这就是我们需要的。

  4. 当你拥有所有这些时,创建控制台项目,引用Python.Runtime.dll然后:

    public static void Main()
    {            
        PythonEngine.Initialize();            
        var gs = PythonEngine.AcquireLock();
        try {                
            // import brotli module
            dynamic brotli = PythonEngine.ImportModule(@"brotli");
            // this is a string we will compress
            string original = "XXXXXXXXXXYYYYYYYYYY";
            // compress and interpret as byte array. This array you can save to file for example
            var compressed = (byte[]) brotli.compress(original);                
            // little trick to pass byte array as python string
            dynamic base64Encoded = new PyString(Convert.ToBase64String(compressed));
            // decompress and interpret as string
            var decompressed = (string) brotli.decompress(base64Encoded.decode("base64"));
            // works
            Debug.Assert(decompressed == original);
        }
        finally {
            PythonEngine.ReleaseLock(gs);
            PythonEngine.Shutdown();
        }            
        Console.ReadKey();
    }
    

    然后构建它并将 put brotli.pyc 与您的.exe文件放在同一目录中。完成所有这些操作之后,您将能够从.NET代码进行压缩和解压缩,如上所示。

答案 2 :(得分:4)

您可以使用提供全流支持的Brotli.NET。

  1. github:https://github.com/XieJJ99/brotli.net/
  2. Nuget:https://www.nuget.org/packages/Brotli.NET/
  3. 将流压缩为brotli数据:

       public Byte[] Encode(Byte[] input)
       {
           Byte[] output = null;
           using (System.IO.MemoryStream msInput = new System.IO.MemoryStream(input))
           using (System.IO.MemoryStream msOutput = new System.IO.MemoryStream())
           using (BrotliStream bs = new BrotliStream(msOutput, System.IO.Compression.CompressionMode.Compress))
           {
               bs.SetQuality(11);
               bs.SetWindow(22);
               msInput.CopyTo(bs);
               bs.Close();
               output = msOutput.ToArray();
               return output;
           }
       }
    

    解压缩brotli流:

       public Byte[] Decode(Byte[] input)
       {
           using (System.IO.MemoryStream msInput = new System.IO.MemoryStream(input))
           using (BrotliStream bs = new BrotliStream(msInput, System.IO.Compression.CompressionMode.Decompress))
           using (System.IO.MemoryStream msOutput = new System.IO.MemoryStream())
           {
               bs.CopyTo(msOutput);
               msOutput.Seek(0, System.IO.SeekOrigin.Begin);
               output = msOutput.ToArray();
               return output;
           }
    
       }
    

    要在Web应用程序中支持动态压缩,请在Global.asax.cs中添加如下代码:

        protected void Application_PostAcquireRequestState(object sender, EventArgs e)
        {
                           var app = Context.ApplicationInstance;
                String acceptEncodings = app.Request.Headers.Get("Accept-Encoding");
    
                if (!String.IsNullOrEmpty(acceptEncodings))
                {
                    System.IO.Stream baseStream = app.Response.Filter;
                    acceptEncodings = acceptEncodings.ToLower();
    
                    if (acceptEncodings.Contains("br") || acceptEncodings.Contains("brotli"))
                    {
                        app.Response.Filter = new Brotli.BrotliStream(baseStream, System.IO.Compression.CompressionMode.Compress);
                        app.Response.AppendHeader("Content-Encoding", "br");
                    }
                    else
                    if (acceptEncodings.Contains("deflate"))
                    {
                        app.Response.Filter = new System.IO.Compression.DeflateStream(baseStream, System.IO.Compression.CompressionMode.Compress);
                        app.Response.AppendHeader("Content-Encoding", "deflate");
                    }
                    else if (acceptEncodings.Contains("gzip"))
                    {
                        app.Response.Filter = new System.IO.Compression.GZipStream(baseStream, System.IO.Compression.CompressionMode.Compress);
                        app.Response.AppendHeader("Content-Encoding", "gzip");
                    }
    
                }
           }