package brotli
Install
Dune Dependency
Authors
Maintainers
Sources
sha256=045ace6a222d4e2d4f58f33cf40c1d2f19f04ffef458de11e1837ff7b73fefb2
md5=1df2ce2a0171f8e85abf0fdbfe91988d
README.md.html
README.md
These are ReasonML bindings to the compression algorithm/code released by Google called Brotli.
Dependencies
Make sure you have the brotli library installed. On OS X you can do brew install brotli
, as of 20/08/17, Brotli is on debian (Sid).
Installation
I assume that you have opam installed, it is OCaml's package manager.
$ opam install brotli
if wanting to install locally, then I recommend using an opam pin
, assuming you're in the root of the directory, do:
$ opam pin add brotli . -y
Compile with:
$ make build
Or play with it directly in utop
:
The API is very simple and limited to compressing, decompressing byte strings and files; type make docs
in the source repo and you get pretty HTML docs in the docs
repo, just open index.html
.
See the documentation online
API
This is directly the commented rei
, you can control compression settings.
/** ReasonML bindings to the Brotli compression library */;
/** Provides two functions for decompressing Brotli algorithm
compressed bytes, files; functions may raise Failure
exception. Note that on_part_decompressed and on_part_compressed
require OCaml to acquire and release the runtime lock
repeatedly. */
module Decompress: {
/** Decompress compressed byte string with optional callback */
let bytes: (~on_part_decompressed: Nativeint.t => unit=?, bytes) => bytes;
/** Brotli decoder version */
let version: string;
/** Decompress the input file to the output file */
let file:
(
~on_part_decompressed: Nativeint.t => unit=?,
~in_filename: string,
~out_filename: string,
unit
) =>
unit;
};
/** Provides functions for compression using the Brotli algorithm with
adjustable parameters, defaults are what Google uses. Be aware
that compression may raise Failure exception */
module Compress: {
/** Brotli encoder version */
let version: string;
type mode =
/** Compression is not aware of any special features of input */ | Generic
/** Compression knows that input is UTF-8 */ | Text
/** Compression knows that input is WOFF 2.0 */ | Font;
/** Controls the compression-speed vs compression-density
tradeoffs. The higher the quality, the slower the
compression. Range is `_0 to `_11. */
type quality = [ | `_0 | `_1 | `_2 | `_3 | `_4 | `_5 | `_6 | `_7 | `_8 | `_9 | `_10 | `_11];
/** Base 2 logarithm of the sliding window size. Range is `_10 to
`_24. */
type lgwin = [
| `_10
| `_11
| `_12
| `_13
| `_14
| `_15
| `_16
| `_17
| `_18
| `_19
| `_20
| `_21
| `_22
| `_23
| `_24
];
/** Base 2 logarithm of the maximum input block size. Range is `_16 to
`_24. If set to `_0, the value will be set based on the quality. */
type lgblock = [ | `_0 | `_16 | `_17 | `_18 | `_19 | `_20 | `_21 | `_22 | `_23 | `_24];
/** Compress the given bytes string to a compressed bytes string */
let bytes:
(
~mode: mode=?,
~quality: quality=?,
~lgwin: lgwin=?,
~lgblock: lgblock=?,
~on_part_compressed: Nativeint.t => unit=?,
bytes
) =>
bytes;
/** Compress in the input file to the output file name */
let file:
(
~mode: mode=?,
~quality: quality=?,
~lgwin: lgwin=?,
~lgblock: lgblock=?,
~on_part_compressed: Nativeint.t => unit=?,
~in_filename: string,
~out_filename: string,
unit
) =>
unit;
};
Here's an example usage:
let test_one = () => {
let raw_data = {|
<html>
<div>
Hello World World World World
</div>
</html>
|};
Printf.sprintf(
"Encoder version %s, Decoder version %s",
Brotli.Compress.version,
Brotli.Decompress.version
)
|> print_endline;
let compressed =
Brotli.Compress.bytes(
~on_part_compressed=
(piece) => Printf.sprintf("Compressed piece %d", Nativeint.to_int(piece)) |> print_endline,
raw_data
);
let compressed_len = Bytes.length(compressed);
Printf.sprintf("Compressed length %d", compressed_len) |> print_endline;
let decompressed =
Brotli.Decompress.bytes(
~on_part_decompressed=
(piece) => Printf.sprintf("Decompress piece %d", Nativeint.to_int(piece)) |> print_endline,
compressed
);
let decompressed_len = Bytes.length(decompressed);
Printf.sprintf("Decompressed length %d, data:%s", decompressed_len, decompressed)
|> print_endline;
if (String.compare(raw_data, decompressed) == 0) {
print_endline("Data was correct in roundtrip");
} else {
failwith("Data was not equal during roundtrip");
};
};
let read_file_content = (file_path) => {
let ic = open_in(file_path);
let stats = Unix.stat(file_path);
let buff = Buffer.create(1024);
Buffer.add_channel(buff, ic, stats.Unix.st_size);
close_in(ic);
Buffer.contents(buff);
};
let test_two = () => {
let cwd = Sys.getcwd();
let original_alice = Printf.sprintf("%s/example/alice29.txt", cwd);
let compressed_alice = Printf.sprintf("%s/example/alice.test.compressed", cwd);
let decompressed_alice = Printf.sprintf("%s/example/alice.test.decompressed", cwd);
Brotli.Compress.file(
~on_part_compressed=
(part) =>
Printf.sprintf("Compressed %d bytes of Alice file", Nativeint.to_int(part))
|> print_endline,
~in_filename=original_alice,
~out_filename=compressed_alice,
()
);
Brotli.Decompress.file(~in_filename=compressed_alice, ~out_filename=decompressed_alice, ());
/* Compare file content of decompressed and original alice */
let decompressed_content = read_file_content(decompressed_alice);
let original_content = read_file_content(original_alice);
Printf.sprintf(
"Compare test with baseline %b",
if (String.compare(decompressed_content, original_content) == 0) {
true;
} else {
false;
}
)
|> print_endline;
Unix.unlink(compressed_alice);
Unix.unlink(decompressed_alice);
};
let () = {
test_one();
test_two();
};