เขียนตัวเข้ารหัส GIF


9

ใช่ GIF แบบเก่าที่ดี ชอบความเก่งกาจ, เกลียดการจดสิทธิบัตรและล้าสมัยบางส่วนเนื่องจากข้อ จำกัด ของมัน (และสิทธิบัตร), GIF ประกอบด้วยที่แกนกลาง, จานสีและภาพดัชนีที่ถูกบีบอัดโดยใช้อัลกอริทึม LZW

งานของคุณคือการเขียนโปรแกรมที่อ่านภาพในรูปแบบASCII PPM (หมายเลขมายากล "P3") จากอินพุตมาตรฐานและเขียนภาพเดียวกัน (พิกเซลเหมือนกันโดยพิกเซล) ในรูปแบบ GIF ไปยังเอาต์พุตมาตรฐาน เอาต์พุตสามารถอยู่ในรูปแบบไบนารีหรือข้อความ ASCII ที่มีแต่ละไบต์แทนด้วยตัวเลขระหว่าง 0 ถึง 255 (รวม) โดยคั่นด้วยช่องว่าง

รับประกันภาพอินพุตไม่ให้มีสีต่างกันมากกว่า 256 สี

เกณฑ์การให้คะแนน:

โปรแกรมของคุณจะถูกทดสอบใน 3 ภาพตัวอย่างและคะแนนของคุณจะถูกคำนวณเป็น:
ขนาดโปรแกรม + ผลรวม (ขนาดผลงาน - ขนาดอ้างอิงสำหรับภาพตัวอย่างแต่ละภาพ)
คะแนนต่ำสุดชนะ

ที่ต้องการ:

  • โปรแกรมของคุณจะต้องทำงานกับรูปภาพประเภทต่างๆขนาดใกล้เคียงกันและไม่ จำกัด เฉพาะภาพตัวอย่าง ตัวอย่างเช่นคุณสามารถ จำกัด ขนาดให้เป็นทวีคูณของ 2 หรือสมมติว่าสีสูงสุด ppm คือ 255 แต่ก็ยังควรใช้งานได้กับภาพอินพุตที่หลากหลาย
  • เอาต์พุตต้องเป็นไฟล์ GIF ที่ถูกต้องที่สามารถโหลดได้ด้วยโปรแกรมที่เข้ากันได้ (หลังจากแปลงกลับเป็นไบนารี่หากใช้ตัวเลือกเอาต์พุต ASCII)
  • คุณไม่สามารถใช้ฟังก์ชั่นการประมวลผลภาพใด ๆ (ในตัวหรือบุคคลที่สาม) โปรแกรมของคุณจะต้องมีรหัสที่เกี่ยวข้องทั้งหมด
  • โปรแกรมของคุณต้องสามารถรันได้ใน Linux โดยใช้ซอฟต์แวร์ที่มีให้ฟรี
  • ซอร์สโค้ดต้องใช้อักขระ ASCII เท่านั้น

ภาพตัวอย่าง:

นี่คือภาพตัวอย่าง 3 ภาพที่จะใช้ในการทำคะแนน คุณสามารถดาวน์โหลดไฟล์ zip ด้วยไฟล์ ppm (ใช้ปุ่มดาวน์โหลดที่ด้านบนของหน้านั้น) หรือคุณสามารถแปลงไฟล์เหล่านี้จากภาพ png ด้านล่างโดยใช้ ImageMagick ด้วยคำสั่งต่อไปนี้:

convert file.png -compress none file.ppm

ฉันยังให้การตรวจสอบ MD5 ของไฟล์ ppm เพื่อการยืนยัน

1. อำพัน

amber.png

ขนาดอ้างอิง: 38055
MD5 การตรวจสอบ ppm: d1ad863cb556869332074717eb278080

2. สีน้ำเงิน

blueeyes.png

ขนาดอ้างอิง: 28638
MD5 checksum ของ ppm: e9ad410057a5f6c25a22a534259dcf3a

3. พริก

peppers.png

ขนาดอ้างอิง: 53586
MD5 checksum ของ ppm: 74112dbdbb8b7de5216f9e24c2e1a627


1
หมายเหตุผู้ดูแล: ความคิดเห็นนอกหัวข้อ / ล้าสมัยถูกลบออก โปรดดูเมตาสำหรับการอภิปรายเกี่ยวกับภาพตัวอย่างในคำถามนี้
Doorknob

ดูเหมือนว่าภาพที่สองจะได้รับการจัดการกับสิ่งนี้: websiteoptimization.com/speed/tweak/lossyที่จะอธิบายอัตราส่วนการบีบอัดที่ดีขึ้นและความไวต่อการปรับแต่งตัวเข้ารหัส LZW
nutki

1
“ ซอร์สโค้ดจะต้องใช้อักขระ ASCII เท่านั้น” - ดังนั้นกล่าวอีกนัยหนึ่งเราไม่ได้รับอนุญาตให้ทำสิ่งท้าทายใน APL
FUZxxl

@FUZxxl จริง แต่คุณสามารถใช้ J. คุณยังไม่ได้รับอนุญาตให้ใช้ Aheui หรือทำเทคนิคการแปลงฐานใน GolfScript / CJam
aditsu ออกเพราะ SE ไม่ทำงาน

คำตอบ:


4

Perl, 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;"

Perl, 354 + 12 + 0 + -1 = 365 418 9521 51168 56639

อาจมีข้อผิดพลาดบางอย่างในรหัสของฉันหรือภาพที่สองได้รับการปรับให้เหมาะกับตัวเข้ารหัสเฉพาะเนื่องจากการเปลี่ยนแปลงที่ไม่มีนัยสำคัญดูเหมือนจะลดขนาดของการอ้างอิงลงอย่างแน่นอน ใช้เวลาประมาณ 30s-60s ต่อภาพ

รุ่น Golfed

#!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,';'

Perl, 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),';'

ดีมาก! แม้ว่าจะใช้เวลามากกว่า 30 วินาทีต่อภาพในที่นี้ ฉันค่อนข้างประทับใจกับ -30 จากรุ่นก่อนหน้าฉันสงสัยว่าคุณสามารถรวมวิธีการต่างๆและได้คะแนนต่ำกว่านี้ได้หรือไม่ นอกจากนี้คุณสามารถเขียนเล็กน้อยเกี่ยวกับสิ่งที่โปรแกรมทำ?
aditsu ออกจากเพราะ SE นั้นชั่วร้าย

ต้องการความกว้างที่จะเป็นทวีคูณของ 64 ดูเหมือนจะสุดขั้ว ...
aditsu ออกเพราะ SE นั้นชั่วร้าย

@aditsu, ไม่จำเป็น, ถ้าความกว้างไม่เท่ากับ 64, ไม่สามารถลองวิธีเรียงต่อกันและใช้การบีบอัดปกติ แน่นอนว่ามีค่าใช้จ่ายอีก ~ 100 ตัวอักษรฉันสามารถสร้างขนาดไทล์ตัวแปรสุดท้ายได้
nutki

ช้ามากและภาพที่เป็นภาพกระเบื้องแสดงเป็นภาพเคลื่อนไหว แต่ทำได้ดีมากมันน่าประทับใจมากที่คุณสามารถทำให้มันเล็กลงได้
aditsu ออกจากเพราะ SE นั้นชั่วร้าย

2

CJam, คะแนน 155 + 35306 + 44723 + 21518 = 101702

เพียงแค่ใช้การอ้างอิงที่เป็นใบ้ มันช้าไม่ได้ทำการบีบอัดจริง ๆ และมันก็ไม่ได้กอล์ฟ

"GIF89a":iS*SqN/S*S%1>:i3/:M0=2<256f{md\}S*:ZS247S0S0SM1>_|:PL*_,768\m0a*+S*S44S0S0S0S0SZS0S8SM1>Pf{\a#}254/256a*{512+2b1>W%}%:+8/{W%2b}%255/{_,S@S*S}/0S59
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.