From c21d122d1e5cfaec524a0cccc1c903e533f2e33e Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 22 Jan 2007 18:02:06 +0000 Subject: [PATCH] Add an icon for the PuTTY installer. Design concept (and noticing that Inno Setup had an option to specify an icon) by Jacob; detailed artwork and translation into Python by me. git-svn-id: svn://svn.tartarus.org/sgt/putty@7136 cda61777-01e9-0310-a592-d414129be87e --- icons/Makefile | 17 +++++++-- icons/mkicon.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++++- windows/installer.ico | Bin 0 -> 11478 bytes windows/putty.iss | 1 + 4 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 windows/installer.ico diff --git a/icons/Makefile b/icons/Makefile index 0697e024..0e16de34 100644 --- a/icons/Makefile +++ b/icons/Makefile @@ -1,6 +1,6 @@ # Makefile for the PuTTY icon suite. -ICONS = putty puttycfg puttygen pscp pageant pterm ptermcfg +ICONS = putty puttycfg puttygen pscp pageant pterm ptermcfg installer SIZES = 16 32 48 MODE = # override to -it on command line for opaque testing @@ -9,7 +9,8 @@ PNGS = $(foreach I,$(ICONS),$(foreach S,$(SIZES),$(I)-$(S).png)) MONOPNGS = $(foreach I,$(ICONS),$(foreach S,$(SIZES),$(I)-$(S)-mono.png)) TRUEPNGS = $(foreach I,$(ICONS),$(foreach S,$(SIZES),$(I)-$(S)-true.png)) -ICOS = putty.ico puttygen.ico pscp.ico pageant.ico pageants.ico puttycfg.ico +ICOS = putty.ico puttygen.ico pscp.ico pageant.ico pageants.ico puttycfg.ico \ + installer.ico CICONS = xpmputty.c xpmpucfg.c xpmpterm.c xpmptcfg.c base: icos cicons @@ -59,6 +60,18 @@ pscp.ico: pscp-16.png pscp-32.png pscp-48.png \ pscp-16-mono.png pscp-32-mono.png pscp-48-mono.png ./icon.pl -4 $(filter-out %-mono.png, $^) -1 $(filter %-mono.png, $^) > $@ +# Because the installer icon makes heavy use of brown when drawing +# the cardboard box, it's worth having 8-bit versions of it in +# addition to the 4- and 1-bit ones. +installer.ico: installer-16.png installer-32.png installer-48.png \ + installer-16-mono.png installer-32-mono.png \ + installer-48-mono.png \ + installer-16-true.png installer-32-true.png \ + installer-48-true.png + ./icon.pl -8 $(filter %-true.png, $^) \ + -4 $(filter-out %-true.png, $(filter-out %-mono.png, $^)) \ + -1 $(filter %-mono.png, $^) > $@ + xpmputty.c: putty-16.png putty-32.png putty-48.png ./cicon.pl main_icon $^ > $@ diff --git a/icons/mkicon.py b/icons/mkicon.py index 00132917..cf076305 100755 --- a/icons/mkicon.py +++ b/icons/mkicon.py @@ -675,9 +675,79 @@ def spanner(size): return canvas +def box(size, back): + canvas = {} + + # The back side of the cardboard box in the installer icon. + + boxwidth = round(15 * size) + boxheight = round(12 * size) + boxdepth = round(4 * size) + boxfrontflapheight = round(5 * size) + boxrightflapheight = round(3 * size) + + # Three shades of basically acceptable brown, all achieved by + # halftoning between two of the Windows-16 colours. I'm quite + # pleased that was feasible at all! + dark = halftone(cr, cK) + med = halftone(cr, cy) + light = halftone(cr, cY) + # We define our halftoning parity in such a way that the black + # pixels along the RHS of the visible part of the box back + # match up with the one-pixel black outline around the + # right-hand side of the box. In other words, we want the pixel + # at (-1, boxwidth-1) to be black, and hence the one at (0, + # boxwidth) too. + parityadjust = int(boxwidth) % 2 + + # The entire back of the box. + if back: + for x in range(int(boxwidth + boxdepth)): + ytop = max(-x-1, -boxdepth-1) + ybot = min(boxheight, boxheight+boxwidth-1-x) + for y in range(int(ytop), int(ybot)): + pixel(x, y, dark[(x+y+parityadjust) % 2], canvas) + + # Even when drawing the back of the box, we still draw the + # whole shape, because that means we get the right overall size + # (the flaps make the box front larger than the box back) and + # it'll all be overwritten anyway. + + # The front face of the box. + for x in range(int(boxwidth)): + for y in range(int(boxheight)): + pixel(x, y, med[(x+y+parityadjust) % 2], canvas) + # The right face of the box. + for x in range(int(boxwidth), int(boxwidth+boxdepth)): + ybot = boxheight + boxwidth-x + ytop = ybot - boxheight + for y in range(int(ytop), int(ybot)): + pixel(x, y, dark[(x+y+parityadjust) % 2], canvas) + # The front flap of the box. + for y in range(int(boxfrontflapheight)): + xadj = int(round(-0.5*y)) + for x in range(int(xadj), int(xadj+boxwidth)): + pixel(x, y, light[(x+y+parityadjust) % 2], canvas) + # The right flap of the box. + for x in range(int(boxwidth), int(boxwidth + boxdepth + boxrightflapheight + 1)): + ytop = max(boxwidth - 1 - x, x - boxwidth - 2*boxdepth - 1) + ybot = min(x - boxwidth - 1, boxwidth + 2*boxrightflapheight - 1 - x) + for y in range(int(ytop), int(ybot+1)): + pixel(x, y, med[(x+y+parityadjust) % 2], canvas) + + # And draw a border. + border(canvas, size, [(0, int(boxheight)-1, BL)]) + + return canvas + +def boxback(size): + return box(size, 1) +def boxfront(size): + return box(size, 0) + # Functions to draw entire icons by composing the above components. -def xybolt(c1, c2, size, boltoffx=0, boltoffy=0): +def xybolt(c1, c2, size, boltoffx=0, boltoffy=0, aux={}): # Two unspecified objects and a lightning bolt. canvas = {} @@ -689,10 +759,12 @@ def xybolt(c1, c2, size, boltoffx=0, boltoffy=0): bb = bbox(c2) assert bb[2]-bb[0] <= w and bb[3]-bb[1] <= h overlay(c2, w-bb[2], 0-bb[1], canvas) + aux["c2pos"] = (w-bb[2], 0-bb[1]) # Position c1 against the bottom left of the icon. bb = bbox(c1) assert bb[2]-bb[0] <= w and bb[3]-bb[1] <= h overlay(c1, 0-bb[0], h-bb[3], canvas) + aux["c1pos"] = (0-bb[0], h-bb[3]) # Place the lightning bolt artistically off-centre. (The # rationale for this positioning is that it's centred on the # midpoint between the centres of the two monitors in the PuTTY @@ -723,6 +795,18 @@ def puttygen_icon(size): def pscp_icon(size): return xybolt(document(size), computer(size), size) +def installer_icon(size): + aret = {} + # The box back goes behind the lightning bolt. + canvas = xybolt(boxback(size), computer(size), size, boltoffx=-2, boltoffy=+1, aux=aret) + # But the box front goes over the top, so that the lightning + # bolt appears to come _out_ of the box. Here it's useful to + # know the exact coordinates where xybolt placed the box back, + # so we can overlay the box front exactly on top of it. + c1x, c1y = aret["c1pos"] + overlay(boxfront(size), c1x, c1y, canvas) + return canvas + def pterm_icon(size): # Just a really big computer. @@ -894,6 +978,8 @@ if colours == 0: return pixvals[colour] def finalisepix(colour): return colour + def halftone(col1, col2): + return (col1, col2) elif colours == 1: # Windows 16-colour palette. cK,cr,cg,cy,cb,cm,cc,cP,cw,cR,cG,cY,cB,cM,cC,cW = range(16) @@ -941,6 +1027,8 @@ elif colours == 1: if colour == cD: return cK return colour + def halftone(col1, col2): + return (col1, col2) else: # True colour. cK = (0x00, 0x00, 0x00, 0xFF) @@ -993,6 +1081,11 @@ else: else: def finalisepix(colour): return colour + def halftone(col1, col2): + r1,g1,b1,a1 = col1 + r2,g2,b2,a2 = col2 + colret = (int(r1+r2)/2, int(g1+g2)/2, int(b1+b2)/2, int(a1+a2)/2) + return (colret, colret) if test: testrun(eval(realargs[0]), realargs[1]) diff --git a/windows/installer.ico b/windows/installer.ico new file mode 100644 index 0000000000000000000000000000000000000000..2bd92c6da2425c32bc31fe9aebe53e46d84cf063 GIT binary patch literal 11478 zcmeHNO>A6O6+X{1<7ayu&%_hQjwkUP3nBy(-V&Bw@l!z(pmd&4 zt6EjpT~{osDyugRy7D!02K!7QKEk7kdOCoCg_`Y-ReRJQ>xYJ^2D$P;O zJMY}{opXQQ{W;eYkwE69UKhwYdAuU>f{3)+Mt^xufG=c~=-s81=NJ)oMu;MY6TECD*TChp8*y0_q>&--Gw|_5h9L+jxHq z{0;DwrXw&Nfsf({1eUN7DJ8ls$mk_Y!Hltcy4h}A!3-Q3uw1Fk&Q{80jl+VFRMrBs zPnB&+Fuy=MC=9FB#l@;qMNWiEwff1CzT5~Kr+mG(w34zfgFL$li)YjV*TA7+ffVea z5!xEzbpYN6-+_LR;X~lK&$hwa;AEdILn$JEpT&O3J=N`e+{sowO>p#JN2LBe!efVGCe}nIU55R}u7={7bo(BAH?d}+G#|6#{dt#UlzL#CH0Jvj69#P(o4voy%)zifD zC=Kwz*v$=jg={fMa8?OKAwc0iKq?ia|CZDjRsuvLh*V}%07f@NfXssY2nYnLi)YSG zKL9O00P1Y$RbV_30YNPhV2Vdi0Q3+J!)$Pi0bp)^p}KgY*p5@QEI6VUPL8oJHvniX zomv@VKfSspvf4N^KhD11JlkA9x6vABUtMdi9pS%x8aJEM%jX{$<8OOEw*UMtmU4qP z8phGvKw9xYYTyuD0tX34c*lHG=6i(Wdw?4l_{u(#ADru@djKS7I|^eI#s>f&AmCAa z2zx9w<|!TU7r{xMG7qJQwj-2ooBLoUPhl?MauweFegobIGhg{B_{ZR{gPC`riFzMo z?(zpP^Ov82Z-L(iGmrTT_?uw#PxF{}A>RSN4rb26yoUJ+?hu{ z@#xkB?coMvKYBjkmYby`=TB<#`3mkVyf5+YQnE6zl0S#( zou+H$6)Rgu$Oyq{Cs9TjIj}lq4fcJ=(8>}d?@+uMQu6Y{dy;g`{f9d5MzrG}8VniX z1%J=x1(JWuj`tz)cj}k`oLsR2Ca-p6?+#^+i9Z;P zp$HYigfUTpCtly*IKf>h-~fS~UgE%kICdmwcUe+mw}8ZM0qdw?#x zB*~az=eGbEGrk$V5h)3vA5V+)fi4&Teu=O5dv&%$4GdiE2mHvp5liZQP>&z`*^ zn1asDn+52i;wD4_1`3orl)N-fB(9l{%%#)c11=cZ5+KsnB&kexmDna*AF(& z5yp_4u>Pc{#Z6p)^0VB>yG4-0o5{@LG~RPa#kaFRj~_W458kaWU1L~eNqoD`bS+{r zCLM6=O&vVETX*VEcdK)>fGyrGLUhcppzanU%KZvBwr16i7Pe`T=fFX-#BY{3pwYV0 z@ib#)L3)jnzFwnzJpYeQyZUiHn zaezL@@+dKwNTDvtFy+9lg{v2I%X5%E_8&`k{c?1`QW*Q?=m4t(McrhdQe;0gyTNW~ zlLg~n(@hHrLMjUOy@;FFaF{E9nwwZr`4F2~Vfla#`8dO&j44NPA^!c9b920UHCL}0 zo!wj6{uYfghe$__+h}A4%stI;!jLIVGcuD7i%%0KY^weV6Tva&5g zxkHI{z4Cd%3v&Ha_@F<+DN%<0Jhp&q;6?BObkOnszZ28mNF(PTuDuJlBUwR1i{uW< zFRA@1