From 002d65a042d857f55822dd05a1aa833315a8a614 Mon Sep 17 00:00:00 2001 From: Privisus Date: Mon, 25 Dec 2017 01:07:37 +0700 Subject: [PATCH] visual art: Add a script for user identicons. --- generate-avatars/Privisus/Alice.png | Bin 0 -> 2435 bytes generate-avatars/Privisus/Bob.png | Bin 0 -> 2294 bytes generate-avatars/Privisus/Marry.png | Bin 0 -> 1068 bytes generate-avatars/Privisus/Privisus.png | Bin 0 -> 1031 bytes generate-avatars/Privisus/README.md | 35 +++++ generate-avatars/Privisus/Zulip.png | Bin 0 -> 697 bytes .../Privisus/generate-identicons.py | 140 ++++++++++++++++++ 7 files changed, 175 insertions(+) create mode 100644 generate-avatars/Privisus/Alice.png create mode 100644 generate-avatars/Privisus/Bob.png create mode 100644 generate-avatars/Privisus/Marry.png create mode 100644 generate-avatars/Privisus/Privisus.png create mode 100644 generate-avatars/Privisus/README.md create mode 100644 generate-avatars/Privisus/Zulip.png create mode 100644 generate-avatars/Privisus/generate-identicons.py diff --git a/generate-avatars/Privisus/Alice.png b/generate-avatars/Privisus/Alice.png new file mode 100644 index 0000000000000000000000000000000000000000..b9727bf953040ba80fe3028145ad8a5063ff5884 GIT binary patch literal 2435 zcmV-}34Hd6P)zpd&(F`#&m>8bBuSDaNs=TGb`5f8TRH@9+El{=CoeTQDrMZFc4DNh1!$cS|1L zzhhup)vSt}^Q(SoEjgQ;(YS2#<0ZAft!sQynZMIy)$qNI#V427J(*W^&*Gma-1@2F zM%S1)gY2}*%CziT6Ml}1>3XB$Cxedu!|zqids4UjWO3u(;Vz!PGr#ghw;dx%a z*2R;4-7)Qb$>62RSLAK2F4*5YF>ia@yXj?@U;=$%&4ZOwejkxFv!m>?OIFuEdse^t zdBd8^WgRoKM*Kcy<%61qNEM$0({}tiX>n`6JeRD` z9rv+)*NIULFr6uBN$=hxP}NPLQ3EmiW_&%+`Ca)%H4hQ9rS*-k);GO`2}#iVh}Zp{ z-=-8D`?35QvJ>Lc>|t`@kt2nZRZ5FXu-$9rKOQTZ@~v|}4pdbSZIHceTJPhV)-5P} zShEP+@0|y}&e(@SJMk5ia0g>@mMcIeu*j62RJgSEkr^OJ2GFLKS3vYhD)8-s>ie-V z@dO>3(QFUqEf}0$n~_|MQA`vkXVj(-RvRFdnlpwHEt7z_3Ar+;3(Qr>UHbp<3;t{=B)7b@iW0vo40Zk zQz0Ph)4CNHT0CfUd1_W&dJb7REO6hA&42G~|3EK15ruXrEF3Tkj=ddUOu|IFrs7l9 zn1sF{tFw5}Lg$J3yKRH+Tc^H#J9R5Xl-Zp>u`{b+;hKBY7*U~H6Pk{{@uLMt^y#!gRAOB9wm@^1}I_Y3B$G<&lq=wrrc%&P?8mqmRSHj z!=VkSXh0GhsmJwTp@d{gD#l4vyE1OZ(UEoAhfS~mg~pZ<+JM7A43D6;@Nj4ORbFvl z{@`3j<{<}S65})UBSwjfLftA6pwx+Ggh)-nL3c2}d-|tO(|7Bp!-cg63u-h!X>=kS z^1?h~%wR$fX2d6Ai{TuaL$C0qUGd`8@=kXMqyt-oiO{WUf{&Dfz<}FC2B3HXZd==H(u@b%zWcJ zm2*UHm>mxN0j>-27pSTvK6De;i%kVId}+=~9EdAyAtn?~2Vj&D;e(0EbcTb^AcKi} z7}>#63P8gynBehHP!wWIfZ=szPN_h#88OT6x)_(1!5!d(i!mgJu!1L9Wo*FdtfSG;?heBpXL~w6V-Z7yqnA`eM*G-{Kg6Ya0%{Sq%Sih+ z&X=}fTd`ly+WQSr9Amc*m zG_*-LDDevYxiM2I>slA`7AFM#l1msCAm(s)1`?Y*qygCuXebSwb==&EcR`U62tyJb zq31#uV%P57nq$>zKd$Z@U1~`NL`Deu|P`-6#nBI4X*(;xiW%LPKE)i%QR#7zN!f< zkZ0azc?+G8S&VE+5x&F*vfJI6qj~gcX{0do_DaZRcJz=BT;zohK0d>r86*)moW!&T z6y`AG!4k?rBVwUVG2HM|IEfxJq(mO$XD9U1C_qcN)1#YN(=yM405SN0peTDT=D3^d zozX@t(!|9kvNk}119Tv)bnv*3nio)eurW7P2?%Yah7OpUUE~1NM?nCbR!EGEBR6r8 zqyzZf8ADdWic1t~+dyzDri{L$1vHR}F~w-aL*7U|3S|{3F=PQi;S0Vk;hXNf&#)A+ zSGNvd+o4e&N#v7Z9**8rd5%&xAgExnfckpVHf+En;Xh1NAOXi{em#X1Oh6-|w4r43 zLX0PCVB#m=>HzOTa@AEXC#a3d6y5Hogd+qGNl|Yptc?cNfsDjB^I|R4G@~$s&$n3A zze2=S*0?vUNmmEMfjmK1=m`sAhnc0OCui!%j=tNDY4=@1@Vk`jN z9`FaWhdO+G>0|K!KV2wVe2oM6Fv{K9QzwcKT=Jqwvp}lB=WGK}g%wc| zBWn4G21G>TG@=imh(4+#`eGB&*T9IrG)MHm7!mysSw#Q)8qxpkNA#zWi2jfi(VyKS z`XgmTf6|TU58x5~b3sJ^xDwGnMMd-vchUSa=fBV_k+0IycoP5s002ovPDHLkV1iHk Bj|Bh# literal 0 HcmV?d00001 diff --git a/generate-avatars/Privisus/Bob.png b/generate-avatars/Privisus/Bob.png new file mode 100644 index 0000000000000000000000000000000000000000..f584e3a9475c734f2aed858e4fbc6eb242906918 GIT binary patch literal 2294 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 B=uZFu literal 0 HcmV?d00001 diff --git a/generate-avatars/Privisus/README.md b/generate-avatars/Privisus/README.md new file mode 100644 index 000000000..5916ca491 --- /dev/null +++ b/generate-avatars/Privisus/README.md @@ -0,0 +1,35 @@ +# Approach + +I decided it would be a good idea to approach this problem +mathematically. Boy I was in for a journey. + +Then I thought about "periodic" things in math, I figured that a sine, cosine, and tangent would be fine to work with. + +I also used PyPNG because it is small and relatively trivial to use and +understand. + +(Note: PyPNG can be obtained via `curl -LO https://raw.github.com/drj11/pypng/master/code/png.py`) + +# Process + +I tried to experiment a little bit in Demos to see if it has a potential. +Something like this showed up: + +![Desmos plot 1](https://lambda.sx/T2V.png "Desmos plot, first three enabled") + +![Desmos plot 2](https://lambda.sx/KS3.png "Desmos plot, last three enabled") + +Okay, looks promising, so I applied them into the program with few tweaks +here and there. + +# Results + +Results can be checked with the following command: + +`avatar-1.png`: `python generate-identicons.py Alice` +`avatar-2.png`: `python generate-identicons.py Bob` +`avatar-3.png`: `python generate-identicons.py Marry` +`avatar-4.png`: `python generate-identicons.py Zulip` +`avatar-5.png`: `python generate-identicons.py Privisus +Privisus@users.noreply.github.com` + diff --git a/generate-avatars/Privisus/Zulip.png b/generate-avatars/Privisus/Zulip.png new file mode 100644 index 0000000000000000000000000000000000000000..1c0e32e33f2d2ea409b7cad05e0aa0bffa371784 GIT binary patch literal 697 zcmV;q0!ICbP)x@kDH5XWX%a{PdS8Au_+KP6{ndPa)61imSrIq)4l?;}9ga}J?hp>5- z(YG&x-|hvLqkT?nRc-IGk^(@z@^DO(O6J49+!r zg@=*=OYGn0TxunWVw;spP(3WAB&w7A0~mxBJ5_!7s5`3D4b(L@gH-=o+Q30i)BG5( z7#R0|A=Cc)s_SJx{;9gF5!Dw-X{fk%8y@A7lE;0nbTO1(fGho6P#FLHab;!Puze{k fEg$Z5e&+lF*xE3eM + +Keyword arguments: + username -- User's username in string + useremail (optional) -- User's email + +Returns: void +''' + +import sys +import hashlib +import png +from math import sin, cos, tan + +#Return the sum of the list with this pattern: + * - // +def unique_sum(val_list): + sum = 0 + for k, ascii_value in enumerate(val_list): + if k % 4 == 0: + sum += ascii_value + elif k % 4 == 1: + sum *= ascii_value + elif k % 4 == 2: + sum -= ascii_value + elif k % 4 == 3: + sum //= ascii_value + + return sum + +#create sha-1 instance +sha1 = hashlib.sha1() + +#create encoded, utf-8 string from the second argument passed by the user +username_encoded = sys.argv[1].encode('utf-8') + +#check if the user supplied more than or equal to three arguments +if len(sys.argv) >= 3: + #if it does, set the encoded user-email + useremail_encoded = sys.argv[2].encode('utf-8') +else: + #if not, use the default encoded user-email + useremail_encoded = "DEFAULT".encode('utf-8') + +#create sha-1 of username +sha1.update(username_encoded) +username_sha1 = sha1.hexdigest() + +#create sha-1 of useremail +sha1.update(useremail_encoded) #dependent on the username +useremail_sha1 = sha1.hexdigest() + +#convert each character in each string to ASCII value, +#and summing it with this pattern: + * - // + +username_val_list = [ord(character) for character in username_sha1] +useremail_val_list = [ord(character) for character in useremail_sha1] + +username_sum = unique_sum(username_val_list) +useremail_sum = unique_sum(useremail_val_list) + +#figure out the trig values for the half of the icon +if useremail_sum % 3 == 0: + trig_values = [sin((useremail_sum**2+1)*x+useremail_sum) for x in range(0,2500//4)] +elif useremail_sum % 3 == 1: + trig_values = [cos((useremail_sum**2+1)*x+useremail_sum) for x in range(0,2500//4)] +elif useremail_sum % 3 == 2: + trig_values = [tan((useremail_sum**2+1)*x+useremail_sum) for x in range(0,2500//4)] + +grid_locations = [] + +#This can be simplified with list comprehension, but I decided to left it this way for readability +for trig_value in trig_values: + q1 = round(255 * sin(username_sum * (useremail_sum * trig_value))) + q2 = round(255 * sin(useremail_sum)) + + if q1 == 0: + q1 = 1 + + if q2 == 0: + q2 = 1 + + k = round(q1) % round(q2) + + if k >= 25 and k < 100: + k = 100 + + if k >= 100 and k < 200: + k = 200 + + if k > 200: + k = 100 + + grid_locations.append(k) + +#check if the list is generally dull, if it is, contrast it +if sum(grid_locations) < 25*25*100: + average_light = 255 * sum(grid_locations) // (25*25*100) + + grid_fix_dull = [] + + for color in grid_locations: + if color < average_light: + grid_fix_dull.append(255-average_light) + else: + grid_fix_dull.append((color*2) % 256) + + grid_locations = grid_fix_dull + +if sum(grid_locations) < 25*25*100: + grid_locations = [255-color for color in grid_locations] + +#split the list into chunk of 25 ints, which will be mirrored in the next steps +grid_squared = [grid_locations[x:x+25] for x in range(0, len(grid_locations),25)] + +grid_rgb = [] + +color_decide = (username_sum+useremail_sum) % 3 + +for row in grid_squared: + rgb_row = [] + for light in row: + if color_decide == 0: + rgb_row.extend([light, light//2, light//3]) + elif color_decide == 1: + rgb_row.extend([light//2, light , light//3]) + elif color_decide == 2: + rgb_row.extend([light//2, light//3, light]) + grid_rgb.append(rgb_row) + +#for each list, add a mirror list so it is symetrical with the respect to y axis +grid_rgb = [grid+grid[::-1] for grid in grid_rgb] + +#for each list, add a mirror list so it is symetrical with the respect to x axis +grid_rgb = grid_rgb + grid_rgb[::-1] + +#put the image and save it +png.from_array(grid_rgb, 'RGB').save(sys.argv[1] + ".png") +