brotli Komprimierung von Streams mit Free Pascal

Komprimierte Datenübertragung

Realisierung eines Interfaces zur brotli Library von Google, aktuelle Releases auch der Windows DLL's stehen unter https://github.com/google/brotli/releases zur Verfügung.

Sicherlich ist es nur eine minimale Realisierung ohne die Klassen mit all ihren Methoden, aber zum einfachen Gebrauch reicht es schon und vor allem zum Test und für einen Vergleich mit GZip.

Ich habe den BROTLI_DEFAULT_QUALITY Wert auf 5 gesetzt nicht auf 11 wie in vielen anderen Realisierungen, dadurch ergibt sich ein Vergleichbarer Wert mit GZip, je nach Dateigröße eine etwas bessere Komprimierung in einer angemessenen Zeit.
Setzt man diesen Wert auf 11, erhält man kein brauchbares Ergenis denn die benötigte Zeit ist zumindest für eine dynamische Komprimierung unbrauchbar.

brotli.pas Pascal (5,34 kByte) 24.06.2018 12:33
// *****************************************************************************
//  Title.............. :  brotli interface library
//
//  Modulname ......... :  brotli.pas
//  Type .............. :  Unit
//  Author ............ :  Udo Schmal
//  Development Status  :  24.06.2018
//  Operating Systen    :  Windows
//
//  Library Download    :  https://github.com/google/brotli/releases
// *****************************************************************************
unit Brotli;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils;

const
  BROTLI_DEFAULT_QUALITY = 5; // my default like gzip
  BROTLI_MIN_QUALITY = 0;
  BROTLI_MAX_QUALITY = 11;
  BROTLI_DEFAULT_MODE = 0;
  BROTLI_MODE_GENERIC = 0; // Default compression mode.
  BROTLI_MODE_TEXT = 1; // Compression mode for UTF-8 formatted text input.
  BROTLI_MODE_FONT = 2; // Compression mode used in WOFF 2.0
  BROTLI_DEFAULT_WINDOW = 22;
  BROTLI_MIN_WINDOW_BITS = 10;
  BROTLI_MAX_WINDOW_BITS = 24;
  BROTLI_DECODER_RESULT_ERROR = 0;
  BROTLI_DECODER_RESULT_SUCCESS = 1;
  BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT = 2;
  BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT = 3;

  function brotliEncodeStream(inStream, outStream: TMemoryStream; mode: LongInt = BROTLI_DEFAULT_MODE): boolean;
  function brotliDecodeStream(inStream, outStream: TMemoryStream): boolean;
  function BrotliCompress(const aFile: string): boolean;
  function BrotliUncompress(const aFile: string): boolean;

implementation

const
  BROTLIENC_DLL = 'libbrotlienc.dll';
  BROTLIDEC_DLL = 'libbrotlidec.dll';

var
  BrotliEncHandle: TLibHandle = 0;
  BrotliDecHandle: TLibHandle = 0;

  function BrotliEncoderCompress(quality: longint; lgwin: longint; mode: LongInt;
    input_size: LongWord; const input_buffer: pointer; var encoded_size: LongWord; encoded_buffer: pointer): boolean;
    stdcall; external BROTLIENC_DLL name 'BrotliEncoderCompress';
  function BrotliDecoderDecompress(encoded_size: LongWord; const encoded_buffer: pointer; var decoded_size: LongWord; decoded_buffer: pointer): LongInt;
    stdcall; external BROTLIDEC_DLL name 'BrotliDecoderDecompress';

function brotliEncodeStream(inStream, outStream: TMemoryStream; mode: LongInt = BROTLI_DEFAULT_MODE): boolean;
var outSize: LongWord;
begin
  result := false;
  outStream.SetSize(inStream.Size);
  outSize := outStream.Size;
  inStream.Position := 0; // goto start of input stream
  outStream.Position := 0; // goto start of output stream
  result := BrotliEncoderCompress(BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, mode, inStream.size, inStream.Memory, outSize, outStream.Memory);
  if result then
  begin
    inStream.Position := 0; // goto start of input stream
    outStream.Position := 0; // goto start of output stream
    outStream.Size := outSize;
  end;
end;

function brotliDecodeStream(inStream, outStream: TMemoryStream): boolean;
var
  outSize: LongWord;
  btResult: LongInt;
begin
  result := false;
  outStream.SetSize(inStream.Size*10);
  outSize := outStream.Size;
  inStream.Position := 0; // goto start of input stream
  outStream.Position := 0; // goto start of output stream
  btResult := BrotliDecoderDecompress(inStream.size, inStream.Memory, outSize, outStream.Memory);
//  case btResult of
//    BROTLI_DECODER_RESULT_ERROR: writeln('BROTLI_DECODER_RESULT_ERROR');
//    BROTLI_DECODER_RESULT_SUCCESS: writeln('BROTLI_DECODER_RESULT_SUCCESS');
//    BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: writeln('BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT');
//    BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: writeln('BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT');
//  end;
  result := btResult = BROTLI_DECODER_RESULT_SUCCESS;
  if result then
  begin
    inStream.Position := 0; // goto start of input stream
    outStream.Position := 0; // goto start of output stream
    outStream.Size := outSize;
  end;
end;

function BrotliCompress(const aFile: string): boolean;
var inStream, outStream: TMemoryStream;
begin
  result := false;
  if FileExists(aFile) then
  begin
    inStream := TMemoryStream.Create;
    try
      inStream.LoadFromFile(aFile);
      outStream := TMemoryStream.Create;
      try
        if brotliEncodeStream(inStream, outStream, BROTLI_MODE_TEXT) then
        begin
          outStream.SaveToFile(aFile + '.br');
          result := true;
        end;
      finally
        outStream.Free;
      end;
    finally
      inStream.Free;
    end;
  end;
end;

function BrotliUncompress(const aFile: string): boolean;
var inStream, outStream: TMemoryStream;
begin
  result := false;
  if FileExists(aFile) then
  begin
    inStream := TMemoryStream.Create;
    try
      inStream.LoadFromFile(aFile);
      outStream := TMemoryStream.Create;
      try
        if brotliDecodeStream(inStream, outStream) then
        begin
          outStream.SaveToFile(ChangeFileExt(aFile, ''));
          result := true;
        end;
      finally
        outStream.Free;
      end;
    finally
      inStream.Free;
    end;
  end;
end;

initialization
  BrotliEncHandle := LoadLibrary(PChar(BROTLIENC_DLL));
  BrotliDecHandle := LoadLibrary(PChar(BROTLIDEC_DLL));
finalization
  if BrotliEncHandle <> 0 then
  begin
    FreeLibrary(BrotliEncHandle);
    BrotliEncHandle := 0;
  end;
  if BrotliDecHandle <> 0 then
  begin
    FreeLibrary(BrotliDecHandle);
    BrotliDecHandle := 0;
  end;
end.

Beispiel:

brotliExample.lpr Pascal (578 Bytes) 24.06.2018 12:33
program brotli_example;

{$mode objfpc}{$H+}

uses
  Classes, SysUtils, brotli;

var
  StartTime, EndTime: QWord;
begin
  StartTime := GetTickCount64();
  BrotliCompress(ExtractFilePath(ParamStr(0)) + 'test.dat');
  EndTime := GetTickCount64();
  WriteLn('Brotli compress TickCount: ' + IntToStr(EndTime - StartTime) + ' ms');
  StartTime := GetTickCount64();
  BrotliUncompress(ExtractFilePath(ParamStr(0)) + 'test.dat.br');
  EndTime := GetTickCount64();
  WriteLn('Brotli uncompress TickCount: ' + IntToStr(EndTime - StartTime) + ' ms');
  ReadLn();
end.

Kontakt

Udo Schmal
Udo Schmal

Udo Schmal
Softwareentwickler
Ellerndiek 26
24837 Schleswig
Schleswig-Holstein
Germany




+49 4621 9785538
+49 1575 0663676
+49 4621 9785539
SMS
WhatsApp

Google Maps Profile
Instagram Profile
vCard 2.1, vCard 3.0, vCard 4.0

Service Infos

CMS Info

Product Name:
UDOs Webserver
Version:
0.5.1.68
Description:
All in one Webserver
Copyright:
Udo Schmal
Compilation:
Sat, 9. Mar 2024 07:54:53

Development Info

Compiler:
Free Pascal FPC 3.3.1
compiled for:
OS:Linux, CPU:x86_64

System Info

OS:
Ubuntu 22.04.4 LTS (Jammy Jellyfish)

Hardware Info

Model:
Hewlett-Packard HP Pavilion dm4 Notebook PC
CPU Name:
Intel(R) Core(TM) i5-2430M CPU @ 2.40GHz
CPU Type:
x86_64, 1 physical CPU(s), 2 Core(s), 4 logical CPU(s),  MHz