Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2314811
  • 博文数量: 527
  • 博客积分: 10343
  • 博客等级: 上将
  • 技术积分: 5565
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-26 23:05
文章分类

全部博文(527)

文章存档

2014年(4)

2012年(13)

2011年(19)

2010年(91)

2009年(136)

2008年(142)

2007年(80)

2006年(29)

2005年(13)

我的朋友

分类:

2006-08-31 22:31:03

RLE 可能是最简单的压缩算法, 但是应该却非常广泛, 尤其是作为打印机的语言, 它的解压不会给CPU带来任何额外的负担, 也不需要辅助的存储空间. 其基本思想是用数字描述重复的字节.
#0123456789
 AAAAAAAAAABCD
RLE存储上面这个串的做法是
10 个 A + 3个字节的 BCD. 因为BCD没有重复, 却需要一个额外的字节来描述它的长度, 所以此时反而浪费了空间.
一个典型的实现是这样的:
F7 41 02 42 43 44
其中 F7 是一个"负数", 如果某个字节大于127, 则它表示紧邻着它的字节需要重复, 重复的字节数是 256 - 0xF7 + 1 = 10, 这里把0xF7看作无符号数.
接下来的02, 因为小于等于127, 所以它表示接下来的 2 + 1 = 3个字节需要原封不动地COPY到解压串中.

C语言的典型实现无论是解压还是压缩都要大约20-30行左右.

下面是应急用PERL的实现:
sub rle_uncompress
{
  my $ref = shift;
  my $i = 0, $len = length($$ref);
  my $data = "";
  while ($i < $len)
  {
    my $b = substr($$ref, $i, 1);
    my $rep = ord($b) ;
    if ( $rep > 127 ) ##repeated data
    {
      $data .= ( substr($$ref, $i+1 , 1 ) x (256-$rep+1) );
      $i += 2;
    }
    else
    {
      $data .= substr($$ref, $i + 1, $rep + 1);
      $i += ($rep + 2); #data length= $rep + 1. repeat byte: 1
    }
  }
  $$ref = $data;
}

这个实现效率一般, 因为 $data .= 操作会引起大量的内存重新分配.

由于PERL支持扩展的正则表达式, 可以根据前面匹配的内容决定后面要使用的正则式, 还可以动态生成被替换的串.

下面是一个正则表达式搞定 RLE 解压, 当然, 它比较复杂, 看起来也不象只是一条语句. 但它的确是, 这样写是为了可读性.
==================================
my $L = 0;
my $data = "\xf7A\x02BCD";
#根据前面的RLE算法描述, 应该解压后得到 AAAAAAAAAABCD

  $data =~ s/
  (
    \G\C
  )
  ((??{$L=ord($1);($L<128)?'\C{0,'.($L+1).'}':'.';}))
  /
  {
  # print "\$L=$L, \$2=" . ord($2), "\n";
  ($L>127)
    ? $2 x (257-$L)
    : $2;
  }
  /gosex;

print "$data\n";
==================================
我只能说自己搞了半天的作品实在是酷, 写到最后也竟然发现自己给这个正则表达式指定的modifier 正好是go sex 连在一起.

对它的测试我采用了打印机生成的真实PRT文件, 也就是真正要送给打印机的那种字节流, 然后把它转换为一个TIFF文件.  Wow!

把转出来的图片也上传一下.

阅读(2188) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~