2016-01-29 41 views
9

quindi mi piacerebbe sfruttare Brotli ma non ho familiarità con Python e C++ ..Compilare Brotli in una DLL .NET può fare riferimento

So che qualcuno aveva compilato in un exe di Windows. Ma come faccio a inserirlo in una DLL o qualcosa che può fare riferimento a un'app .NET. So che c'è IronPython, devo solo inserire tutti i file sorgente in un progetto IronPython e scrivere un adattatore .NET che chiama nell'API Brotli e li espone? Ma in realtà, io non sono nemmeno sicuro se l'API Brotli è Python o C++ ..

Guardando tools/bro.cc, sembra che la "voce di" metodi sono definiti in encode.c e decode.c come BrotliCompress(), BrotliDecompressBuffer(), BrotliDecompressStream() metodi. Quindi suppongo che una DLL possa essere compilata dalle classi C++.

+1

Non so se volevi chiedere altro fonti su Brotli. È disponibile su [GitHub] (https://github.com/google/brotli). – gt6707a

+0

Rimossa la riga "Questa non è un'azione per me" dalla tua risposta. Le domande-SO non sono solo per te. Spero non ti dispiaccia. – jgauffin

+1

@jgauffin che lo fa tramite python (ancora da codice .NET \ C#) va bene per te? – Evk

risposta

3

È possibile utilizzare Brotli.NET che fornisce il supporto completo del flusso.

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

per comprimere un flusso di dati 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; 
     } 
    } 

per decomprimere un flusso 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; 
     } 

    } 

Per sostenere impacco dinamica nelle applicazioni web, aggiungere il codice come questo nel 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

Nello spirito di .NET, penso che questa sia l'opzione migliore in questo momento. Detto questo, ** WinBrotli ** che è menzionato in un'altra risposta soddisfa anche. – gt6707a

+0

WinBrotli è OK quando l'input/output è piccolo. Tuttavia, richiede di comprimere/decomprimere i dati in memoria, il che significa che ha bisogno di molta più memoria e avrà una latenza più elevata. –

5

Mostrerò un modo per farlo chiamando la libreria nativa python dal codice .NET. Quello che vi serve:

  1. È necessario intall python 2.7 (speranza che è ovvio)
  2. È necessario compilare Brotli dai sorgenti. Speriamo sia facile. Prima installazione Microsoft Visual C++ compiler for Python 2.7. Quindi clonare il repository brotli tramite git clone https://github.com/google/brotli.git e compilare utilizzando python setup.py build_ext. Al termine, nella directory build\lib.win32-2.7 troverai il file brotli.pyd. Questo è il modulo python C++ - ne avremo bisogno in seguito.

  3. È necessario scaricare i file binari pythonnet o compilarli dal sorgente. Il motivo per cui usiamo pythonnet qui, e non per esempio Iron Python, è perché Iron Python non supporta i moduli python nativi (C \ C++), ed è quello che ci serve qui. Quindi, per compilare dal sorgente, clonare tramite git clone https://github.com/pythonnet/pythonnet.git quindi compilare tramite python setup.py build. Di conseguenza otterrai Python.Runtime.dll (nella directory build\lib.win32-2.7), che è ciò di cui abbiamo bisogno.

Quando si dispone di tutto ciò che in atto, creare progetto di console, di riferimento e quindi 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(); 
} 

poi costruire questo e put brotli.pyc si ottiene sopra nella stessa directory con il tuo file .exe. Dopo tutte quelle manipolazioni sarete in grado di comprimere e decomprimere dal codice .NET, come vedete sopra.

+0

'using (Py.GIL()) { } 'eliminerebbe 7 righe di codice! 'PythonEngine.Shutdown()' è ancora necessario alla fine. – denfromufa

+0

anche 'pip install git + https: // github.com/google/brotli' è molto più veloce! – denfromufa

+0

Non sapevamo che ci troviamo qui sulla concorrenza in code line :) – Evk

13

Per evitare la necessità di Python, ho biforato la fonte originale di brotli qui https://github.com/smourier/brotli e ho creato una versione di Windows DLL che è possibile utilizzare con .NET. Ho aggiunto una directory che contiene un Visual Studio 2015 soluzione con due progetti "WinBrotli":

  • WinBrotli: una DLL di Windows (x86 e x64) che contiene codice C++ originale invariata C/Brotli.
  • Brotli: un'applicazione Console di Windows (qualsiasi CPU) scritta in C# che contiene il codice di interoperabilità P/Invoke per WinBrotli.

Per riutilizzare la DLL Winbrotli, basta copiare (versioni di rilascio si possono trovare già costruiti negli WinBrotli/binari cartella) WinBrotli.x64.dll e WinBrotli.x86.dll da parte vostra applicazione .NET e incorporano il BrotliCompression.cs nel tuo progetto C# (o portalo in VB o in un'altra lingua se C# non è la tua lingua preferita). Il codice di interoperabilità selezionerà automaticamente la DLL corretta che corrisponde al processo corrente 'bitness (X86 o X64).

Una volta fatto questo, il suo utilizzo è abbastanza semplice (input e output possono essere percorsi di file o flussi standard .NET):

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

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

per creare WinBrotli, ecco quello che ho fatto (per altri che vorrebbe utilizzare altre versioni di Visual Studio)

  • creato un progetto DLL di serie, rimosse l'intestazione precompilata
  • Incluso tutti i file encoder e decoder Brötli originale C/C++ (mai cambiato nulla in là, così abbiamo puoi pdate i file originali quando necessario)
  • configurato il progetto per rimuovere le dipendenze su MSVCRT (quindi non abbiamo bisogno di implementare altre DLL)
  • disabili del 4146 avvertimento (altrimenti noi non possiamo compilare)
  • Aggiunto un file dllmain.cpp molto standard che non fa nulla di speciale
  • Aggiunto un file WinBrotli.cpp che espone il codice di compressione e decompressione brotli nel mondo Windows esterno (con un livello di adattamento molto sottile, quindi è più semplice interop in .NET)
  • Aggiunto un file WinBrotli.def che esporta 4 funzioni