펄, 515 + -2922 + 0 + -2571 = -4978
다른 접근법. 이번에는 64xH 크기의 타일에 이미지를 저장하려고합니다. 사양에 따라 문제가 없지만 일부 소프트웨어는 첫 번째 타일이나 애니메이션 만 표시 할 수 있습니다. 더 나은 공간적 위치 때문에 타일이 더 잘 압축됩니다. 나는 여전히 두 번째 이미지에 대해서도 정상적인 압축을 수행하고 더 짧은 것을 선택합니다. 이렇게하면 이미지가 두 번 압축되므로 이전 솔루션보다 두 배 느립니다.
#!perl -n0
sub r{$r.=1&"@_">>$_ for 0..log(@d|256)/log 2}
@k=/(\d+) (\d+)/;
@l=map{$$_||=(push(@t,split$"),++$i)}/\d+ \d+ \d+/g;
print+GIF89a,pack(vvCxxC768,@k,~8,@t);
sub v{($w,$h)=@_;for$k(0.."@k"/$w-1){
$k*=$w;$r='';@d=();@p=grep+($z++-$k)%"@k"<$w,@l;
$"=' ';$_="@p ";$"='|';while(/./){
r 256;%d=map{($_,$_-1)}@d=1..256;
$d{$&}=@d+2,r$d{$1},unshift@d,$&while@d<4095&&s/^(@d) (\d*)/$2/}
r 257;$_=pack"b*",$r;
$h.=pack"Cv4n(C/a)*",44,$k,0,$w,$k[1],8,/.{0,255}/gs
}$b=$h if!$b||length$b>length$h}
"@k"%64||v 64;v"@k";print"$b;"
펄, 354 + 12 + 0 + -1 = 365418 9521 51168 56639
내 코드에 약간의 버그가 있거나 두 번째 이미지가 겉보기에 중요하지 않은 변경으로 인해 크기가 참조로 정확하게 줄어듦에 따라 특정 인코더에 최적화되었습니다. 이미지 당 약 30 ~ 60 초가 걸립니다.
골프 버전.
#!perl -n0
sub r{$r.=1&"@_">>$_ for 0..log(@d|256)/log 2}
@k=/(\d+) (\d+)/;
@p=map{$$_||=(push(@t,split$"),++$i)}/\d+ \d+ \d+/g;
$_="@p ";$"='|';while(/./){
r 256;%d=map{($_,$_-1)}@d=1..256;
$d{$&}=@d+2,r$d{$1},unshift@d,$&while@d<4095&&s/^(@d) (\d*)/$2/}
r 257;$_=pack"b*",$r;
print+GIF89a,pack(vvCxxC768,@k,~8,@t),
pack("Cx4vvn(C/a)*",44,@k,8,/.{0,255}/gs),';'
GIF 압축기가 취할 수있는 유일한 결정은 LZW 사전을 재설정 할 때입니다. 일반적으로이 작업에 대한 이미지가 선택된 방식으로 인해 가장 좋은 순간은 사전이 오버플로되는 순간 인 각 4096 코드입니다. 이러한 제한으로 인해 사전은 오버플로되지 않으므로 구현시 몇 바이트가 절약됩니다. 이것이 자세히 작동하는 방법입니다.
#!perl -n0
# function to add one codeword to the output stream @r.
# the current codeword length is based on the dictionary size/
sub r{push@r,map"@_">>$_,0..log(@d|256)/log 2}
# get the dimensions into @k
@k=/(\d+) (\d+)/;
# get pixel indexes to @p and palette to @t
@p=map{$$_||=(push(@t,split$"),++$i)}/\d+ \d+ \d+/g;
# convert index table into space separated string
$_="@p ";$"='|';
# LZW encoder; while something to encode
while(/\S/){
# output reset code
r 256;
# reset code dictionary $d is the last code number,
# %d is the map of codes and @d list of codes
$d=257;%d=map{($_,$_-1)}@d=1..256;
# find codes using regexp, stop at dictionary overflow
while($d<4096&&s/^(@d) (\d*)/$2/){
unshift@d,$&;$d{$&}=++$d;r$d{$1}}}
# end LZW encoder; output end code
r 257;
# convert bit string @r to bytes $f
vec($f,$j++,1)=$_ for@r;
# output header up to the color table
print+GIF89a,pack(vvCvC768,@k,~8,0,@t),
# output rest of the header
pack(Cv4CC,44,0,0,@k,0,8),
# output the LZW compressed data $f slicing into sub-blocks
$f=~s/.{0,255}/chr(length$&).$&/egsr,';'
펄, 394 + -8 + 0 + -12 = 374
리셋 포인트를 추측하기 위해 휴리스틱을 추가하면 압축이 약간 향상되지만 추가 코드를 정당화하기에는 충분하지 않습니다.
#!perl -n0
sub r{$r.=1&"@_">>$_ for 0..log(@d|256)/log 2}
@k=/(\d+) (\d+)/;
@p=map{$$_||=(push(@t,split$"),++$i)}/\d+ \d+ \d+/g;
$_="@p ";$"='|';while(/./){
r 256;%d=map{($_,$_-1)}@d=1..256;
$d{$&}=@d+2,r$d{$1},unshift@d,$&while
(@d<4001||(/((@d) ){11}/,$&=~y/ //>12))&@d<4095&&s/^(@d) (\d*)/$2/}
r 257;$_=pack"b*",$r;
print+GIF89a,pack(vvCxxC768,@k,~8,@t),
pack("Cx4vvn(C/a)*",44,@k,8,/.{0,255}/gs),';'