11

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

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

tools/bro.cc,看起来“入口”方法定义在encode.cdecode.cas BrotliCompress(),方法中BrotliDecompressBuffer()BrotliDecompressStream()所以我想一个DLL可以从C++类中编译出来。

4

3 回答 3

13

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

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

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

完成后,使用它就相当简单了(输入和输出可以是文件路径或标准 .NET 流):

        // 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 文件
于 2016-05-30T20:46:29.450 回答
5

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

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

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

一切就绪后,创建控制台项目,引用 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();
}

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

于 2016-05-25T21:47:52.007 回答
4

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

  1. github:https ://github.com/XieJJ99/brotli.net/ 。
  2. Nuget:https ://www.nuget.org/packages/Brotli.NET/ 。

要将流压缩为 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");
                }

            }
       }        
于 2016-10-24T09:47:16.677 回答