2015年9月24日木曜日

Googleによる新しい圧縮アルゴリズム Brotliを試してみた.

Google、新しい圧縮アルゴリズム「Brotli」公開 (マイナビニュース)

google/brotli (GitHub)

GitHubでコードが公開されていたので,さっそく試してみました.

このコードは,Windows 10上のVisual Studio 2015 Communityで試しています.

  • main.cpp
  • dec (brotliのdecフォルダをコピー)
  • enc (brotliのencフォルダをコピー)

decとencをコピーした上で,プロジェクトに全てのファイルを組み込みます.
この際に,decとencには一部同名のファイルがあるため,オブジェクトファイルが被らないように,
出力フォルダを分けておきます.

後は,次のようなコードで圧縮と解凍ができます.


// main.cpp
#include <iostream>
#include <string>
#include <memory>
#include <cstdio>
#include <cstdlib>
#include <enc/streams.h>
#include <enc/encode.h>
#include <dec/streams.h>
#include <dec/decode.h>

int main(int argc, char * argv[])
{
    FILE * fout = fopen("main.cpp.brotli", "wb");
    if(!fout) { return -1; }

    FILE * fin = fopen("main.cpp", "rb");
    if(!fin) { return -1; }

    fseek(fin, 0, SEEK_END);
    auto size = ftell(fin);
    fseek(fin, 0, SEEK_SET);

    {
        brotli::BrotliFileOut bfout(fout);
        brotli::BrotliFileIn bfin(fin, size);

        // 圧縮時の設定ができる
        brotli::BrotliParams params;

        // true of falseが返る
        if(brotli::BrotliCompress(params, &bfin, &bfout))
        {
            std::cout << "圧縮に成功しました." << std::endl;
        }
        else
        {
            std::cerr << "圧縮に失敗しました." << std::endl;
            return -1;
        }
    }

    fclose(fout);
    fclose(fin);

    fin = fopen("main.cpp.brotli", "rb");
    fseek(fin, 0, SEEK_END);
    auto compressed_size = ftell(fin);
    fseek(fin, 0, SEEK_SET);
    std::string buffer;

    {
        std::unique_ptr<char[]> buffer(new char[size + 1]);
        buffer[size] = '\0';

        // メモリ出力用の構造体
        BrotliMemOutput output;

        // 解凍関数呼び出し
        auto result = BrotliDecompress(
            BrotliFileInput(fin),
            BrotliInitMemOutput(
                reinterpret_cast<uint8_t *>(buffer.get()),
                size,
                &output
            )
        );

        switch(result)
        {
        case BROTLI_RESULT_ERROR:
            std::cerr << "何らかのエラーが発生しました." << std::endl;
            return -1;
        case BROTLI_RESULT_NEEDS_MORE_INPUT:
            std::cerr << "解凍に必要な入力が不足しています." << std::endl;
            return -1;
        case BROTLI_RESULT_NEEDS_MORE_OUTPUT:
            std::cerr << "解凍先のバッファが不足しています." << std::endl;
            return -1;
        case BROTLI_RESULT_SUCCESS:
            std::cout << "解凍に成功しました." << std::endl;
            break;
        default:
            std::cerr << "未知のエラーが発生しました." << std::endl;
            return -1;
        }

        std::cout << buffer.get() << std::endl;
    }

    fclose(fin);

    return system("pause");
}

軽く触ってみた感じで,圧縮と解凍でAPIに対称性が無い感じがする(片方は名前空間に入っていて,もう片方は入っていない,だったり,入出力用のストリームの構造であったり)ので,
そのうちAPIは変更されるんじゃないかなぁ,という気がします.

結果はこんな感じです.
圧縮方法 結果サイズ (バイト)
無圧縮 2,487
brotli 728
zip 1,054

BrotliParamsに設定する値がデフォルトでは一番圧縮率が高くなる(その分処理が重い)になっているので,
その辺変更すると多少変わるかもしれませんが,デフォルトだと単なるzip圧縮よりも圧縮されていますね.

0 件のコメント:

コメントを投稿