From 1fefbf0db781fc04434ae6bcd9984efc34ff511e Mon Sep 17 00:00:00 2001 From: funnygeeker Date: Sat, 23 Mar 2024 22:41:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20micropython-easydisplay?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.ZH-CN.md | 3 +- README.md | 3 +- driver/st7735_buf.mpy | Bin 3665 -> 3656 bytes driver/st7735_buf.py | 2 +- driver/st7735_spi.mpy | Bin 4140 -> 4131 bytes driver/st7735_spi.py | 2 +- driver/st7789_buf.mpy | Bin 4225 -> 4215 bytes driver/st7789_buf.py | 2 +- driver/st7789_spi.mpy | Bin 4729 -> 4720 bytes driver/st7789_spi.py | 2 +- lib/easydisplay.mpy | Bin 6275 -> 5787 bytes lib/easydisplay.py | 575 ++++++++++++++---------------------------- main.py | 3 +- 13 files changed, 203 insertions(+), 389 deletions(-) diff --git a/README.ZH-CN.md b/README.ZH-CN.md index abeed32..5537bd0 100644 --- a/README.ZH-CN.md +++ b/README.ZH-CN.md @@ -30,8 +30,7 @@ from lib.easymenu import EasyMenu, MenuItem, BackItem, ValueItem, ToggleItem spi = SPI(1, baudrate=20000000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(17)) dp = st7735_buf.ST7735(width=128, height=128, spi=spi, cs=14, dc=15, res=16, rotate=1, bl=13, invert=False, rgb=False) -ed = EasyDisplay(display=dp, font="/text_lite_16px_2312.v3.bmf", show=True, color=0xFFFF, clear=True, - color_type="RGB565") +ed = EasyDisplay(dp, "RGB565", font="/text_lite_16px_2312.v3.bmf", show=True, color=0xFFFF, clear=True) status = True diff --git a/README.md b/README.md index f53deed..a3961ca 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,7 @@ from lib.easymenu import EasyMenu, MenuItem, BackItem, ValueItem, ToggleItem spi = SPI(1, baudrate=20000000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(17)) dp = st7735_buf.ST7735(width=128, height=128, spi=spi, cs=14, dc=15, res=16, rotate=1, bl=13, invert=False, rgb=False) -ed = EasyDisplay(display=dp, font="/text_lite_16px_2312.v3.bmf", show=True, color=0xFFFF, clear=True, - color_type="RGB565") +ed = EasyDisplay(dp, "RGB565", font="/text_lite_16px_2312.v3.bmf", show=True, color=0xFFFF, clear=True) status = True diff --git a/driver/st7735_buf.mpy b/driver/st7735_buf.mpy index 6117fe3b26913021514b8fd6944953fd2cc9d99a..807b176eb007f697bbda7c5e5c50daafc55a5790 100644 GIT binary patch delta 1225 zcmZXT-%lJ>6vuaVVSgjbo#8O7v`gOe?Q|)k zI~SUi_Mz;0|A4j+KJG@q7V1nGoO3T z{hoX7-0w^7mss~&O+HePwl2AZp6>X-;lbm_`c9?)`u5f%E^SG^l7?L=c$LCym!bIz z?7j+nuEE~xu5A`;mJi49LCcMD0n&v-R#>3J$UkO1>(#m<8Z{254|1_9Q72yF-#Qb z!=xLIOD2ii7y%pfOJ>O;POO1-Omm29%(Ry|6RE+Ps-ZP~w6X zVAB7pL=g*dUfYafS%k^(X4r%h7dLHG%l7}yUc@Enul5>dy^acIBaUW^I(mjqJN(=j zopn@gRo~MdC`v`ev${~Kg)_zavJ?NbP=m(k69<^pGZdUvoJyn4W@axsz2&O*dnxNd znkBTxiK*BbRJA`dB$Xu-CXA}oar)3%;%n%v3cRldQcf+;U*;<-_m!0en{aPU?TjHx zXoxyo+qpp+bX7jre=pKy@I~yte~9ffcroiVp@DmmUFZYJE_1!JGi}v5hFD~Xq9GO= zq8BA;+O?G(MRyhFs>DP%`p^|x_pEN&p%OE(kQ|arqwWx|rdkwTcs_H$*7!vAPIt9R z&$}y&ii9gEz&r(u-;mhW(o+k#76AIks4BTOhzA1 zEgG1NKb~A%n3-H!h)=$-1F$-tI;kju3V)@}Zxdd`=lYl^3rqeOi!uATk$E?(Q%hg4 z<)rY^Otz%+%7=yJb?Wd4ah@Qql%_eQ%KCcwnSklb+hkdbe5190g^2qWvIs9vAPZl= zdi#$%s~Kk{%&i*BGIxJ{x#9oIGi>?6oX|LbH(+LJDc~hnT;z=C8?IWiqYte*o=#dT;;$ delta 1308 zcmZXT-%}e^6vwmK{7z`Y&2k!kw9uP`2tfyuopgj+Ata?xsl71_ z*$Z{3&S*pLA0U13p%ps`DS^F8;R z@7}$;R`H}l*Qrxg5;Uj#U27PeoVY^O+*f8{pg%f%YUJF|*@^Vm+$}!dHV20i&`zOa z9uD7zSMEUPT{!YFyt)8g_aKb@@EUG}qnI>6Hzr=_!NdozViP*6`?I*r9gt4vj-wcrr5L&^h#5gOLjgRwQN%lPat<&tsxuaMY^; z!OKBOw^waN#TuJU9;`Hdj*VV>9=~HD@GPR@$e$&S4Wb< zbL`mBe~Ayp=<|lMcx=|gZRIti7$$fc6V3MBEjb$6o)5-Y=6vYi6}4vr5)`?$7MwH`Ck^_U&f7=7j2?Jel{Bpo-Dyu6I_~d+O5Z?4z_2 zc%t-vjxIBAp`}bF%N&W^7mLdqYb(ps+4aYW>{Jl3t|V=C_V1{f(c%Xy8?5g->v=Gh YSzlSb@7J&!#o~=ZT(EeDSqw-20W}(kWdHyG diff --git a/driver/st7735_buf.py b/driver/st7735_buf.py index cca20e6..f626154 100644 --- a/driver/st7735_buf.py +++ b/driver/st7735_buf.py @@ -144,7 +144,7 @@ def __init__(self, width: int, height: int, spi, res: int, dc: int, self.cs = Pin(cs, Pin.OUT, Pin.PULL_DOWN) if bl is not None: self.bl = PWM(Pin(bl, Pin.OUT)) - self.bl.duty(1023) + self.back_light(255) else: self.bl = None self._rotate = rotate diff --git a/driver/st7735_spi.mpy b/driver/st7735_spi.mpy index 2f6c00f911778c3418824500c04151ca7dbced5e..0cee60b91f269a589284660d8ab5ade597343af4 100644 GIT binary patch delta 1480 zcmZWoTWk|Y6!rQU+p*(}my4YcY{m(BI4#L$>jd*?;y8ss6XHTk!gGU3dF0_f786RS zcM>EjK8mCHsrpf<_<~Zjb`mF`N>xRxLcc0iYQ+yyKdM%$P|`S3tNygJHW5+#F*A40 zx%ZxX@9f_3-}IY%%sL<8r_Ddw`4fZj;o~D`PMwygf6mR^ z3VUwB-rMl%XV7y8dhfzM9D+U^h8QNz@ERrp?8l@94qzg}>zK5|8<=#!K};ghk4YyC zU=oExm~_Em1&&;Yqj+jb2gmR=36A4yDUjIR2ZMO(9|=ydJ(YsE%K;}{P8f2P!JC*! za0-(_I33UhxaTWqfinSpzz{G7OvRHSX9MPd<@sXBu!0qdm4%5PEA2Nh(J^pD&_TJt z0XiV)T`o}%u2|eaN*YSbN5_=)r~Sx)hSZE`h>v@1D4~pMz)3n`j#%D;w_PrHhkj%3 z?S5Bqi5!SRIrszwt%4i2#u~W&Ej)yUb+AnU*eNeC){&(Zk4$O!FEp>P1fV zY*cw4Ce&2YQj;WiJ`Wm1E~Fn&`5N{n=)Xt{O46ex6{+NvAotv_9VIcrlb9ISMt5jv z*IK^_N?uihOm$VDQ**K1UJFGF5GG@5!7h~ia807Ho|W-eiNGak&|1s({nn^KK0i)B zwpMc&=$F<;z5E`1YOVBM$P~gj)=w1)aRagVq=fl;d7N&tHF7fTwe9JUmEWXV*007R zJ0>7%enjWBRm;kvpE1*gNDXO}mArM$qXM&0b%1=0W6`>gL(U^Ele8y4MwqE_C)mWEYyC#J+(Q|B2mekT1PY z@7r4n=aPMkqwg!De~X+VI>He>eWA3aSx$FLD&M3O%GhnSF<_s>ni~%zK_-UuAxWxc z@|(104516Gis{m-CL=Ksb9zWpF&SU{U@3#i#NyP_)9lnAPvcW<4d9b6riUddSX*7M zx;OGK(I=%F_lB~??)x7bp;aCoBbG#ZT(PQrTP90pW6mPq8a%Rw~|>Fxrc}p=#Kx>Sw=s~@sWjlK|Px)`KABRPn~yD0|SVZ z=R}U=mB@jE->Li#`cYYxrL!nWzbNzcpJRH_xm<3AsfgUS+4=m#h55;qIUreLvTWzJ5Xp9u^PO{kzwdm1 z&%M{3H=X(}y{d+mP3nKp74?ZjBa_c&&HT|L@qxpqPoC%>%6-h;*QB;h!uB-mkf7rl z?EDluZ@}wQ(DfPYx(T~)!5$ofC~kr`Fx>!qF%@7RrU7^p(;&QsX)APNx)pjb4MQ)c zZLlBH2pqt)9o{Bz@Dn(MFFsenVSFV9F?=NjN7%Urj^c~|#30UODg}Ku3mmgq;kc~? zPGA~?eoT+RNtepSy_`M+oN}pM8kg3kE36C|aOqu!my;o<2_`WX7N$;2TCZWMV&EA; z1*HN9XrG|A*@9}YMdKP;R9{>=c$Tc{cOnfsE@y(8_;9%iCCC{CI3}IfhYjc89h(i_ zmA=&P>KhVlK@NgKDQpxFY!d9y6s_m>26$)|%HTBtV6(6a8U+XVg>u+}NuR>5h8Cd$ zBGGu|^`74*FL4*_B46gHsI0246})7Kl(?1Q_j|VcYyDl)Il}?&y!5?cwc{YtBi(JJ zvzG_eK~8p5%l2x%29HaB8v=Wh^ycS2O^^$zdu86kx`O_T1oDWYrq8P((?pOfCmpf%rABa??a;!X9Bf2B9)sO zI8oYW+R5akX?3kg{&2GFC)tH)oT?Ztk_81x=aDfLMqcrP^u**W7i-g6VsU$FJhe3* zkI;^fZOF(DCpsgU%xk&RQovkSb?RRDkZkAKlX)81CELsLn|3sCFT5SSFO8Tht46c3 zeNCi|gtuP)eJQ_a{GzjyUnhQ$lCtK2Mp=I~uebKx)#CLcRZ)(rsYY@a2R4Z5j+o5* zmAs2AB(wJOly>WhR`Sr?Q(IIPDl0BAWaolq&A8d(gU%W z&+D#JUP1_u_cK!&OjAEaB23=RC|}d!EGx%O|EW&5n7kXnfp1!8bH6n~{FDtl`X8tz8{r zBKW1%eo9P&%cBf;ox2{pI_umXw;NIGbao-g zu~quWTE|(XudEft&DqRMNYfkckojimnbn(WQT&!9s4e}1m|S%&Ex~m@)q@#2Pr~1k z?r#t+%^@}4I)>Ett&1~%-Ck5S3n6YXGauw0F45ut(^*D;JIlAt-SMee2k0+7`+sb^ zmFn$96wL-XxxH`TujibNx;Z zM(%{I{Z>OY*3Vo2bc)B0W=|hEbLzy&3-f<{bK`sNM>D6;Ppv&%l-g`(b3F(T&qD82 zcq9*x&O_ehCvdCL!=3YNDB;;B&5lGFhbA( zqeN|o!;3JMho@eLBeRfE;V8ioI7V<3vIGyqIKeTPAnJZNPSgyXn1Pd*;Z*K5c=`&Q zCb$pI5KO>Xf=zIapaRbjY==pL9q=r{6g)?;6V4Otf(rz@;dvEacpEN~nLi9LMXqJw zMRF|%FEPCuUM4etXW$if=ipVZ2QGQNkn{Qg4YEPzw*Qz7u#JD4i#Y>}<9 zO}3X_9Wtq`XVwtGFk`yNDC?-17VJSH?eU6eL96;kSg;7Wf~J_VXbAG@ET>3C( zQn;isT@ZJ(0SowFsHp_$j@F{1z|SdM$z5T#D=}_6zMTOC$uvRp&a@pxxO=B(ia~Qe zHO4ynw|FOmsL$ySuoPtk&+W8z>$X;Bgmcp|=OGJ^9`w>RXAS40KR6prJPOp!SB89A zv4-AW7?WIjAUi!tqy+NJyPI$1czT}iWA`U~sGiRYVMcns=!W(n--LV~bSPhn^b%-f zk$!4&MRGif`8w6EPpL&fpGMS+zu)CEki9xJ+R%XI$T#E@sw-Msub&=yVqfcuCdmSt zR|Y@V`~foE{#{p(fZTfOxUS-4Q8liohKj1KsG8POy#j*lP`HVkD}!;fCIvL7BxzDm zlPUxZ&}COO9EZ)P&Fx@djD9}!z=vu9WE zft6yuIm1Hv-ZtjK)*A`hP^Oa}DHFXRn8XLC1(W}wt&i^9+R}y1B)6q)DBKqU7R~Md zH?J`Bm#bpO+U=N;rN^I!N51V`&ZW}=)~qTVZmOw+Lthod6#dy#oN z(Y;=1t5pT8TPye_w(dq&Z};uBO%}evLc6uqjkS+&Ce3U?n7mn%OO>v(N(0${0H7Ch AQ~&?~ delta 1480 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 YrKaa+zn)y$#PmW|&ZfRjQ%7R|01P7ls{jB1 diff --git a/driver/st7789_spi.py b/driver/st7789_spi.py index 0d1526f..6146473 100644 --- a/driver/st7789_spi.py +++ b/driver/st7789_spi.py @@ -177,7 +177,7 @@ def __init__(self, width: int, height: int, spi, res: int, dc: int, self.cs = Pin(cs, Pin.OUT, Pin.PULL_DOWN) if bl is not None: self.bl = PWM(Pin(bl, Pin.OUT)) - self.bl.duty(1023) + self.back_light(255) else: self.bl = None self._rotate = rotate diff --git a/lib/easydisplay.mpy b/lib/easydisplay.mpy index 99b8bd22d9cd10f15346d6fd95803d78a744e481..055122e5e8a6fdf0dffa1ad170339deed81b3020 100644 GIT binary patch literal 5787 zcmd5=T~HfYc5Vp}vW!9MZW@UnBTH9TLi}0?+3U=B#;xYx*vJ@bKsTs1)Pt}%F`;e&_12sDj zTjiYFEdvvrJmeu2QQi04d(J)g-gCe6oh~{wRC$cSHML_Cwc+0QM1LecHrzW=Gd4jL zlzxEd`^E<-t`YnSieJi_pIL#*109*0AIu24;6QXVL1}}R!xNM)7$1sWq4I*E z;c#z^%8QJCKO9R?Y$!S$jRg}EV_`}s%ap!vFsMk{c;rvQ6x}byklXA zDoxCSvX~bS#iB4r+cz9ZQ2F8E;mBA#OlilW!xL0qC=!FnP@HU^=}3pPa?p&i!9KWx zOjOw5U^oGX>knV0wDEBGG9|s4eX@l*92^>s_sP3ccFPjG%vrKyeUwy@eX^C(Cc;BsZ)A*kha*ar(i<9>MkNjGE5ng^A`~4NJ4w}6HzX^P zjF!ZelDee&Q|cI{9;DQLl=ezA)=x>%(msG_Z!Fe3p)9K(4PQ}CqmK^vE0Q!Jsiar6 z@-0duBkDM%zDlVlsII8wmHY=a=I5E;mj#cv9&bJ0dj9zNYw-6x^L|cg)O-h(bGUUh z6pfL)k#E{e9D)=Z=}nw4zj=+yDSw$k21>GpMnzFMHRp%Ov{CRv97N*g(P+XAa*Df0f*i<3M$VUCUtPnccqYPfszIGk~0EEbN(VKKg=(;OM;9Sq0Ky|J)) zXBXhB;eYb=-_O&iV7CYN5`sp3;V7k1nW>zjy)G{(8K?x-v{xe^jGRc(aWB;!p{7fX zc`C7>s_Lq!S36ZDS*2=D9T4@|Am@~3bJ-wk^tpPiGppo4sfN>(=5o2ET231{@1pcN zx0=)WLaHCn2X_#yI9Vmtm9LDPF+`h zA@_=l;{>t?pUJaV=#ut*4B|U|#}HDLiHH9EPVH9y2^g=7r`IYnk_`0=|&+`me-azOJ?U z#hw(C$6DvQ($cY{tf`YV$S;P724yraX4w4V02#OKnW6Z?elbEcc%R1Z7l(<)zE9)u zi&3I+?9){E#Te04?9({?;yBSb_h~Bq;#H!l+^4DXi*FK5)jmzNU%XB<)%!FxelbZj zHTyKRe(`OhsokT|n{;)4aYl)zD91RdZOA|B7k}Ji@wMoP{ZS7UXw&)WH~v-d2HI4Y z;2MT1^IhM$^j-1iJt>QH^^2J==Pc4&Urc@Zd3x&E=b=9x>T}lngW_NH^k56Z*y6y| zHf(FEpnK-rsynmqrx^3y6jQ*s?~!-IeSUm?VRQPcUMD|Tn)zDX5QIhP={2>YB|9jhvWW( zc))J+x>9WYoJVyhJ-H!xtrVcKfOW%x(<$c2_NM4j2gpbR^gOE2JI7BrE&f6Aw>>@R z9bJ2MmBW6f<$}ZBHU~*S56$VnMbfE2o-ylDL58H5QZZSh?zXC)2&d_YRn4A&)!eEu zD3aZfJ}IVb>WOd$R9Wl^=)6!)fwCL|`$yJnFrB^uJ~l~wAp^b)2 zDRIMMMWC1g#SvfV?~ecdUjrX3t6%Yd@A5E^fysEZF2EGe>clb|+V^McZ}D0>TWkZ? zu>GjrSMB_swaNbK346$Hw_5FWR%fU#6md94YivIIu{wKGbwi}Kxn%)X7g9{&-9<&< z?yV|<{^3nUD7wF*2!;=DDFXe`nj$cdmKDMHU`Y{7AEX!->(`ZD@y9nCv*2LZkj8Y& z0RlWXX4(p5T(<=1H>^1j#Y+Hq%pybbD_poHG%hY&yn7Gn^{;LSK3YSECATUm(Yfwy z%<*9u*Jj42<#DY%-a(I8HS7tbmm`lj7D?iQCo4cCQCtM+me7=9>maM!2h`xi0^sj9Q z9lHbk-%P^T>l;EBO#e#SM22ldBg5C5claMpDn4exJ^vgQCaZc|=Ak|H84Uf$^%Q#? z6?s(HNQaTp4J|T2+yGN4_83w+o-EL6NCz3@aF|j|zTiVFTZv5R`BlVuasvFni%N(F zN$7~_b`r8roXlVlO2H7yr>vB zYbPk53T;b5GsN=g9ljB)q4~>eE2Mq^hw-OGQbCkDA^2ziJjFKdGU3CjJL$Jo?_@Xn z2QLpR1#kAJB7T8v8RAxqDg=iOyKK$YMtl_es+?^$XLYBo-qwU0a934Rm6fD0cHz!5 z4*Pk#-C?)eEN5T}u5dW)ZmYxLz~xr#Mvd^oRp;yX40~S;cQj`bLH{BV4EHklr|)O5 z%@AyVltFyqgG^R%AKrWcEx_?ZIyy(I-D*LYd&IY7*yPb#^Zne9*V!fy^@)p;TejIl zxm9)Q$B-*b12(*8&D{{BsU@LtW%=TR4{yB${WKrC^%C&Y{AmUJw-oHt1pCVb`yh$p z3P=Peg9Ht3SQ9eegV-0J%5l^880qem2dvGeDQka;!{iu<`6ft zjf>=6bj$eSW(l~8B${B$$cN>9cPT1GLGsoJTa=NN*`krD#3mV?9Ml`w5&v8yn<9>g zJ&R0;6-C&SJ10PoAqH#!xQP2ycuQXVoRTFzR6M&4oQg~MK6&NNopELK8_U9VD7jUF z3K4K^VDAnPR{wLG#S%F^Oo|f+jm(u+RKJ{=J-G3XJ!*qBGn(}p~6`NafSD8Y5 zWQWUAj0<|IOREgR783B^O7d1)>F{lmf!K=5g6$7g7@@<#_IFi)ax*H2U7&KY8N4U*~@#y#y%VIPc2d^BUyn{eM1h%PO#&71)ix zd!28Fa()2H)8bw(`wo1GsifnlwCDbK_ScnED%h_36+Hl-Jhd$E4z1J?LVKbRd)ni~wnl3OuE2IHcG^$_uom(;0Sj1WFdHth7T4iAO(q)HoFw8#Lsr@w)F z8gLK82s7*O0clkMlfAt@1DI#&0p<)YM1|{6to3KzYM_u^xoD4U+#{Pn20z4J+7K3| zce{iIe!e06f(&ImiW|b8O(Wyf_SEKEU*HlbZBUSq>DSoQiA#C!Ib2FACMohwq=CX} zf)=VS>7F7qL{M3_!{LM@lfYg6-RC z`1CG?lFT8Kw1q5NsAPK+TlqE^uqZOpBkL2P={B;G)Hes)f2hXjJyb?|Wyx+-21HOM z5+Z>5h3y$4ux-I7_J1J+R4)8Z%&-9sr4sUdmkkah1Z;rzvjNy`0wL_Mfde@R8#o9X zfGo2CgAlNR1=s-ig|NZX|D$!D0c!#MUWTK67ntWTGAh(l0XI;ID$?`FqHs?u40zFD zlBhqpwl_cJq}4&v%ECbqd?aIk(z8)?p;J!EcmGj5WRpKB5OUg`_WEj@4O=X=m9|zp zw!1C3ebmyilTo_~a&IR=?kzU|PIdn#)AYejrs2Von__*|Jdf(b73-l5;ij}R@X;-6 z{)X_g-2t}QTHt}2|L_q#ug5FtPW9NQC+lR&V4D}IIJ#2%Ow?WwQGaDlEfQMD(2Qq{v&=(y{ z66(O&&JPnL|z~m32|{EFFg2WD4rw?!Du8J40@Cy%iR>BZ3xo&zqJ&ZEg04h3 zI+&T)7mkDodENjQ3k*biLxfe9kmTaYKusfM5trY$Ow@a49CGT1SQSS zbc7vh$!Ny-=^pS+#wsWf8ulO69Ng!1ec znh13=bS_C~hQqzdej-=7jmYZ{g-`c`<8jOph6F4chE0I?4a4#9lkKTuu>nFA>lq+~ z(Ugs1x*8hlj|V!NPSz8`yQ$|?J>k=Ys%IdE<%89P3gHzMoQp{53v9SU#Q!zvOLcGzTJ6$?f%;1wa51#zX<=wnfGHt zrDR%(oYJPjU^I>cKnf=d76(*(fJ+{*y!|ebQ}(P0nRu0Es1yW|Q+1*rFB=3YSU@;o z8H^?^I2=R0RaI3MHr#6&i4I}O;G`D`RaU!4gWp~akyFw&m>7!1qVZ&?*V2I3H%J?> zoPe~eB66BG^CkH>9}iffgOL%7+fxZHw+z8C24eA0A^|d()^TN(`JrzFnl7JM?I6bi+JB~IA6hQ zckeD6=Cw+fqBzT}q?CSMn+zU7T-LQ7UsTm1|a0 zYV$T~n^{9?%-gB$<~%CTyo1`|Kj9{{J3UHjXGc)+QQphRof8z2e|5urOYhU41;|t5 z+a_`+bQ9+Bk_ppecCE%b_IQ--1L zQ`PQmRE=9h?Qw6X-0nPTuX_jOapzOD?wyoZcgn5xD5!nV>Y&{ZEeY*&Zawup&<3Di zgth?M!_ZRD9&r~^jN3>#yNEi5w+W-J+|IqlRNJPWnd%;ODLVI- zP$xTrr62TP{`2dfDo$!ST~E+kYcv%Vn@dW|_)2~kveqA^?HOxsZfujHQRmZ4>PcFA zoYpn(c!})&54OSI4z%Jmq!W$$4$)|s5{(7ZqLG>rjfJzK(Ksg>P4l9$XhAdk7TufpFE6b^sNe{xvui& zsdIerXts<&`zIR1UisoBEW!|^}IoIP7OZjS#DbKF}vdpZ6B=Iq_V@o@Y{nB&>R z(V8^19RC-m@VJwgtejHU=6gB*uTNP!d>TCN^%DMOjpXJ!Klm6N(O;3jFVuIM|M-+> z70x}J_;%7Nyz_AE+i%iikG=_}+Fkkki;DSwcG})hP7X|Z6jv`?6ZQ7%qTZlCcmux= z-DHNQrdP+mORe9Und3c5Kbft4VK(Jac$9qC?ezQ#+c0-wO?VVc&wmMIYVA71&ZSnb zO-=t>ooY0g@->k!_VeHKI+wkYJVOqOuu}2qB<%01nC|))>3r#KrbY~&kNtzzc{mz- zDqHFWj1&_<>(x z*%{%%4KhAEng0HJk0QNJ#^+>m_4f2kmpDK6sO$Xv#1Cs=mh-S;?b~mrXSx}JnID}F zp0D}D;5rhGh2OYPD{a7rw759&UDx?VS+(SmT)5_*odJ)G`3_JF7rEf)bq;%-TQodB=~Y}! zkFKzFHX;a4FdPJ*q(wcwzRG)*emrsrdR|5FgZ&3w4lZ#a&TnTw(6m(Ub~=vvx}A>Z zNk9cMIjODlC;?lf6&Jh;fDBQ;i%(T4yKIWD*`wr;O=)03n@14>Myd<&MATcyzGjaB zE6cz_=LvHRmgF9q6Bj)*|Z79skZYlW|dR@qjWjFeZROcLe|G z+;9Hw#wUua$_DPu;d6kRr6u0lpwU!z;Ud4wj-K)F_0?J1`)v(&+HvTBBj|A0Y>pb6 zD_9f!MQ)A5iOyM2z)@aaVMoc@qc!;5Qr+mYc2C0=VBba8XJn%I#*$1F+?|yP^UVdB zpzbWnMB!(bWWsoFUM5Oz&&fpTt!0@oeSTRc%D$Mb&w>-ux-?Dtw&5f>Nb8$-O8M^d zlfAYaFz0KFY=da11tb7Opbbcu`i?GusK1j%Q}gV5X;iR^4En~e*fw$iL5;Es#FuQ{ zT;0hu(q%aQIq=XE=2vX<6w+N@eQ*ttR}rQ4t+1_62bhmXVXSF|?S$pu39CrAj!2~Y zVf8BW;ixR*0*GfGgJP_;&Nl^Z^H(tRhxf=4(ZC=IJDM)M#5ReB7g3>C!7!+hE?m~O ztgyFuC{udN3i~QD7-~orc@`CV6iA13q}r36o?7x|`H6nx4Wo64v1O@CMZ| z*osVm#mrq0bOftMM%b@6`%ja0c*FW%vdwdBBRK8BRi+-aLo@x3Z|4H*1Kj}k%n|;l zh+iX>-ecUw8qv`9w1C{m{;R2`^)}i=@7@FR z8}>enHDJl4O2Ly

AX{r0`}Y`i-|T`Cz)8$(f=jIaB=E?4}66OTINpDm_Y;oxI2R zGRSl9QseJbpD!EQy~G!8LTU{iUc#fOQQoJu%lbpK?y^m_!u~pieZC+-Sm`{#rpYky zMT%5yCQ@|>?xi%jq;I7u<|K}K5;m!%3lW7=$`6q%O+aLwmHFH8%eLGV_E+PQ>1ZQ) z2EomjHj!tpKvP7X9fPKLS>H*UeYs2eBD!Srtz$`FPM2cCu7hE(q@Z4c7E_?*u7WN@ zMS+%!3fh9qs2FQ4=DSd_08gsxm6P-?+DhBz*q5O;qg`wCF5FtzXe(}QYqU)=XAdet zaOp)hPnO|CO55dCLf%&POkrq-*J-ORg^_lC(hp0|o@t7A|Wt^DY3X}BJ<^$Rp& z>J~9Q{WaT$N|7bKipr)|5%OgDnZwNQ-jnp41m_oC5lHMMea5k6v^i-PP49+Z^--^jw%6Or>2lg( zqg{4X3%G(hTn^evOBiF{0GSh;C{)=Iv02;eoBl*-d5R`?H_+tnQsb97_b%xVeSS&b z`Nbvu!TXmCFL?=CiwmsIr$#!+0CJ-ai~4=g!yj0X2l{2Wu-X(W>@R+{JOPPdAmjR% z=>k-+3=p98dz3V_i7wnk8#mD=pg|6vF90l!Kkd>*sOZ-#?8kU0BM~m6e>skfW9wt9 z?>wZ7k%@;Qf=vHRo7!nJQ+J#;BPf6P2GD>TsD)7Ma7o79W=L`=yGu4e7QoRcB{9xv z$l$WNE~Jx-p;3YulMFEc5=J^;O!&G{b;Z zrjZuezGfS)Kt2N=SOP5{Drs~XmEc}Ustc6>I+XAj9qcqsJ2L2CUxRx(paQ)H9}>_y z)@TPRV}CCrZV!N)9nr|~6e3Cy0*F9cAp+*DBF9sRa3Uv$2q%UJpe2aVBLom(1&DCU z5b@yuNY5jHGN>SD;b^Y|9F-!Yj7R0*ff`hvo&tQ60I3NET2U!Z)1SXP!*=<$!N5;H z2c`7g2I(sinkRYu(W#Zf?vqlgiW7W+UAh4vk31q1$sF!tjc1yH{~%!Irne&I%g?pDo&UK%hPyFm%}R zy-=X<-Xr5n9t9b{`^Sqw$NTi+Vs?w)oD+* zUz&JDcyNEYu80|d>iEGrt(%A9E-!DTN&K0NFLFybbT7$~%N#`{$n(n+m+SU0_yc99 dfnAioL710(dC=Dy*afNYhYm;#y(XdHe*;iz)rbH9 diff --git a/lib/easydisplay.py b/lib/easydisplay.py index 899ad96..b96dc62 100644 --- a/lib/easydisplay.py +++ b/lib/easydisplay.py @@ -1,7 +1,7 @@ # Github: https://github.com/funnygeeker/micropython-easydisplay # Author: funnygeeker # Licence: MIT -# Date: 2023/1/19 +# Date: 2023/2/18 # # 参考项目: # https://github.com/AntonVanke/micropython-ufont @@ -13,29 +13,21 @@ # PBM文件转换:https://blog.csdn.net/jd3096/article/details/121319042 # 灰度化、二值化:https://blog.csdn.net/li_wen01/article/details/72867057 # Framebuffer 的 Palette: https://forum.micropython.org/viewtopic.php?t=12857 - from io import BytesIO from struct import unpack -from framebuf import FrameBuffer, MONO_VLSB, MONO_HLSB, MONO_HMSB, RGB565, GS2_HMSB, GS4_HMSB, GS8 +from framebuf import FrameBuffer, MONO_HLSB, RGB565 class EasyDisplay: - MONO_VLSB = MONO_VLSB - MONO_HLSB = MONO_HLSB - MONO_HMSB = MONO_HMSB - RGB565 = RGB565 - GS2_HMSB = GS2_HMSB - GS4_HMSB = GS4_HMSB - GS8 = GS8 - BUFFER_SIZE = 32 + READ_SIZE = 32 # Limit the picture read size to prevent memory errors in low-performance development boards def __init__(self, display, + color_type, font: str = None, key: int = -1, show: bool = None, clear: bool = None, invert: bool = False, - color_type="RGB565", color: int = 0xFFFF, bg_color: int = 0, size: int = None, @@ -46,44 +38,38 @@ def __init__(self, display, """ 初始化 EasyDisplay - Args: - display: 显示实例 - font: 字体文件所在位置 - key: 指定的颜色将被视为透明(仅适用于 Framebuffer 模式) - show: 立即显示(仅适用于 Framebuffer 模式) - clear: 清理屏幕 - invert: 反转颜色 - color_type: 图像格式,RGB565 屏幕用 "RGB565",黑白 屏幕用 "MONO" - color: 图像主体颜色(仅彩色屏幕显示黑白图像时生效) - bg_color: 图像背景颜色(仅彩色屏幕显示黑白图像时生效) - size: 文本字号大小 - auto_wrap: 文本自动换行 - half_char: 半宽显示 ASCII 字符 - line_spacing: 文本行间距 - Args: display: The display instance + 表示显示的实例 + color_type: Color type of screen, "MONO" or "RGB565" + 屏幕的颜色类型,"MONO" 或者 “RGB565” font: The location of the font file + 字体文件位置 key: The specified color will be treated as transparent (only applicable for Framebuffer mode) + 指定的颜色将被视为透明(仅适用于 Framebuffer 模式) show: Show immediately (only applicable for Framebuffer mode) + 立即显示(仅适用于 Framebuffer 模式) clear: Clear the screen + 清理屏幕 invert: Invert colors + 反转颜色 color_type: Image format, "RGB565" for RGB565 screen, "MONO" for black and white screen + 图像格式,RGB565 屏幕用 "RGB565",黑白 屏幕用 "MONO" color: The main color of the image (only effective when displaying black and white images on a color screen) + 图像主体颜色(仅彩色屏幕显示黑白图像时生效) bg_color: The background color of the image (only effective when displaying black and white images on a color screen) + 图像背景颜色(仅彩色屏幕显示黑白图像时生效) size: Font size + 文本字体大小 auto_wrap: Automatically wrap text + 文本自动换行 half_char: Display ASCII characters in half width + 半宽显示 ASCII 字符 line_spacing: Line spacing for text + 文本行间距 """ self.display = display - try: - _buffer = display.buffer - # buffer: 驱动是否使用了帧缓冲区,False(SPI 直接驱动模式) / True(Framebuffer 模式) - buffer = True - except AttributeError: - buffer = False - self._buffer = buffer + self._buffer = hasattr(display, 'buffer') # buffer: 驱动是否使用了帧缓冲区,False(SPI 直接驱动) / True(Framebuffer) self._font = None self._key = key self._show = show @@ -111,7 +97,7 @@ def fill(self, *args, **kwargs): self.display.fill(*args, **kwargs) def pixel(self, *args, **kwargs): - self.display.pixel(*args, **kwargs) + return self.display.pixel(*args, **kwargs) def hline(self, *args, **kwargs): self.display.hline(*args, **kwargs) @@ -149,13 +135,13 @@ def fill_circle(self, *args, **kwargs): def clear(self): """ - 清屏 + Clear screen """ self.display.fill(0) def show(self): """ - 显示 + Display """ try: self.display.show() @@ -169,62 +155,12 @@ def rgb565_color(r, g, b): """ return (r & 0xf8) << 8 | (g & 0xfc) << 3 | b >> 3 - @staticmethod - def _calculate_palette(color, bg_color) -> tuple: - """ - 通过 主体颜色 和 背景颜色 计算调色板 - - Args: - color: 主体颜色 - bg_color: 背景颜色 - - Calculate the color palette based on the main color and background color - - Args: - color: Main color - bg_color: Background color - """ - return [bg_color & 0xFF, (bg_color & 0xFF00) >> 8], [color & 0xFF, (color & 0xFF00) >> 8] - - @staticmethod - def _flatten_byte_data(byte_data, palette) -> bytearray: - """ - 将 二进制 MONO 黑白图像渲染为 RGB565 彩色图像 - Args: - byte_data: 图像数据 - palette: 调色板 - - Returns: - RGB565 图像数据 - - Render a binary MONO black and white image as an RGB565 color image - - Args: - byte_data: Image data - palette: Color palette - - Returns: - RGB565 image data - """ - _temp = [] - r = range(7, -1, -1) - _t_extend = _temp.extend - for _byte in byte_data: - for _b in r: - _t_extend(palette[(_byte >> _b) & 0x01]) - return bytearray(_temp) - def _get_index(self, word: str) -> int: """ - 获取文字索引 - - Args: - word: 字符 - - Get Text Index + Get Text Index 获取文字索引 Args: - word: Character + word: Character 字符 """ word_code = ord(word) start = 0x10 @@ -243,55 +179,21 @@ def _get_index(self, word: str) -> int: start = mid + 2 return -1 - @staticmethod - def _reverse_byte_data(byte_data) -> bytearray: - """ - 反转字节数据 - - Args: - byte_data: 二进制 黑白图像 - - Returns: - 反转后的数据 (0->1, 1->0) - - Reverse Byte Data - - Args: - byte_data: Binary black and white image - - Returns: - Reversed data (0->1, 1->0) - """ - r = range(len(byte_data)) - for _pixel in r: - byte_data[_pixel] = ~byte_data[_pixel] & 0xff - return byte_data - # @timeit @staticmethod - def _HLSB_font_size(bytearray_data: bytearray, new_size: int, old_size: int) -> bytearray: + def _hlsb_font_size(bytearray_data: bytearray, new_size: int, old_size: int) -> bytearray: """ - 缩放 HLSB 字符 - - Args: - bytearray_data: 源字符数据 - new_size: 新字符大小 - old_size: 旧字符大小 - - Returns: - 缩放后的字符数据 - - Scale HLSB Characters + Scale HLSB Characters 缩放字符 Args: - bytearray_data: Source character data - new_size: New character size - old_size: Old character size + bytearray_data: Source char data 源字符数据 + new_size: New char size 新字符大小 + old_size: Old char size 旧字符大小 Returns: - Scaled character data + Scaled character data 缩放后的数据 """ - r = range(new_size) # 对于 micropython 来说可以提高效率 + r = range(new_size) # Preload functions to avoid repeated execution and improve efficiency if old_size == new_size: return bytearray_data _t = bytearray(new_size * ((new_size >> 3) + 1)) @@ -305,82 +207,31 @@ def _HLSB_font_size(bytearray_data: bytearray, new_size: int, old_size: int) -> (bytearray_data[_old_index >> 3] >> (7 - _old_index % 8) & 1) << (7 - _row % 8)) return _t - @staticmethod - def _RGB565_font_size(bytearray_data, new_size: int, palette: tuple, old_size: int) -> bytearray: - """ - 缩放 RGB565 字符 - - Args: - bytearray_data: 源字符数据 - new_size: 新字符大小 - old_size: 旧字符大小 - - Returns: - 缩放后的字符数据 - - Scale RGB565 Characters - - Args: - bytearray_data: Source character data - new_size: New character size - old_size: Old character size - - Returns: - Scaled character data - """ - r = range(new_size) - if old_size == new_size: - return bytearray_data - _t = [] - _t_extend = _t.extend - _new_index = -1 - for _col in r: - for _row in r: - if (_row % 8) == 0: - _new_index += 1 - _old_index = int(_col / (new_size / old_size)) * old_size + int(_row / (new_size / old_size)) - _t_extend(palette[bytearray_data[_old_index // 8] >> (7 - _old_index % 8) & 1]) - return bytearray(_t) - def get_bitmap(self, word: str) -> bytes: """ - 获取点阵图 + Get Dot Matrix Image 获取点阵图 Args: - word: 单个字符 + word: Single character 单个字符 Returns: - bytes 字符点阵 - - Get Dot Matrix Image - - Args: - word: Single character - - Returns: - Bytes representing the dot matrix image of the character + Bytes representing the dot matrix image of the character 字符点阵 """ index = self._get_index(word) if index == -1: return b'\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x0f\xcf\xf3\xcf\xf3\xff\xf3\xff\xcf\xff?\xff?\xff\xff\xff' \ - b'?\xff?\xff\xff\xff\xff' + b'?\xff?\xff\xff\xff\xff' # Returns the question mark icon self._font.seek(self.font_start_bitmap + index * self.font_bitmap_size, 0) return self._font.read(self.font_bitmap_size) def load_font(self, file: str): """ - 加载字体文件 - - Args: - file: 字体文件路径 - - Load Font File + Load Font File 加载字体文件 Args: - file: Path to the font file + file: Path to the font file 文件路径 """ self.font_file = file - # 载入字体文件 self._font = open(file, "rb") # 获取字体文件信息 # 字体文件信息大小 16 byte ,按照顺序依次是 @@ -412,40 +263,35 @@ def load_font(self, file: str): def text(self, s: str, x: int, y: int, color: int = 0xFFFF, bg_color: int = 0, size: int = None, half_char: bool = None, auto_wrap: bool = None, show: bool = None, clear: bool = None, - key: bool = None, invert: bool = None, color_type: int = None, line_spacing: int = None, *args, - **kwargs): + key: bool = None, invert: bool = None, line_spacing: int = None, *args, **kwargs): """ - Args: - s: 字符串 - x: 字符串 x 坐标 - y: 字符串 y 坐标 - color: 文字颜色 (RGB565 范围为 0-65535,MONO 范围为 0 和 大于零-通常使用 1) - bg_color: 文字背景颜色 (RGB565 范围为 0-65535,MONO 范围为 0 和 大于零-通常使用 1) - key: 透明色,当颜色与 key 相同时则透明 (仅适用于 Framebuffer 模式) - size: 文字大小 - show: 立即显示 - clear: 清理缓冲区 / 清理屏幕 - invert: 逆置(MONO) - auto_wrap: 自动换行 - half_char: 半宽显示 ASCII 字符 - color_type: 色彩模式 "MONO" 或 "RGB565" - line_spacing: 行间距 - Args: s: String + 字符串 x: X-coordinate of the string + x 坐标 y: Y-coordinate of the string + y 坐标 color: Text color (RGB565 range is 0-65535, MONO range is 0 and greater than zero - typically use 1) - bg_color: Text background color (RGB565 range is 0-65535, MONO range is 0 and greater than zero - typically use 1) + 文字颜色 (RGB565 范围为 0-65535,MONO 范围为 0 和 大于零-通常使用 1) + bg_color: Text background color (RGB565 range is 0-65535, MONO range is 0 and greater than zero - typically use 1)\ + 文字背景颜色 (RGB565 范围为 0-65535,MONO 范围为 0 和 大于零-通常使用 1) key: Transparent color, when color matches key, it becomes transparent (only applicable in Framebuffer mode) + 透明色,当颜色与 key 相同时则透明 (仅适用于 Framebuffer 模式) size: Text size + 文字大小 show: Show immediately + 立即显示 clear: Clear buffer / Clear screen + 清理缓冲区 / 清理屏幕 invert: Invert (MONO) + 逆置(MONO) auto_wrap: Enable auto wrap + 自动换行 half_char: Display ASCII characters in half width - color_type: Color mode, "MONO" or "RGB565" + 半宽显示 ASCII 字符 line_spacing: Line spacing + 行间距 """ if color is None: color = self.color @@ -465,8 +311,7 @@ def text(self, s: str, x: int, y: int, auto_wrap = self.auto_wrap if half_char is None: half_char = self.half_char - if color_type is None: - color_type = self.color_type + color_type = self.color_type if line_spacing is None: line_spacing = self.line_spacing @@ -478,14 +323,29 @@ def text(self, s: str, x: int, y: int, try: _seek = self._font.seek except AttributeError: - raise AttributeError("The font file is not loaded... Did you forget?") + raise AttributeError("The font file is not loaded... Did you forgot?") + + dp = self.display + font_offset = font_size // 2 + + # 颜色反转 + if invert: + color, bg_color = bg_color, color + + # 配置调色板 + if color_type == "MONO": + palette = FrameBuffer(bytearray(1), 2, 1, MONO_HLSB) # MONO pixels occupy 1 byte for every 8 pixels + elif color_type == "RGB565": + palette = FrameBuffer(bytearray(4), 2, 1, RGB565) # RGB565 pixels occupy 2 bytes for every 1 pixel + else: + raise KeyError("Unsupported color_type: {}".format(color_type)) + palette.pixel(1, 0, color) + palette.pixel(0, 0, bg_color) # 清屏 if clear: self.clear() - dp = self.display - font_offset = font_size // 2 for char in s: if auto_wrap and ((x + font_offset > dp.width and ord(char) < 128 and half_char) or (x + font_size > dp.width and (not half_char or ord(char) > 128))): @@ -503,93 +363,55 @@ def text(self, s: str, x: int, y: int, elif ord(char) < 16: continue - # 超过范围的字符不会显示* + # 超过范围的字符不会显示 if x > dp.width or y > dp.height: continue # 获取字体的点阵数据 - byte_data = list(self.get_bitmap(char)) - - # 分四种情况逐个优化 - # 1. 黑白屏幕/无放缩 - # 2. 黑白屏幕/放缩 - # 3. 彩色屏幕/无放缩 - # 4. 彩色屏幕/放缩 - byte_data = self._reverse_byte_data(byte_data) if invert else byte_data - if color_type == "MONO": - if font_size == self.font_size: - dp.blit( - FrameBuffer(bytearray(byte_data), font_size, font_size, MONO_HLSB), - x, y, - key) - else: - dp.blit( - FrameBuffer(self._HLSB_font_size(byte_data, font_size, self.font_size), font_size, - font_size, MONO_HLSB), x, y, key) - elif color_type == "RGB565": - palette = self._calculate_palette(color, bg_color) - if font_size == self.font_size: - data = self._flatten_byte_data(byte_data, palette) - if self._buffer: - dp.blit( - FrameBuffer(data, font_size, font_size, - RGB565), x, y, key) - else: - dp.set_window(x, y, x + font_size - 1, y + font_size - 1) - dp.write_data(data) + byte_data = self.get_bitmap(char) + + # 准备并缩放字符数据 + byte_data = bytearray(byte_data) + if font_size != self.font_size: + byte_data = self._hlsb_font_size(byte_data, font_size, self.font_size) + + # 显示字符 + fbuf = FrameBuffer(byte_data, font_size, font_size, MONO_HLSB) + if self._buffer: # FrameBuffer Driven + dp.blit(fbuf, x, y, key, palette) + else: + if color_type == "RGB565": + n_fbuf = FrameBuffer(bytearray(font_size * font_size * 2), font_size, font_size, RGB565) + n_fbuf.blit(fbuf, 0, 0, key, palette) # Render black and white pixels to color + elif color_type == "MONO": + n_fbuf = fbuf # Not tested else: - data = self._RGB565_font_size(byte_data, font_size, palette, self.font_size) - if self._buffer: - dp.blit( - FrameBuffer(data, - font_size, font_size, RGB565), x, y, key) - else: - dp.set_window(x, y, x + font_size - 1, y + font_size - 1) - dp.write_data(data) + raise ValueError("Unsupported color_type: {}".format(color_type)) + dp.set_window(x, y, x + font_size - 1, y + font_size - 1) + dp.write_data(n_fbuf) + # 英文字符半格显示 if ord(char) < 128 and half_char: x += font_offset else: x += font_size - try: - dp.show() if show else 0 - except AttributeError: - pass + self.show() if show else 0 def ppm(self, *args, **kwargs): self.pbm(*args, **kwargs) def pbm(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, invert: bool = False, - color_type=None, color: int = None, bg_color: int = None): + color: int = None, bg_color: int = None): """ - 显示 pbm / ppm 图片 - - # 您可以通过使用 python3 的 pillow 库将图片转换为 pbm 格式,比如: - # convert_type = "1" # 1 为黑白图像,RGBA 为彩色图像 - # from PIL import Image - # with Image.open("文件名.png", "r") as img: - # img2 = img.convert(convert_type) - # img2.save("文件名.pbm") - - Args: - file: pbm 文件 - 文件路径 (str) - 原始数据 (BytesIO) - x: 显示图片的 x 坐标 - y: 显示图片的 y 坐标 - key: 指定的颜色将被视为透明(仅适用于 Framebuffer 模式) - show: 立即显示(仅适用于 Framebuffer 模式) - clear: 清理屏幕 - invert: 反转颜色 - color_type: 图像格式,RGB565 屏幕用 "RGB565",黑白 屏幕用 "MONO" - color: 图像主体颜色(仅彩色屏幕显示黑白图像时生效) - bg_color: 图像背景颜色(仅彩色屏幕显示黑白图像时生效) - Display PBM / PPM Image + 显示 pbm / ppm 图片 # You can use the Pillow library in python3 to convert the image to PBM format. For example: + # 您可以通过使用 python3 的 pillow 库将图片转换为 pbm 格式,比如: # convert_type = "1" # "1" for black and white image, "RGBA" for colored image + # convert_type = "1" # 1 为黑白图像,RGBA 为彩色图像 + # # from PIL import Image # with Image.open("filename.png", "r") as img: # img2 = img.convert(convert_type) @@ -597,17 +419,27 @@ def pbm(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, Args: file: PBM file + pbm 文件 File path (str) + 文件路径 Raw data (BytesIO) - x: X-coordinate of the displayed image - y: Y-coordinate of the displayed image + 原始数据 + x: X-coordinate + X 坐标 + y: Y-coordinate + Y 坐标 key: Specified color to be treated as transparent (only applicable in Framebuffer mode) + 指定的颜色将被视为透明(仅适用于 Framebuffer 模式) show: Show immediately (only applicable in Framebuffer mode) + 立即显示(仅适用于 Framebuffer 模式) clear: Clear screen + 清理屏幕 invert: Invert colors - color_type: Image format, "RGB565" for RGB565 screen, "MONO" for black and white screen + 反转颜色 color: Image main color (only effective when displaying black and white image on a color screen) + 图像主体颜色(仅彩色屏幕显示黑白图像时生效) bg_color: Image background color (only effective when displaying black and white image on a color screen) + 图像背景颜色(仅彩色屏幕显示黑白图像时生效) """ if key is None: key = self._key @@ -617,8 +449,7 @@ def pbm(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, clear = self._clear if invert is None: invert = self.invert - if color_type is None: - color_type = self.color_type + color_type = self.color_type if color is None: color = self.color if bg_color is None: @@ -635,41 +466,53 @@ def pbm(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, _width, _height = [int(value) for value in f.readline().split()] # 获取图片的宽度和高度 f_read = f.read if file_format == b"P4\n": # P4 位图 二进制 - if self._buffer == 0: # 直接驱动 - buffer_size = self.BUFFER_SIZE - if invert: # New - color, bg_color = bg_color, color - palette = self._calculate_palette(color, bg_color) # 计算调色板 - dp.set_window(x, y, x + _width - 1, y + _height - 1) # 设置窗口 - data = f_read(buffer_size) + # 颜色反转 + if invert: + color, bg_color = bg_color, color + # 配置调色板 + if color_type == "MONO": + palette = FrameBuffer(bytearray(1), 2, 1, MONO_HLSB) + elif color_type == "RGB565": + palette = FrameBuffer(bytearray(4), 2, 1, RGB565) + else: + raise KeyError("Unsupported color_type: {}".format(color_type)) + palette.pixel(1, 0, color) + palette.pixel(0, 0, bg_color) + + if self._buffer: # Framebuffer 模式 + data = bytearray(f_read()) # 读取并显示图像 + fbuf = FrameBuffer(data, _width, _height, MONO_HLSB) + dp.blit(fbuf, x, y, key, palette) + else: # 直接驱动 write_data = dp.write_data + dp.set_window(x, y, x + _width - 1, y + _height - 1) # 设置窗口 + buffer_size = self.READ_SIZE + width = buffer_size * 8 + # Use different types of buffers according to different color types + if color_type == "RGB565": + data_fbuf = FrameBuffer(bytearray(buffer_size * 16), width, 1, RGB565) + elif color_type == "MONO": + data_fbuf = FrameBuffer(bytearray(buffer_size), width, 1, MONO_HLSB) # Not tested + else: + raise ValueError("Unsupported color_type: {}".format(color_type)) + data_fbuf_blit = data_fbuf.blit + # Read a picture several times, taking a part of it each time + data = bytearray(f_read(buffer_size)) while data: - # if invert: # Old - # data = bytes([~b & 0xFF for b in data]) - buffer = self._flatten_byte_data(data, palette) - write_data(buffer) - data = f_read(buffer_size) # 30 * 8 = 240, 理论上 ESP8266 的内存差不多能承载这个大小的彩色图片 - else: # Framebuffer 模式 - data = bytearray(f_read()) - if invert: - # data = bytearray([~b & 0xFF for b in data]) # Old - color, bg_color = bg_color, color # New - # data = self._reverse_byte_data(data) - if color_type == "MONO": - fbuf = FrameBuffer(data, _width, _height, MONO_HLSB) - dp.blit(fbuf, x, y, key) - elif color_type == "RGB565": - fbuf = FrameBuffer(data, _width, _height, MONO_HLSB) - palette = FrameBuffer(bytearray(2 * 2), 2, 1, RGB565) - palette.pixel(1, 0, color) - palette.pixel(0, 0, bg_color) - # palette = FrameBuffer(bytearray((color, bg_color)), 2, 1, RGB565) - dp.blit(fbuf, x, y, key, palette) - if show: # 立即显示 - try: - dp.show() - except AttributeError: - pass + fbuf = FrameBuffer(data, width, 1, MONO_HLSB) + data_fbuf_blit(fbuf, 0, 0, key, palette) # Render MONO pixels into RGB565 pixels + len_data = len(data) + if len_data < buffer_size: # Limit the data sent to no more than the Buffer size, so as to avoid data overflow and affect the display + if color_type == "RGB565": + fbuf_data = bytearray(data_fbuf)[:len_data * 16] + elif color_type == "MONO": + fbuf_data = bytearray(data_fbuf)[:len_data] + else: + raise ValueError("Unsupported color_type: {}".format(color_type)) + else: + fbuf_data = bytearray(data_fbuf) + write_data(fbuf_data) + data = bytearray(f_read(buffer_size)) elif file_format == b"P6\n": # P6 像素图 二进制 max_pixel_value = f.readline() # 获取最大像素值 @@ -680,10 +523,11 @@ def pbm(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, try: dp_color = dp.color except AttributeError: - pass + dp_color = self.rgb565_color dp_pixel = dp.pixel if self._buffer: # Framebuffer 模式 - buffer = bytearray(_width * 2) + if color_type == "RGB565": + buffer = bytearray(_width * 2) for _y in r_height: # 逐行显示图片 for _x in r_width: f_rinto(color_bytearray) @@ -693,8 +537,7 @@ def pbm(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, g = 255 - g b = 255 - b if color_type == "RGB565": - buffer[_x * 2: (_x + 1) * 2] = dp_color( - r, g, b).to_bytes(2, 'big') # 通过索引赋值 + buffer[_x * 2: (_x + 1) * 2] = dp_color(r, g, b).to_bytes(2, 'big') # 通过索引赋值 elif color_type == "MONO": _color = int((r + g + b) / 3) >= 127 if _color: @@ -706,11 +549,6 @@ def pbm(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, if color_type == "RGB565": fbuf = FrameBuffer(buffer, _width, 1, RGB565) dp.blit(fbuf, x, y + _y, key) - if show: # 立即显示 - try: - dp.show() - except AttributeError: - pass else: # 直接驱动 dp.set_window(x, y, x + _width - 1, y + _height - 1) # 设置窗口 buffer = bytearray(_width * 2) @@ -732,54 +570,47 @@ def pbm(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, else: _color = bg_color if _color != key: # 不显示指定颜色 - dp_pixel(_x + x, _y + y, _color) # NOTE 可使用缓冲区进行性能优化,考虑到兼容性,暂不修改 + dp_pixel(_x + x, _y + y, _color) if color_type == "RGB565": dp.write_data(buffer) - # NOTE 可使用缓冲区进行性能优化,考虑到兼容性,暂不修改 - else: raise TypeError("Unsupported File Format Type.") + self.show() if show else 0 # 立即显示 + def bmp(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, invert: bool = False, - color_type=None, color: int = None, bg_color: int = None): + color: int = None, bg_color: int = None): """ - 显示 bmp 图片 - - # 您可以通过使用 windows 的 画图 将图片转换为 `24-bit` 的 `bmp` 格式 - # 也可以使用 `Image2Lcd` 这款软件将图片转换为 `24-bit` 的 `bmp` 格式(水平扫描,包含图像头数据,灰度二十四位) - - Args: - file: bmp 文件 - 文件路径 (str) - 原始数据 (BytesIO) - x: 显示图片的 x 坐标 - y: 显示图片的 y 坐标 - key: 指定的颜色将被视为透明(仅适用于 Framebuffer 模式) - show: 立即显示(仅适用于 Framebuffer 模式) - clear: 清理屏幕 - invert: 反转颜色 - color_type: 图像格式,RGB565 屏幕用 "RGB565",MONO 屏幕用 "MONO" - color: 图像主体颜色(仅彩色图片显示以黑白形式显示时生效) - bg_color: 图像背景颜色(仅彩色图片显示以黑白形式显示时生效) - - Display BMP Image + Display BMP Image 显示 bmp 图片 # You can convert the image to `24-bit` `bmp` format using the Paint application in Windows. # Alternatively, you can use software like `Image2Lcd` to convert the image to `24-bit` `bmp` format (horizontal scan, includes image header data, 24-bit grayscale). + # 您可以通过使用 windows 的 画图 将图片转换为 `24-bit` 的 `bmp` 格式 + # 也可以使用 `Image2Lcd` 这款软件将图片转换为 `24-bit` 的 `bmp` 格式(水平扫描,包含图像头数据,灰度二十四位) Args: - file: BMP file + file: bmp file + bmp 文件 File path (str) + 文件路径 Raw data (BytesIO) - x: X-coordinate of the displayed image - y: Y-coordinate of the displayed image + 原始数据 + x: X-coordinate + X 坐标 + y: Y-coordinate + Y 坐标 key: Specified color to be treated as transparent (only applicable in Framebuffer mode) + 指定的颜色将被视为透明(仅适用于 Framebuffer 模式) show: Show immediately (only applicable in Framebuffer mode) + 立即显示(仅适用于 Framebuffer 模式) clear: Clear screen + 清理屏幕 invert: Invert colors - color_type: Image format, "RGB565" for RGB565 screen, "MONO" for black and white screen + 反转颜色 color: Image main color (only effective when displaying black and white image on a color screen) + 图像主体颜色(仅彩色图片显示以黑白形式显示时生效) bg_color: Image background color (only effective when displaying black and white image on a color screen) + 图像背景颜色(仅彩色图片显示以黑白形式显示时生效) """ if key is None: key = self._key @@ -789,8 +620,7 @@ def bmp(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, clear = self._clear if invert is None: invert = self.invert - if color_type is None: - color_type = self.color_type + color_type = self.color_type if color is None: color = self.color if bg_color is None: @@ -827,7 +657,7 @@ def bmp(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, flip = False else: flip = True - if _width > dp.width: # 限制图像显示的最大大小(多余部分将被舍弃) + if _width > dp.width: # Limit the maximum size of image display _width = dp.width if _height > dp.height: _height = dp.height @@ -877,7 +707,7 @@ def bmp(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, else: _color = bg_color if _color != key: # 不显示指定颜色 - dp_pixel(_x + x, _y + y, _color) # NOTE 可使用缓冲区进行性能优化,考虑到兼容性,暂不修改 + dp_pixel(_x + x, _y + y, _color) if color_type == "RGB565": if self_buf: @@ -885,13 +715,8 @@ def bmp(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, dp.blit(fbuf, x, y + _y, key) else: dp.write_data(buffer) - # NOTE 可使用缓冲区进行性能优化,考虑到兼容性,暂不修改 - if show: # 立即显示 - try: - dp.show() - except AttributeError: - pass + self.show() if show else 0 # 立即显示 else: raise TypeError("Unsupported file type: only 24-bit uncompressed BMP images are supported.") else: @@ -899,25 +724,17 @@ def bmp(self, file, x, y, key: int = -1, show: bool = None, clear: bool = None, def dat(self, file, x, y, key=-1): """ - 显示屏幕原始数据文件,拥有极高的效率,仅支持 RGB565 格式 - - Args: - file: dat 文件 - 文件路径 (str) - 原始数据 (BytesIO) - x: X坐标 - y: Y 坐标 - key: 指定的颜色将被视为透明(仅适用于 Framebuffer 模式) - Display screen raw data file, with extremely high efficiency, only supports RGB565 format. + 显示表示屏幕原始数据的文件,拥有极高的效率,仅支持 RGB565 格式 Args: - file: DAT file - File path (str) - Raw data (BytesIO) - x: X-coordinate - y: Y-coordinate + file: dat file dat 文件 + File path (str) 文件路径 + Raw data (BytesIO) 原始数据 + x: X-coordinate X坐标 + y: Y-coordinate Y 坐标 key: Specified color to be treated as transparent (only applicable in Framebuffer mode) + 指定的颜色将被视为透明(仅适用于 Framebuffer 模式) """ if key is None: key = self._key @@ -944,7 +761,7 @@ def dat(self, file, x, y, key=-1): data = f_read(_width) y_offset += 1 else: # 直接驱动模式 - size = self.BUFFER_SIZE * 10 + size = self.READ_SIZE * 10 data = f_read(size) dp_write = self.display.write_data self.display.set_window(x, y, x + _width - 1, y + _height - 1) diff --git a/main.py b/main.py index dbb8a70..dd85ae8 100644 --- a/main.py +++ b/main.py @@ -5,8 +5,7 @@ spi = SPI(1, baudrate=20000000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(17)) dp = st7735_buf.ST7735(width=128, height=128, spi=spi, cs=14, dc=15, res=16, rotate=1, bl=13, invert=False, rgb=False) -ed = EasyDisplay(display=dp, font="/text_lite_16px_2312.v3.bmf", show=True, color=0xFFFF, clear=True, - color_type="RGB565") +ed = EasyDisplay(dp, "RGB565", font="/text_lite_16px_2312.v3.bmf", show=True, color=0xFFFF, clear=True) status = True