Skip to content

Instantly share code, notes, and snippets.

@ambv
Last active March 23, 2022 17:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ambv/fc5aa32738b1ccb231b5e3828a43c383 to your computer and use it in GitHub Desktop.
Save ambv/fc5aa32738b1ccb231b5e3828a43c383 to your computer and use it in GitHub Desktop.
Happy Atheist Day!
import base64
import bz2
from dataclasses import dataclass
from pathlib import Path
import pickle
from typing import Iterable, Iterator
try:
from rich.color import Color
from rich.console import Console, ConsoleOptions, RenderResult
from rich.segment import Segment
from rich.style import Style
except ModuleNotFoundError:
raise ImportError("Install Rich to run this.") from None
ColorLine = list[Color]
def image_to_color_lines(
path: Path,
*,
width: int = 80,
background_color: Color = Color.from_rgb(255, 255, 255),
) -> Iterator[ColorLine]:
try:
from PIL import Image
except ModuleNotFoundError:
raise ImportError("Install Pillow to generate color lines yourself.") from None
img = Image.open(path)
orig_width, orig_height = img.size
aspect_ratio = orig_height / orig_width
height = int(aspect_ratio * width)
img = img.resize((width, height))
line = []
count = 0
if img.mode == "RGBA":
bg = Image.new("RGBA", img.size, tuple(background_color.triplet))
img = Image.alpha_composite(bg, img)
img = img.convert("RGB")
for r, g, b in img.getdata():
line.append(Color.from_rgb(r, g, b))
count += 1
if count == width:
yield line
line = []
count = 0
@dataclass
class CommandLineImage:
color_lines: Iterable[ColorLine]
def __rich_console__(
self, console: Console, options: ConsoleOptions
) -> RenderResult:
background = None
background_color = None
padding = None
for line in self.color_lines:
if background_color is None:
background_color = line[0]
if padding is None:
width = len(line)
padding = (options.max_width - width) // 2
if background is None:
background = line
else:
yield Segment(" " * padding, Style(bgcolor=background_color))
for fg, bg in zip(line, background):
yield Segment("▄", Style(color=fg, bgcolor=bg))
yield Segment.line()
background = None
color_lines_compressed = """\
6<ł%_0gSqh;d#@;DeT2@<<*!us53kVs8W-!rSRYTs8W-!s8W-!s8W-!s8W-!s8W,W&KVI5!!!"H-oUki#D(_S!!#
t#54ATg(`m)71.6Xd'Kh5[1hKHF;bYUK4[tK0qP-a4%1c>#4Z*=NJYpfpaemL58VK;^-^$=)ocBf_g5L?Q`fi/k!
hLVLD)R8r;^4OG!;-Fi-o=PQl91U_:]LIq!!>Idzzzz!7@G>z2+9`(2,0>m!siE;BZ[+u6&6EZcl+Sb+f5nUH:AL
15T2Cg)$%SZ1]RN7N;sh7Bp1n,"&0[h!!"<#,p`Nk!!$[:JY2uC!!!#G#)tBOd*łU2HArdHRVAGA"$chd!!!O+!&
OZU!!4GldZZrp;e[;Me,Tq7ci=*.!,0^`J2.O`"$e[]BqPL"%0I.BTJQłBci>oDAtqTk!!$[XOeDk6;H46(!"Ao;
))M<n)?9aod)][0cl"Y?!!!H.#+>MsW&/4FVEpjT!!$[4BGWDWOłe!r.arpI&4NQj-jko.;k9Ss5uEO`;Lk^aUa6
R;$:Q4?"UHł&TFPq8Le*+!&/,a%5g@hY)F-S(:f=V+7FMuJ08)e#&-D_Df>9WI@BLfICSłnh_#!&%5@$EsOl8HSR
cgod0R-EVJW(I-RDi.;`2JEPbD[uł@cisl0Oks0YT&+I7cIrsBd1B-)l#cNin[:l+]:RY'*1cmUm)#>TVt.b=A$B
++GW^/18c8SZrAUF/=Kcj3*^9(B6i8aSbK*hV`Dl)(<H<?NgEłUU3J==71EPgPF7K:>iB)?&41sanłgM<PF#%"l2
$T;-e$@17.lXsdP%h8JskVNF^WId=PPUqOt-5PdO9t9WdWHt3?j#5BtG$ljZl/KN*mc[3[%a1)3'1qSDNWajH7O%
RUh-S8kOZO;]2;UX-5C&B-KWq?At>*VV!nWN1sLW_H0Q#N!(Pb0Oł6''H#V>$n4$A)J[ł0V7J$Gmj?I)7AYTj!bf
E^R3WEb'il!e0.<iX'VUNoKbC3rk"[łV#)m$Vji`AgMk'2aDm#M*EłSe:ka_+K.]>ie)20p&ZZX1U^56CaTk]2t,
qM;Z7%(X5Dd$(L5pCGM#&T*dh.7I,b0%hk$[%u<('k9^Gq%=dl^AHVND+0k)&kZ*G@Jt$)(7cd)^e,nV?1/2VK,B
`(_D;R)TIX[.b,CrU>QsC/-rLjH3R=ł#(n74$R-?%0OVmU0k;S</Sf+':^Y`R]+mfYD1i[*SHd:nX_P>hE2D/6#$
dfWo.DDłhS[rnm@,9OZ-:LcRN!e)Qq5,_VNd*X=baH>?Bg#Y<)mLU3LI%i8ER>:(8Y_$D@ESY,1VdTR**iBKqr!]
*3=.&^df63f/K$#cdlF'H<IguS!-i*7CLep0f<(H#M1R=aACsFN)lGWeWU)So?q3PF3SF$6Y:@uW>=(N8p_/9PhV
`[RgftR'N6AJPBXPl8qp.g!J;3ulmj<%(r:1&[0OOQ[,quBB&]'H'cqFTk-`#ł@EKlKGN1WhhkDhmXtM(i"H$X@Y
_sF=CfłX-ł%b@BnV*(cg4i7%AYml@3=Y:^d1LLuNQi7>h+ZLC[UEl^#VK?poP[.i.>Un8!?Q?u$cB845^Y,;iKB?
:GQeO;?puIXZj^n!!_*>c,n6%i7*9L!;Hu736rG08#_n.M!?cL$SB4AH'$3t4&r/l/.:PSNAP.1q;Pg+!łJ%6YS>
@j#1=1d$+łTF>UoQBjGr2DAii&HV[&ihhV"Cd$eNPTaZTT<te1?dI8L9ns<?,8c,FPrEPek!Xc(5P-jO%HEYd=gQ
`4'F@)kjo%8<Bh0Yj($4$kbmaKH-)-G0X$O@#M:S2Dr[8pk'.3Sm[Zf"AU8e@SBd80i5u"QSeNK''Co7@EusF0:o
0g(o7`]VK&u+VTCk*@?0QB5)r+błjWgmV24J2ocPrKf`XYA"[a;jU=b!^'5oFURfJ<S%)^QKAa=g(4ccs$$#Ig;R
qgB%'VcUFWl@$<#69Q/q@K;Y2kj8H9.#`-Q4jT-M*P%=adYc`m&go0-CLE`@4[;@%he_H*PhabL7R6-PYRW4!WYf
VT-"SlIP<IcVM[&2RSotI"9qFh8otKsm-11cHn"2-]Er`"34$^J5R9W*LGW"*-n-)nmE?SR+Ga'ATK^YXjq`KaPs
I_"S!D9"P0.f^PV<tn3B3lNZt+#$</Tu!_Włh)8s"@8K,*H4-orKIDDqq+U>50ł9KNZE+;1.NHB2e'[ł4P_MU7pZ
pW?+E0F5tGKAW5g.T@,$U)1W(0RP#'iA#'a.łdd)9Z*-LNZ/*%>Grk%Xol]I&oJCK>hlh3i@)8?6nZłf&R5eg:ol
K%Ws)Z8&E;6/9a+Ru_FR9kWiRiF)4b2u/Jl];ZDT<Qjd&5u`XAnAim^tZO-,Mi>]bka/JY[e86W3I^I<0&Ca5'K$
G=@^qm$@hdN'5IN"W?!#V".7Zk6^cYd]*1Fr=="_łNUaL"HIFG4:%fMFr,S"3V@s.k;kd1IU7T2N0A(/Af,/k^l?
rTgOu)Nr5*IN.[1Fj<B$tXm)a]KOf*M3BVaCa2o17NT-]FnuE1CG@_$(o@G?)3.="dd9()m2i4g3]H)if*X,?iJA
FnmIrY/'I_X62fO)-g?Yp#L9OE"r@J<43^@+Kkk5P.&OYQW1DAtp8Wi4Wd/+M<d8>mdT`@'aX>h6ceo<=)&@Yg6?
>/3g'.oXt1WC;I4YUS(?Q@b)Op*+#?$<gG_:f$MQB[NP!6a9!/5_=k7I2Ujj&G)S&1Rłj8B:f=Q2F!cRj-+rTd6t
b:'V$s=SKIXZ2as.'M,lJkOu4oj=HX+mOD77X?pW#Y!2(HmJuDNrM@>*:%#BEd/5LOV<+Ulk/f]BFcTHeiC.f0-]
?G^pn1(IQhgn+J.H[ER#('$Z0;Y<"+,f"HirpgeZłKK%2sODA`Ij#Mo]5kQhNT#:'a_ZQWHGIhR,2L.>:L>[d$Sm
a,ZN#,[80dh)$@E7łWeRu9c;?ł)E"RrjN+OV7VFlshK-5-BiV?XX4kN?4VW+&K;,t[baaj6S1Vo6;4*M_S-2Sq+d
Spt?!/mA%$["`lRZdG4t^M/%>q:u.#aCQ+J?O3nrXJ">SSB8!>mL,8[TN-K^ScEi5F#a"f732M@uUT-7+LD;]+T=
oh>rJfXf1r.r3Ik(+E9hlp5HWFgb=FmW;A3<_"c?R"j^A'J_[JER?%h%!^h'%ba!f?'ł#dSK5((^neB'NkhPln9)
3S4"!o]AeL4N/i'CM<[$g$QnD[ST#7'$4@l,`]A[R(@/)dHZ(.2#ke:e-UQu/0MC2ł:%3R(@7r`[Ea")3=V2/5D8
I_-I(ka/eH)[:>8/lW$[iRgec3IMrU_HS8;$A#GNS(#,;?ost!MI!R6FG4t+@R)H<9pjV*D'*JPQomI:=VEY<pBK
H<E.,#b6J3ECb%-g(C2-$!hs3g)"GXVA6E0>=)m#>0(//hf^,s_')JIs!YW2sf3i"'&2Rd/OXr$nVX0Pk-OGJ1KO
Y]9PhQI`c%:.Fe9*$N)K=o01tFt5ko!WDhlu6oRmg5PJ='o9`A)*39Q68S,iY?56on(KOJm_&&Sae.?pnnR+tR1/
M(hL,&<h4A)-P,(Qr$&@a$GXZ_EplO+<_j/84Wb*1*ł!K1+KRS+=]q'N.@&oJJcJ&8;SIJMNTG[$:pgł,"OHr&ct
TI+G1f3,)hDTJk1^=TTG&,J;B-=W!łNh@4hT^DIV%EM"i9,ł4W"rX$A'](12,7fCp$277/"G!Xapl5Z5+P+on&g#
-łY<@^!`S]łduBf,<W=>E0)'ZZUl1>c5/0anj[qV0P-S8;kDO>q!4H)f,gu!=At'?8s6/]dAOdJsK,0-,gVbZ7[P
iO<b,Y&<R.ZL$;"!T91ZS*(%RSMQ)t!+D1`s#>0aZ6(pZ_^krłRGI]8,63uG#f*uX&_>r?ErT2,a+Ft[b#"m%Lrł
TqC!s'i>Ig3AUYdC)P!łT6=%+4T^iF*.9M9MhH8WnTtI"+XuPNf4gQgU!J8<'cM.8rMFgB>E!QE_85?94upEq(kd
OTgY*rM7O#-)T:jT%K-X^YX?N"J!W!MsTi^%b[n3QY--J^M%'OEDpqm7GHKG>>5SpBKMX->=lg$FBłK7lpkuNgNC
%F]o+nHM>[C?#F<fa^rn8m24B,YdI!p3?S1;]^.stSLoCluT]IG/k&#Llf3S>dVMWf`IHO5a-f8.płQ3Z#Zuq'Wr
6e+,DgZ8Ai*^6V;4sYBCQG$akrY`tBC'X;Fe$s::X<<S6fe)A0O_<kbesuj<%UłYHW/(:R.m%Vq#=r9MuHS`f%7U
!L-50]9^/s,3ipfc(7o=#?KX1*ZJSD_Ul;(=`*?2RSA&TWf?jBka<jiLZLLOCN5h[dRYXP+'3[F82s=?2Tq]#>mA
*KX?Dh7O2d+C(hJ4,!;Y7Adr+kPTC1dt[6oQ*q-$^M1]8:m?NlBmTSZ@0WQ-=@uVsrechS4k'O'2VT[6@"]0fjGm
^'P%u<UUTSO?#@_5c(9U3[9T^;"mnmLW1elfO>=drł!a@npQ5<0c*=tA*^<VfirRf'#qama,1S/i,4Kio5,Gmf!g
!-]/WF<VXp1Uka6`L/OS^3]j#,lU?JfiHi^jroaQ3JM2duf/nnbfD5jI.Q7*QZiF3"4!R,i]Xs1T&^@+l+D`PpO!
]Lbp!$"/0&Tc"oc,;sg'?QX:-s&9n+;]8o8-+6nItFeZ`PB!8"k!c$+X%sC`(S$9DLl^1o+h&Y?S6'8i[L]iqKa`
K&YS&uJ8rGqh>e*dEmgPUJ6%[a7-Z%rAnRe-"A>g.;&m;@4A[:CJ0GSU0S10^MSW[h>#L36!gKG?#Dł!V84#VccK
f8!Dpi,=2i3.qO_W?YZpDXj0]3obPftR#WL-RO#Yba<7Ył;Z+pS6L;f[S%(n`<-OurjYnX2N3(QIHU)8?"n!u4Nt
6V5?n#12t$p-/B"R!K+Pq5@7KBg0sa1MRbBQ&IU',uc`1#TRFjPa!Ył+qSF81n7*fTb&CN$@ouMOVl(@5YVO2L`B
"gW@Fnł"@1I+0nb?$LeUf5eq_0*DhlT`L5*2]1n9n/Y`=EaX/iR3ł3e%dYVR+3$k!,g#Z*oF1^XkH6::m04PA?u+
YLQ],X(oFW8PJq7e#JRQV(4Ag_!E<@]Błupq)ł<_M!T>_g=o\
"""
def main(compressed: str = "") -> None:
console = Console()
if not compressed:
# regenerate image from .png
# original at https://www.atheistrepublic.com/atheist-day/symbol
color_lines = list(image_to_color_lines(Path("atheism.png"), width=42))
compressed = base64.a85encode(
bz2.compress(pickle.dumps(color_lines, protocol=4)), wrapcol=88, pad=True
).decode()
compressed = compressed.replace("\\", "ł")
print(len(compressed))
print(compressed)
compressed = compressed.replace("ł", "\\")
color_lines = pickle.loads(bz2.decompress(base64.a85decode(compressed)))
console.print(CommandLineImage(color_lines))
if __name__ == "__main__":
main(compressed=color_lines_compressed)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment