2016-01-29 3 views
9

Так что я хотел бы воспользоваться Brotli, но я не знаком с Python и C++ ..Compile Brotli в DLL .NET может ссылаться

Я знаю, что кто-то был скомпилирован в EXE-файл Windows. Но как я могу обернуть его в DLL или что-то, что может использовать приложение .NET? Я знаю, что есть IronPython, просто я приведу все исходные файлы в проект IronPython и напишу .NET-адаптер, который вызывает API Brotli и раскрывает их? Но на самом деле, я даже не уверен, что если Brotli API является Python или C++ ..

Глядя на tools/bro.cc, это выглядит как «записи» методы определены в encode.c и decode.c, как BrotliCompress(), BrotliDecompressBuffer(), BrotliDecompressStream() методы. Поэтому я полагаю, что DLL может быть скомпилирована из классов C++.

+1

Не уверен, что вы хотели попросить больше повторно источники о Бротли. Он доступен на [GitHub] (https://github.com/google/brotli). – gt6707a

+0

Удалено из вашего ответа «Это не действие для меня больше». SO-вопросы предназначены не только для вас. Надеюсь, вы не против. – jgauffin

+1

@jgauffin, выполняющий это через python (все еще из .NET \ C# кода), подходит вам? – Evk

ответ

3

Вы можете использовать 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; 
     } 

    } 

Для поддержки динамического компресс в веб-приложениях, добавьте код, как это в 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"); 
       } 

      } 
     }   
+0

В духе .NET я считаю, что это лучший вариант в настоящее время. Тем не менее ** WinBrotli **, упомянутый в другом ответе, также удовлетворяет. – gt6707a

+0

WinBrotli в порядке, когда ввод/вывод мал. Тем не менее, он требует сжатия/распаковки данных в памяти, что означает, что ему требуется гораздо больше памяти и будет иметь более высокую задержку. –

5

Я покажу один способ сделать это, вызвав родную библиотеку python из .NET-кода. Что вам нужно:

  1. Вы должны intall Python 2.7 (надеюсь, что это очевидно)
  2. Вам нужно собрать brotli от источника. Надеюсь, это легко. Сначала установите Microsoft Visual C++ compiler for Python 2.7. Затем клонировать репозиторий 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 не поддерживает собственные (python) модули на языке C++, и это то, что нам нужно здесь. Итак, чтобы скомпилировать из источника, клонировать через git clone https://github.com/pythonnet/pythonnet.git, затем скомпилировать через 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-кода, как вы видите выше.

+0

'using (Py.GIL()) { } 'исключит 7 строк кода! 'PythonEngine.Shutdown()' по-прежнему необходимо в конце. – denfromufa

+0

также 'pip install git + https: // github.com/google/brotli' намного быстрее! – denfromufa

+0

Не знал, что мы находимся на соревновании по экономике с кодовой строкой :) – Evk

13

Чтобы избежать необходимости в Python, я раскошелил исходный источник brotli здесь https://github.com/smourier/brotli и создал версию DLL для Windows, которую вы можете использовать с .NET. Я добавил каталог, содержащий Visual Studio 2015 решение "WinBrotli" с двумя проектами:

  • WinBrotli: а Windows DLL (x86 и x64), который содержит оригинальный неизменный C/C++ brotli код.
  • Brotli: приложение Windows Console (любой процессор), написанное на C#, которое содержит код взаимодействия P/Invoke для WinBrotli.

Для повторного использования Winbrotli DLL, просто скопировать WinBrotli.x64.dll и WinBrotli.x86.dll (вы можете найти уже построенные версии релиз в WinBrotli/бинарников папку) в сторону приложения .NET, и включить BrotliCompression.cs файл в вашем проекте C# (или переносить его на VB или на другой язык, если C# не является вашим любимым языком). Код interop автоматически выберет правильную DLL, соответствующую текущей битовости процесса (X86 или X64).

После того, как вы сделали это, используя его довольно просто (вход и выход могут быть путями к файлам или стандартный .NET Streams):

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

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

Чтобы создать WinBrotli, вот что я сделал (для другие, которые хотели бы использовать другие версии Visual Studio)

  • создал стандартный проект DLL, удалили предкомпилированный заголовок
  • Включена все файлы Си кодер и декодер оригинального brotli/C++ (не изменились ничего там, так что мы можешь бновить исходные файлы при необходимости)
  • Настроенные проект, чтобы удалить зависимости от MSVCRT (так нам не нужно развернуть другой DLL)
  • Отключена 4146 предупреждение (в противном случае мы не можем компилировать)
  • Добавлено очень стандартный файл dllmain.cpp, который ничего не делает
  • Добавлен файл WinBrotli.cpp, который предоставляет код сжатия и декомпрессии Brotli для внешнего мира Windows (с очень тонким слоем адаптации, поэтому его проще взаимодействовать в .NET)
  • Добавлен файл WinBrotli.def, который экспортирует 4 функции
Смежные вопросы