From 5b5cac8d90a96b0b3b6a67d02f902aece8922cb0 Mon Sep 17 00:00:00 2001 From: ussoewwin <136552381+ussoewwin@users.noreply.github.com> Date: Tue, 19 May 2026 03:29:31 +0900 Subject: [PATCH] docs: replace README language switcher SVGs with PNG assets --- README.md | 5 +- README.zh.md | 5 +- assets/lang-en-active.png | Bin 0 -> 681 bytes assets/lang-en-active.svg | 10 --- assets/lang-en-inactive.png | Bin 0 -> 617 bytes assets/lang-en-inactive.svg | 4 - assets/lang-switch-en.png | Bin 0 -> 1751 bytes assets/lang-switch-zh.png | Bin 0 -> 1674 bytes assets/lang-zh-active.png | Bin 0 -> 1167 bytes assets/lang-zh-active.svg | 10 --- assets/lang-zh-inactive.png | Bin 0 -> 1164 bytes assets/lang-zh-inactive.svg | 4 - scripts/generate_lang_buttons.py | 141 +++++++++++++++++++++++++++++++ 13 files changed, 145 insertions(+), 34 deletions(-) create mode 100644 assets/lang-en-active.png delete mode 100644 assets/lang-en-active.svg create mode 100644 assets/lang-en-inactive.png delete mode 100644 assets/lang-en-inactive.svg create mode 100644 assets/lang-switch-en.png create mode 100644 assets/lang-switch-zh.png create mode 100644 assets/lang-zh-active.png delete mode 100644 assets/lang-zh-active.svg create mode 100644 assets/lang-zh-inactive.png delete mode 100644 assets/lang-zh-inactive.svg create mode 100644 scripts/generate_lang_buttons.py diff --git a/README.md b/README.md index a44de05..920c5a6 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ # ComfyUI-Nunchaku QwenImage&ZImageTurboLoraStack

- English -    - 中文 + English中文

A ComfyUI custom node for loading and applying LoRA (Low-Rank Adaptation) to Nunchaku Qwen Image and Z-ImageTurbo models. ComfyUI Nodes 2.0 compatible. **Requires Nunchaku 1.2.0+ and ComfyUI-Nunchaku 1.2.0+ for v4 functionality.** diff --git a/README.zh.md b/README.zh.md index 48294a3..c7d2c31 100644 --- a/README.zh.md +++ b/README.zh.md @@ -1,9 +1,8 @@ # ComfyUI-Nunchaku QwenImage&ZImageTurboLoraStack

- English -    - 中文 + English中文

用于 Nunchaku Qwen Image 和 Z-ImageTurbo 模型的 ComfyUI 自定义节点,支持加载和应用 LoRA(低秩适配)。兼容 ComfyUI Nodes 2.0。**v4 功能需要 Nunchaku 1.2.0+ 和 ComfyUI-Nunchaku 1.2.0+。** diff --git a/assets/lang-en-active.png b/assets/lang-en-active.png new file mode 100644 index 0000000000000000000000000000000000000000..effc1a6d62ea491683dc053e2c1a529340d0cf48 GIT binary patch literal 681 zcmV;a0#^NrP)i6# zp>i1i(r9EfX-U^<-t8I4$M^!(ixHs#rdKpb6i~D(9{$ z?M$ipuIt(aug2#~h=W^CQ*^YgWy88^>isL|+SkaXhf|U`yOYZ+`tMH`%Lm)*+1%_C zaXKuX;}c&Pj;9xYv;lpc%~W{|WT>?HsuJKz>?7@){M6NW+1Rj(BfHk4EK3q+cRqj1 zF%bJuET8CT!0+?wEiN1k7;cdF==Cfw$L5QByB)1-^iSN)Q?;&0UjKtBzGsze2kfvN z0Ek2rWwoD9XBd1kL-+nhXRIp2!GPhG)ZKZWV*JyBbG8F+nd|b(;@rJSl(L-jMyj1p z3fxZNbfDyRz)eG@ - - - - - - - - EN - diff --git a/assets/lang-en-inactive.png b/assets/lang-en-inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..2b01f2e5176b62815b1b360c152394d958329889 GIT binary patch literal 617 zcmV-v0+#)WP)F|9LGQNTBpEnd5Lm~*fKZpR9lNTu`CEeFxFyeqrgK!1$jvD-laoy@(@vwBv?|0 z5K$~em;PBTwgicl8bLy8y5wGVJ2jVMQncw&Q-p;-SA;kZ~`I||( z{CHWn&JuAyWkuJo)m^J1t5&)IM3yT}!u&-UE%5TQ2?5g365pbsyM&!VRDKG*++^>8yOlN;p^(>QmI}nz&&KSdy^uda+da(7-hklBV zeTP267MX$j=0x%WaCl$Q>A$Gdzb*t_oDM$<@elX`$i}~QT&&*p00000NkvXXu0mjf D>N`4G literal 0 HcmV?d00001 diff --git a/assets/lang-en-inactive.svg b/assets/lang-en-inactive.svg deleted file mode 100644 index 7925383..0000000 --- a/assets/lang-en-inactive.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - EN - diff --git a/assets/lang-switch-en.png b/assets/lang-switch-en.png new file mode 100644 index 0000000000000000000000000000000000000000..d7798eedcb8d76ac245ec8083c89ae9b6385c8d7 GIT binary patch literal 1751 zcmV;|1}OQ7P)m(UL++TkW)HS{h~hrmZJW*&Y zK@gfFN_`p?ZQWs)t`h`^jto~CMR0bzJyN>2>9JN;7ytLOlh#VqMuDbrXcf6P;K%L2x1ewQ{Oh zH$iaS)KV;*Ah-|_oFKT+ms4fAmLRy!mlF#o2rk4!xhDB34dlN=&AUiMT8bfa+7# z?Al$T)rEELgh4fM_O_);N=o-?<)FX-e2qo`{QX<&KT25>K+%ct%)sLFT(cZVcXE9( zkP4it?FSkd{?Gr*fEhC6>rdM@CcM49wX)4-W8a@;S~)l<5Jfq&Rjk5d;qc*dhkNvk zHPbKF41nEkXX-zQSrtPkEs@y{z1Ecl6Bh zVO$wwI&C6z4~}~J!`-9wJfO2)?A78#+%L|o2`)P)pRuDyVKn+^^?&W(&*tKvwQ^#@ zAW3{TBzL~?D}_6cUr-w#FO~G`LwR8S4lzUSHa+Ryjez#;DEn(am6erzzj8IBM<#3a zD>8n-ZntZ`TTHK>NFJ_LTsbt!A#HHrz(D|Zmz0vV zK3l6BHDb7fk0^p`f`_$a^%k4m%b>GQQQd3 zd1pTL&BL7wgTX-R*fGq0b1neef7{99&&=d-`4IrTyjn3n?FM9Nmky{tWnXlVn|}VR<02nz=X6L2@Gg2g44?z-E+4eV|niBdB3W_jFe6oR7FNH z4WEY#2@cZ!f&v2^>Vty<9qLV{3-hUa^*B2_rK&1cH+eT_i-}SK%wD#aLEZf^`Fao$ zd=cZ4+GDfJzFTyhhpXYli3+~@W(BL)W^s04%*F>xKj!COw~?AM27f<45u6@4a-y2o zmX-2MT4w<67#2*??&G48|H-r|_tm@YzgLyihUMf*)~wB9MMfqS6&CGtqtS&Bx~=Zca_% z;Ro-hZJX1pgDws2$g@w(;EExG9rAA$i-nBLRXp+R3*_c+LJz0wG^?}#K-|>)I<^1f zpp|*w?PJolAu_skNdLaErWNmmVCUac5+!}Sb~AIO)> zmQz@?MXMW{G?=(PG5Yl3q9enVqOCjZx4m25>>ujVHDz37Hqj--M@BgMTdZ*Vgfw2B zJqL5|Xoe)l*xS8Vz4xBMaVnygtLysqc+Hb*9Re5vmY002ovPDHLkV1jzMXy^a{ literal 0 HcmV?d00001 diff --git a/assets/lang-switch-zh.png b/assets/lang-switch-zh.png new file mode 100644 index 0000000000000000000000000000000000000000..82a456cd997a9a835ccaeac1be2fc9ea88c99320 GIT binary patch literal 1674 zcmV;526g#~P)J zrfStFYT_db)zm7YR#CLzBS4IAd5A(mj}zs@gZ=>=hrofzaSQxD$tF9@&K^5E-~G+} zezQ9u2!bF8%@I|73SCOQRw7j=2;k@It+I;X%0=eY=@qGE8`8=_Tjg&KTDx9SGYYU? zDphK2$Jo_XY$7y4uuMrwiEnMfvlF2SLgNWfEn*V{>k6+{!HL)e!8%kcI1!s5SjWn# z#pN#uHnMQil@tW)S~;~;halLqV$=|gwm0Dq>1Pm<>TVq^gYW@!!3)hvA-Fpv4V0G`jB<6zlV?q@g-xRs@U2I8yv z-LX`7D~-TpAXh0uYf%>NR$4l-aVH2K94KEyQL?Xf3Wwxi|U%Z})u*H&@qYcWrgK(blBP$}e&5Q#wC4ZE0kr{#0Ux zd28ds>$`t3rBg>tPbzs*WJbYZ$(oKNlbG*Pg44!C+w9j$O=|HA8Gr z6XRiGGEXw^q3!62+Chu^xZz}P-eb!5m@vX5HbdGS^5c_`z_+a~P_0I5Zx6tQOUWdj zzbGx3Cii{|xqA;)2rMiF?aS=|aP;Yd>+nIQyqvB3prk|uXTx`q7#194N=NP7&EvvC zX~a#8`v;HlB=a5sDy=;o7tTb}+KG+}XPT^A!NtqyjwK*rfrcKHSL3mq|M_S5_Uuuu z;6jEDA>mvS**Q5p(COH-FNR4I!lV^j0k5TVEav+j*igR*=Tjqh*GA#BY#snky?p4l zemV9YrDO8qLIYWAHp^T}MLbpPG=xtYZ%W4cd6c-muD{f$lvU4%q%B{u!9QSucsBGyrqolE{d=jgm-Hujz#CV_fR{|JwXqqu+Y7`nqJDZH71QdZfi zG=@vd$Z8QcGyLQ6Xti2t)e5EU;CJ!f7=e3eNF}iuA3h>0atk--EvG2EbmrFMtGBo| zeGz&44p)l5X`CJL2n(Ux@88kpeSe!?PjTco%`Yqf@W;ByI+geEaA)+$;q2NQEv;LD zJUDuqmje6a641MRIv07-vHZ6q2J$6$vI2_oTKB5CQF(!x>R%#zGi8|bof0s2!(&X(#4c6rO>cK<9WgY<=#t>1wRC#rZ`(|Vym--lSLZ^p>AGCK@b$g|AVSZ U{i)S_@c;k-07*qoM6N<$g0gigssI20 literal 0 HcmV?d00001 diff --git a/assets/lang-zh-active.png b/assets/lang-zh-active.png new file mode 100644 index 0000000000000000000000000000000000000000..f09369bf3ba520a4f66e6266260efc323304aab1 GIT binary patch literal 1167 zcmV;A1aSL_P)jPpSi#@KsL|}>=Z+#GPDp_3)~O90L04qWG}3I<$?g`*HK_JupJ9n z#84>@Z3MR7#{TaHK9N)c9G+=!lOwqOz_Lm1+Y+U%7T6?$6Xog}a3-*=0hUN3Yrr$X zG4p{3CHCKdJ+R#;2XB)*I4dwDvDLtR61yFcF1v^aQpWXB9r%pR=O+MT!2TF$nBaTY zN}@{-umR|o3os>sD+6kxqyvTH(t+oI_oMXZ1%3tA1ngB2z&$J3K0OoAq5)%~H79L( zug)l`^gVB4c*I{v?JO$u$vMbD-tu?IF=wjgR61~@ z`8*@t*ZkwAPD@h3>acdxy1XDXSLam*8(KsHjy&#*(Et6>5U4^6+Pjhg&}XHSxO#c8 zt?!#7;PVM^a?wC_ebDPvS`CY~7o(1gWzqKHptlX3`wM%0lSl`qqO{UCqPClV-ZwR; z8}-mrQAyg)E&g&zb`}|5?m}Zq^v@wq7uLN85VcAf%F%QVTUBk)9)kvO^~0}lU9pM; ze5!Ky_TwFPO0u{Zbc^o}ny!Dk!?L&-gC0$?aq@vm(^-u9E5g0e;~_?`6P1%Y%Dz9V zjG7L#zg`kC9f&4%yn%%q3T}c1pi-+z-MkUQ!)AIaDjBue1-QxR^0wVmKGt5>h`p{c z@|+N>$C$qY)4JzT$A#|RcpO6v{8UF$!75Z*jsH)O`#AASbLcx%g{`V4-17yv>5(oi zl|;*O7Fcpo8}wmq!{;y3RrWdV-hKvu`-8x?C3%+ zPxZ{|;AFwmPmsC4jHDMWVbDA`hOw4^O~;m9xO@E-t^Y1vrmbiPwj;;F@;9|XkEzf? z#ux9A@Z{1NubRw>sPcO4X&jAbLqFU#!oT1B!ljqD`lHHm3AWei!usjAv=_gHqw!2w zo9&0=*iZZ}hRW%xlyrZvkMup;aGYwv_G1mB*9UKTn6smc&bL2eenuL`H7n618|kSy zB#RoQEQ`!Sk+tObL6ul6q%cY6HUUmS&?b65T!2#`v^kN-DH@ph;M`5Xl{lA8=G7VE hJtrvhJtsm6)&KLGbdn&xz4!nC002ovPDHLkV1nG|K%)Qv literal 0 HcmV?d00001 diff --git a/assets/lang-zh-active.svg b/assets/lang-zh-active.svg deleted file mode 100644 index 4c102e8..0000000 --- a/assets/lang-zh-active.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - -‡ - diff --git a/assets/lang-zh-inactive.png b/assets/lang-zh-inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..2ddc6b56c07aebf99037ea75ff2d2ceac362abd4 GIT binary patch literal 1164 zcmV;71atd|P)o2+2q(IXHa5w0v6`GNGd0tnYKEDp ziNT~~%BIOQCT4adF4A%pk$|u$OF%;t1ypv~UEA$PAx@!OJL-fug`P5nIE5m_DRizA;uJd9 z32_R=Ln&YM^5szqcD^jPi{E<}PfySPwa@mBF522V=o)Hk(Yu~>vSC6J^|K&@5-V6j+eX>AjyN_W6eS;o#X9U*Y1VO8`7@e-_bEk>ieQY-nQ7-p~HN08puT>A3>@ z{CvfTn=ZLI8_~wcPM8k7zUu|2bfCGljpE%OPq;rxl89NpjQYlA0FE3zc3p9;ZSC@M zbktpLDQ(VORi-3q<>jW9ql}K4oZ^3+J4fda$K|#@Jx!zo?m%=@B!P==0l;dta;U1t zDPCdt7Kg(j&us~DF+!X>AW0H;ug!Ey7X}B<18}mhA7ew49NTd3dZ#&5h;uP|U8+3l zY&IJurDd2*W=i(#l}B6Toe?A_YDGFQ6N*0EJ>xuXGSq4{xtp>ne7_igpHKYCt8cu; z(C`QVUS9KfByTg~mX{k68xzfHy-sdll?ITX_YgsWi$ntM$~Wt%JcDtQVKK-2IKlPBCla0ThpAa`4c0Tj;%yYDV-6gpm z=CLtq>x@(wDlwVN@_LQNhs^Xe4pr4+v)KS>X>FsktDCI#>sX^t$J^UWh`Z4YoHGC7f!)?<9%*#*EnPfyllrjvEgIy4%eaoc-&&Ew(C50arv<*Tp1 zp}nI^j;+niaH+I8b*hvki6`>&c)PF&ZG0@N^*a1~r@m<%x;TV_r?%18f10YA!(12| zCO0P=cPhOS^>GSezMn=C&zzvlN>w3l7F4GSaSAOd_7L5p%o=bZPN8pI@aQ?wD|!s& ez2`)rQ2qiGr=AZKx*DGV0000 - - -‡ - diff --git a/scripts/generate_lang_buttons.py b/scripts/generate_lang_buttons.py new file mode 100644 index 0000000..3a6bee1 --- /dev/null +++ b/scripts/generate_lang_buttons.py @@ -0,0 +1,141 @@ +"""Generate language switcher PNG assets (GitHub-safe, no SVG CJK text).""" +from __future__ import annotations + +from pathlib import Path + +from PIL import Image, ImageDraw, ImageFont + +ROOT = Path(__file__).resolve().parents[1] +OUT = ROOT / "assets" + +W, H = 220, 44 +SEG_W = W // 2 +R = 12 +PAD = 3 + +FONT_EN = Path(r"C:\Windows\Fonts\segoeuib.ttf") +FONT_ZH = Path(r"C:\Windows\Fonts\msyhbd.ttc") +FALLBACK = Path(r"C:\Windows\Fonts\arialbd.ttf") + + +def _font(path: Path, size: int) -> ImageFont.FreeTypeFont: + if path.exists(): + return ImageFont.truetype(str(path), size) + return ImageFont.truetype(str(FALLBACK), size) + + +def _rounded_rect( + draw: ImageDraw.ImageDraw, + xy: tuple[int, int, int, int], + radius: int, + fill: tuple[int, ...], + corners: tuple[bool, bool, bool, bool] = (True, True, True, True), +) -> None: + x0, y0, x1, y1 = xy + if x1 <= x0 or y1 <= y0: + return + tl, tr, br, bl = corners + r = min(radius, (x1 - x0) // 2, (y1 - y0) // 2) + if r < 1: + draw.rectangle(xy, fill=fill) + return + if x1 - r > x0 + r: + draw.rectangle([x0 + r, y0, x1 - r, y1], fill=fill) + if y1 - r > y0 + r: + draw.rectangle([x0, y0 + r, x1, y1 - r], fill=fill) + if tl: + draw.pieslice([x0, y0, x0 + 2 * r, y0 + 2 * r], 180, 270, fill=fill) + else: + draw.rectangle([x0, y0, x0 + r, y0 + r], fill=fill) + if tr: + draw.pieslice([x1 - 2 * r, y0, x1, y0 + 2 * r], 270, 360, fill=fill) + else: + draw.rectangle([x1 - r, y0, x1, y0 + r], fill=fill) + if br: + draw.pieslice([x1 - 2 * r, y1 - 2 * r, x1, y1], 0, 90, fill=fill) + else: + draw.rectangle([x1 - r, y1 - r, x1, y1], fill=fill) + if bl: + draw.pieslice([x0, y1 - 2 * r, x0 + 2 * r, y1], 90, 180, fill=fill) + else: + draw.rectangle([x0, y1 - r, x0 + r, y1], fill=fill) + + +def _draw_segment( + img: Image.Image, + index: int, + label: str, + active: bool, + palette: str, + font: ImageFont.FreeTypeFont, +) -> None: + draw = ImageDraw.Draw(img) + x0 = index * SEG_W + x1 = x0 + SEG_W + box = (x0 + PAD, PAD, x1 - PAD, H - PAD) + corners = (index == 0, index == 1, index == 1, index == 0) + + if active: + fill = (52, 112, 204, 255) if palette == "en" else (212, 68, 94, 255) + _rounded_rect(draw, box, R, fill, corners) + gloss_h = max((box[3] - box[1]) // 2, 6) + _rounded_rect( + draw, + (box[0], box[1], box[2], box[1] + gloss_h), + R, + (255, 255, 255, 42), + corners, + ) + text_color = (255, 255, 255, 255) + else: + _rounded_rect(draw, box, R, (240, 242, 245, 255), corners) + text_color = (82, 90, 99, 255) + + bbox = draw.textbbox((0, 0), label, font=font) + tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1] + tx = x0 + (SEG_W - tw) // 2 + ty = (H - th) // 2 - 1 + draw.text((tx, ty), label, font=font, fill=text_color) + + +def _make_switcher(en_active: bool) -> Image.Image: + img = Image.new("RGBA", (W, H), (0, 0, 0, 0)) + track = Image.new("RGBA", (W, H), (0, 0, 0, 0)) + td = ImageDraw.Draw(track) + _rounded_rect(td, (2, 2, W - 2, H - 2), R + 2, (210, 214, 220, 255), (True, True, True, True)) + _rounded_rect(td, (3, 3, W - 3, H - 3), R + 1, (248, 249, 251, 255), (True, True, True, True)) + img = Image.alpha_composite(img, track) + + font_en = _font(FONT_EN, 22) + font_zh = _font(FONT_ZH, 21) + _draw_segment(img, 0, "EN", en_active, "en", font_en) + _draw_segment(img, 1, "中文", not en_active, "zh", font_zh) + return img + + +def _split_halves(full: Image.Image) -> tuple[Image.Image, Image.Image]: + return full.crop((0, 0, SEG_W, H)), full.crop((SEG_W, 0, W, H)) + + +def main() -> None: + OUT.mkdir(parents=True, exist_ok=True) + + en_view = _make_switcher(en_active=True) + zh_view = _make_switcher(en_active=False) + + en_l, en_r = _split_halves(en_view) + zh_l, zh_r = _split_halves(zh_view) + + en_l.save(OUT / "lang-en-active.png", optimize=True) + en_r.save(OUT / "lang-zh-inactive.png", optimize=True) + zh_l.save(OUT / "lang-en-inactive.png", optimize=True) + zh_r.save(OUT / "lang-zh-active.png", optimize=True) + + en_view.save(OUT / "lang-switch-en.png", optimize=True) + zh_view.save(OUT / "lang-switch-zh.png", optimize=True) + + print("Wrote PNG assets to", OUT) + + +if __name__ == "__main__": + main()