#算术编码 #算术 #无损 # #编码 #解码器

arcode

算术编码器(无损熵编码器)

8 个版本

0.2.4 2022年6月21日
0.2.3 2021年1月2日
0.2.2 2020年12月8日
0.1.2 2019年4月15日

#173压缩 类别中

Download history 11/week @ 2024-03-13 27/week @ 2024-03-27 31/week @ 2024-04-03 13/week @ 2024-04-10 6/week @ 2024-04-17 43/week @ 2024-04-24 14/week @ 2024-05-01 8/week @ 2024-05-08 50/week @ 2024-05-15 22/week @ 2024-05-22 47/week @ 2024-05-29 116/week @ 2024-06-05 202/week @ 2024-06-12 230/week @ 2024-06-19 137/week @ 2024-06-26

每月下载量 723 次

MIT 许可证

740KB
756

Aricode

适用于 Rust 的算术编码器。

Crates.io Crates.io GitHub top language

关于

这个包提供了一个高效的算术编码/解码器实现。这个包基于描述算术编码的论文,可在此处找到。这个实现具有许多可读性和性能改进,尤其是在解码方面。

这个项目的目标不是提供一个即用型的压缩解决方案。算术编码(熵编码)是几乎所有现代压缩方案的核心。这个包旨在被包含在未来的项目中,这些项目依赖于高效的熵编码器,例如 PPMLZ77/LZ78h265/HEVC

核心组件

有许多结构可供使用,但对于普通用户来说,只有少数会被使用。

  • Model 模型符号的概率。计数可以在编码过程中进行调整,以提高压缩效果。
  • Encoder 根据源模型和符号进行编码。
  • Decoder 根据源模型和位流进行解码。

示例

在 git 仓库中有一个 old_complex.rs 文件,该文件根据每个字符进行上下文切换。更简单的示例可以在 new_simple.rs 中找到。

输入和输出位流

为了使算术编码工作,需要逐位读取流(用于解码和编码器的输出)。因此,需要BitBit。将输入包裹在缓冲区读取器/写入器中可以大大提高性能。

使用bitbit创建输入流。

use arcode::bitbit::{BitReader, MSB, BitWriter};
use std::io::Cursor;

fn read_example() {
  // normally you would have a Read type with a BufReader
  let mut source = Cursor::new(vec![0u8; 4]);
  let input: BitReader<_, MSB> = BitReader::new(&mut source);
}

fn out_example() {
  // once again would be Write type with a BufWriter
  let compressed = Cursor::new(vec![]);
  let mut compressed_writer = BitWriter::new(compressed);
}

源模型

根据您的应用,您可能有一个或多个源模型。编码器和解码器都依赖于源模型。如果解码器与编码器不同步,您将无法正确解码。

model::Builder

为了创建源模型,您需要使用model::Builder结构体。

use arcode::{EOFKind, Model};

fn source_model_example() {
  // create a new model that has symbols 0-256
  // 8 bit values + one EOF marker
  let mut model_with_eof = Model::builder()
    .num_symbols(256)
    .eof(EOFKind::EndAddOne)
    .build();
  
  // model for 8 bit 0 - 255, if we arent using
  // the EOF flag we can set it to NONE or let it default
  // to none as in the second example below.
  let model_without_eof = Model::builder()
    .num_symbols(256)
    .eof(EOFKind::None)
    .build();
  let model_without_eof = Model::builder().num_symbols(256).build();

  // we can also create a model for 0-255 using num_bits
  let model_8_bit = Model::builder().num_bits(8).build();
  
  // update the probability of symbol 4.
  model_with_eof.update_symbol(4);
}

编码

编码一些简单的输入

use arcode::bitbit::BitWriter;
use arcode::{ArithmeticEncoder, EOFKind, Model};
use std::io::{Cursor, Result};

/// Encodes bytes and returns the compressed form
fn encode(data: &[u8]) -> Result<Vec<u8>> {
  let mut model = Model::builder()
    .num_bits(8)
    .eof(EOFKind::EndAddOne)
    .build();

  // make a stream to collect the compressed data
  let compressed = Cursor::new(vec![]);
  let mut compressed_writer = BitWriter::new(compressed);
  
  let mut encoder = ArithmeticEncoder::new(48);

  for &sym in data {
    encoder.encode(sym as u32, &model, &mut compressed_writer)?;
    model.update_symbol(sym as u32);
  }

  encoder.encode(model.eof(), &model, &mut compressed_writer)?;
  encoder.finish_encode(&mut compressed_writer)?;
  compressed_writer.pad_to_byte()?;

  // retrieves the bytes from the writer. This will
  // be cleaner when bitbit updates. Not necessary if
  // using files or a stream
  Ok(compressed_writer.get_ref().get_ref().clone())
}

解码

use arcode::bitbit::{BitReader, MSB};
use arcode::{ArithmeticDecoder, EOFKind, Model};
use std::io::{Cursor, Result};

/// Decompresses the data
fn decode(data: &[u8]) -> Result<Vec<u8>> {
  let mut model = Model::builder()
    .num_bits(8)
    .eof(EOFKind::EndAddOne)
    .build();

  let mut input_reader = BitReader::<_, MSB>::new(data);
  let mut decoder = ArithmeticDecoder::new(48);
  let mut decompressed_data = vec![];

  while !decoder.finished() {
    let sym = decoder.decode(&model, &mut input_reader)?;
    model.update_symbol(sym);
    decompressed_data.push(sym as u8);
  }

  decompressed_data.pop(); // remove the EOF

  Ok(decompressed_data)
}

依赖项