来源:pageout
译者:此间不留白
协议:CC BY-NC-SA 4.0
介绍
早在2019年5月, Gynvael Coldwind组织了一场code golf竞赛(短码比赛)。参赛者的奖品是国际IT安全会议CONFidence的门票。实际上,这次竞赛包含了C++,javascript和python的3种编程语言环境的比赛,我的关注点在python环境下的比赛。赛题的目标是生成一个命名为confidence.png有效的PNG图像,并且其像素值与指定的模型图像相匹配。参赛作品在全新安装的离线Ubuntu 19.04服务器使用python3 confidence.py的命令上运行,并且有60秒的执行时间限制。不能使用暴力方法,最后,代码量最小的confidence.py将会赢得比赛。
图像
模型图像是一个大小为11746字节大小的文件,如下所示:
第一步是在保留像素值的同时使图像尽可能小。并且有以下分析:
- 图像是完全不透明的,并且仅仅使用了8种颜色;
- PNG文件包含了一些我们可以去除的元数据(metedata);
- 图像是20×20的实心方块组成的;
- 图像可以无损的放大或者缩小20倍(不使用插值法);
遗憾的是,默认的python3环境中不包含任何第三方的图像处理库,所以不得已放弃以上方法。使用GIMP删除元数据和alpha通道并将图像转换为索引模式,得到了4283字节的PNG文件。然后我们可以使用PNG优化器optipng或pngcrush可以压缩至2547字节。使用参数为-iterations = 50 --filters = 01234mepb
的zopflipng可获得2428字节的最佳结果。对一些web浏览器和移动app而言,2428字节足以显示损坏的png文件。但是,我们需要的是正确的png文件,所以可能做不到保留像素值的同时,使其大小小于2428字节。
脚本
至此,我们已经尽可能的优化PNG文件了,怎样使用通用的压缩方法进一步压缩呢?我们可以使用的python方法,而zopfliwins再次使用原生的deflate流。要在Python中解压缩,我们需要使用wlibs = -8
作为加参数的zlib.decompress. 现在,如何将这710字节的二进制数据放入Python脚本?我们将需要整个2009个字节才能将其表示为字节文字.首先想到的是base64编码,等等,base64编码也支持base85编码,字符集越大,效率越高,毕竟是一个是短码比赛,每个字节都很重要,所以,综上,可以得到如下代码:
import zlib,base64 as b;open('confidence.png','wb').
write(zlib.decompress(b.b85decode('>kRO7=jD>(Vqjq4_4
IHFVqjozU|?XeU||M|Nd3K20Hh=Wd_r7-bSx7~4>Q~U|Nj@Wupez~y4cvfuA$LVZp&W=2
2OcT7srqa#y58yCq8lzX?Pee!gk9^=LnP7F(Bd=3*#0`QWX2fGJVOexNm|C-+uQsdM-Eq
8eUw*$Uq_Z5J94bE&77_?*v#6TxaFskPt8cVTA;T10dYc;0VNwjLb}IAj|?(z;Y+Z$CXJ
Ps06MItfU!;!AhXYKxPrI2yPi+MYru0<}n~Ef+)ad5@AIU1*9q>97^OWLO2?TQM^x*qFY
@rq{6=JpT770r(3%|-B&9!xp(w##q_&@FaMTuO8odhRJa^hh`MuTqsfu8SN4is^%q`tW6
cMh%b)hHk$U`0s`hm0^Eb=yX6xGB{PR$qxZp}q3+rCn7BOr0e81CIy_Ov+S@ZAnRMoKEW
$SzSD_2#1{$EqZ#7tD`NlU8T88&avlo@@YGsLcPUEef$*|R5ee_LnGPM@;%-BwKt7NX)V
p4WJz&t9)M>7>k6{>N8&`|W*|*=iY5oO<_c`MkNr#TK*v6*FnMHMR#o6#cgSyz;@?vbYB
<Z1xMOn(*|?d2Sq(u?)`S<zu9BI)Ct&$8-6Tu!2`o?;o9=8{VVML|P^#od0qzlo_jRU2<
Ra=6l}QpQc%_exKO)e7@-4x%Fo120u7?ku`ouf*46j_Mvtj>kB+&S)|wce(NbI*RQo-?q
3!0zFwiFPO^FU!}WmSC5hyhLj9$EOYK|t-~IpdQ+ABpo?|jHN%}M{T`5mc7bewBjymWcU
fR1WeDCTTQ-x98MzOUG-`v{PeY@WkYuO03m0GDJLtgn?J4w!^+)rdG!sByt6fsZ_{M*LP
ZUka9|5^L~W2ieZdIS=8Jghz&<lY0~c)I$ztaD0e0ss'),-8))
Method | 大小 |
---|---|
bz2.compress | 950 |
lzma.compress | 768 |
gzip.compress | 732 |
zlib.compress | 722 |
zlib.compress (level=9) | 720 |
zopfli --deflate | 710 |
Method | len() | len(repr()) |
---|---|---|
b64encode | 948 | 951 |
a85encode | 888 | 915 |
b85encode | 888 | 891 |
注意import语句,在编码数据字符串之前没有b。 请记住,许多文本编辑器会在保存的文件中添加其他换行符。 摆脱它! 对于代码高尔夫比赛来说8位太多了。
全二进制
跳过base85编码,直接在原始文件中嵌入二进制数据怎么样?当然,这种方法在短码比赛中是非法的。但是非比赛代码中可以尝试一下!
#coding=l1
import zlib;open('confidence.png','wb').write(zlib.d
ecompress(open(__file__,'rb').read()[111:],-8))
这种解决方案指需要821个字节,确实是一种不合竞赛规则,但是有效的解决方案。无论出于何种原因,都可以暴力地从encodings.aliases.aliases.keys()
和二进制数据生成具有所有Python编码的文件,然后尝试运行它们。 选择最小的方案。
网友评论