带有PIL的Python,得分0.094218
压缩机:
#!/usr/bin/env python
from __future__ import division
import sys, traceback, os
from PIL import Image
from fractions import Fraction
import time, io
def image_bytes(img, scale):
w,h = [int(dim*scale) for dim in img.size]
bio = io.BytesIO()
img.resize((w,h), Image.LANCZOS).save(bio, format='PPM')
return len(bio.getvalue())
def compress(img):
w,h = img.size
w1,w2 = w // 256, w % 256
h1,h2 = h // 256, h % 256
n = w*h
total_size = 4*1024 - 8 #4 KiB minus 8 bytes for
# original and new sizes
#beginning guess for the optimal scaling
scale = Fraction(total_size, image_bytes(img, 1))
#now we do a binary search for the optimal dimensions,
# with the restriction that we maintain the scale factor
low,high = Fraction(0),Fraction(1)
best = None
start_time = time.time()
iter_count = 0
while iter_count < 100: #scientifically chosen, not arbitrary at all
#make sure we don't take longer than 5 minutes for the whole program
#10 seconds is more than reasonable for the loading/saving
if time.time() - start_time >= 5*60-10:
break
size = image_bytes(img, scale)
if size > total_size:
high = scale
elif size < total_size:
low = scale
if best is None or total_size-size < best[1]:
best = (scale, total_size-size)
else:
break
scale = (low+high)/2
iter_count += 1
w_new, h_new = [int(dim*best[0]) for dim in (w,h)]
wn1,wn2 = w_new // 256, w_new % 256
hn1, hn2 = h_new // 256, h_new % 256
i_new = img.resize((w_new, h_new), Image.LANCZOS)
bio = io.BytesIO()
i_new.save(bio, format='PPM')
return ''.join(map(chr, (w1,w2,h1,h2,wn1,wn2,hn1,hn2))) + bio.getvalue()
if __name__ == '__main__':
for f in sorted(os.listdir(sys.argv[1])):
try:
print("Compressing {}".format(f))
with Image.open(os.path.join(sys.argv[1],f)) as img:
with open(os.path.join(sys.argv[2], f), 'wb') as out:
out.write(compress(img.convert(mode='RGB')))
except:
print("Exception with {}".format(f))
traceback.print_exc()
continue
解压缩器:
#!/usr/bin/env python
from __future__ import division
import sys, traceback, os
from PIL import Image
from fractions import Fraction
import io
def process_rect(rect):
return rect
def decompress(compressed):
w1,w2,h1,h2,wn1,wn2,hn1,hn2 = map(ord, compressed[:8])
w,h = (w1*256+w2, h1*256+h2)
wc, hc = (wn1*256+wn2, hn1*256+hn2)
img_bytes = compressed[8:]
bio = io.BytesIO(img_bytes)
img = Image.open(bio)
return img.resize((w,h), Image.LANCZOS)
if __name__ == '__main__':
for f in sorted(os.listdir(sys.argv[1])):
try:
print("Decompressing {}".format(f))
with open(os.path.join(sys.argv[1],f), 'rb') as img:
decompress(img.read()).save(os.path.join(sys.argv[2],f))
except:
print("Exception with {}".format(f))
traceback.print_exc()
continue
这两个脚本都通过命令行参数将输入作为两个目录(输入和输出),并转换输入目录中的所有图像。
这个想法是要找到一个尺寸小于4 KiB且与原始尺寸相同的长宽比,并使用Lanczos滤波器从下采样的图像中获得尽可能高的质量。
调整为原始尺寸后的压缩图像的Imgur相册
计分脚本输出:
Comparing corpus/1 - starry.png to test/1 - starry.png... 0.159444
Comparing corpus/2 - source.png to test/2 - source.png... 0.103666
Comparing corpus/3 - room.png to test/3 - room.png... 0.065547
Comparing corpus/4 - rainbow.png to test/4 - rainbow.png... 0.001020
Comparing corpus/5 - margin.png to test/5 - margin.png... 0.282746
Comparing corpus/6 - llama.png to test/6 - llama.png... 0.057997
Comparing corpus/7 - kid.png to test/7 - kid.png... 0.061476
Comparing corpus/8 - julia.png to test/8 - julia.png... 0.021848
Average score: 0.094218