你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【安富莱STemWin教程】第20章 XBF外置字体方法(官方推荐)

[复制链接]
baiyongbin2009 发布时间:2015-1-29 11:59
特别说明:完整STemWin的1-60期教程和配套实例下载地址:链接, i7 s1 K2 X3 b, b0 B, V
第20章 XBF外置字体方法(官方推荐)

& M4 e8 E7 p: E  L) _" J
    官方给的这种外置字体方法非常好,而且还可以支持抗锯齿,显示效果非常好,本期教程就是教会大家这种方式。用FontCvt生成的XBF格式字体文件可以在外部存储器,本期教程就以SD卡为例跟大家讲解。
    20. 1  XBF格式字体生成方法
    20. 2 移植到开发板上显示
    20. 3 总结
5 ~0 D1 m3 X0 b" m; {, w
20.1 XBF格式字体生成方法
    这里我们使用FontCvt生成一种微软雅黑字体,字体选择36号并选带扩展的4位抗锯齿效果。
20.1.1 第一步:选择带扩展的4位抗锯齿
20.1.png
20.1.2 第二步:选择字体类型和大小
20.2.png
20.1.3 第三步:另存为XBF格式文件
20.3.png
20.4.png
    此过程字体生成的时间有点长,大家要耐心等待,生成后文件大小:
20.5.png
20.2 移植到开发板上显示
    移植到开发上的程序主要分为两部分,一个是从SD卡中读取字体的驱动,另一个建立一个对话框显示字体。
20.2.1 创建XBF字体
  1. GUI_XBF_DATA XBF_Data;
    + ]! z7 T# m% ~9 d
  2. GUI_FONT     XBF_Font;' D, q; \3 R, ]+ ^7 e0 [
  3. FIL          Fontfile;
    3 X! n1 X$ Z# d( X  S4 h$ t* R5 d

  4. % f5 m' E$ M" f9 {  O
  5. /*
    ) C0 X& n" k( I5 r2 v
  6. *********************************************************************************************************- M3 F. I& z& |+ s) i
  7. *
    6 N  [/ t7 ^7 h7 N5 R9 Z
  8. *       _cbGetData
    ( C5 b8 L$ p0 D6 T7 j# d
  9. *
    1 k9 g' w. S$ Q- k
  10. * Function description
    & ~: W& M* |0 d% n8 z, Q, H9 B
  11. *   Callback function for getting font data
    - F- V7 d8 L2 L
  12. *
    7 z0 U1 a) F2 ~
  13. * Parameters:
    2 b. J3 ~9 }2 L7 \7 S- W
  14. *   Off      - Position of XBF file to be read9 h1 L4 r  R: ^# f3 b
  15. *   NumBytes - Number of requested bytes
    $ ?! j- u& F3 F  N3 f5 R8 m
  16. *   pVoid    - Application defined pointer1 C* V! E8 ?! M1 k
  17. *   pBuffer  - Pointer to buffer to be filled by the function! P: r: j2 \% l% }' H$ @
  18. *6 k5 M2 _! |& [( w7 a6 R2 R
  19. * Return value:  i8 |/ w5 I* N. F6 [
  20. *   0 on success, 1 on error: m6 R) Y7 W; k- [: ^0 y2 F
  21. *********************************************************************************************************
    : I8 W/ D3 F0 o8 I
  22. */( |4 i, C7 v# N- d' N( C
  23. static int _cbGetData(U32 Off, U16 NumBytes, void * pVoid, void * pBuffer) (1)
      @+ ~: i' ~/ e  p& K2 D
  24. {& q$ `+ i; h* B' o" f# S
  25. FIL *FontFile;1 G) w3 |3 T% i0 r" _1 ~9 [$ z! D# f
  26. ) L# q- P* U" k  I+ X6 i, c/ |% t9 l# q' [
  27. /* The pVoid pointer may be used to get a file handle */: B; x. H# z3 Z$ d/ L: ?
  28. FontFile = (FIL *)pVoid;
    8 \) m0 v1 k# B' V3 q, v9 P

  29. % B5 w" @: y1 P  Z  \6 ]# F; B
  30. /*
    ( s! d0 v% v" Z9 ]' m* i3 L$ S
  31. * Set file pointer to the required position
    ( t# i8 ^4 K' m5 m8 q: j- f* B
  32. */1 C8 V3 Q; Q1 p7 U1 |$ G
  33. result =f_lseek(FontFile, Off);
    5 M5 {  w) f% h- G
  34. if (result != FR_OK) ! H1 a; A4 O2 X4 q1 K4 n3 Y' t
  35. {  b9 n9 a' l0 l
  36. return 1; /* Error */4 s8 a& _- F( w0 M) G0 K7 v- h
  37. }
    9 E! \5 L) F0 S& f
  38. , g# G5 N) X# N, u9 b  J, n
  39. /** _( p$ E, E% A7 \  @4 x+ }
  40. * Read data into buffer
    ' X/ |, r. Y" |4 l: P& t
  41. */6 s4 G1 a  z& {. A2 m( H
  42. result = f_read(FontFile, pBuffer, NumBytes, &bw);- o4 Z: e, y) t
  43. if (result != FR_OK)
    , X& r; b* J4 T8 j6 \$ `( l; n: `
  44. {% ?0 {, ]! x& c
  45. return 1; /* Error */
    9 r5 [* K; L- j6 T$ L
  46. }
    8 d9 p* X: e( s: p
  47. return 0;7 ]* X& Q, @" f7 g; E0 S
  48. / {  t% w* M0 x
  49. }5 R  ~2 l! Z5 N) ^" Q
  50.   |4 A# P, O6 L* V, f! t  R
  51. /*/ w! T" M1 x9 X0 {- B
  52. *********************************************************************************************************
    5 l# s8 r& @/ s8 G
  53. *        函 数 名: _ShowXBF$ C  z3 T* [' a
  54. *        功能说明: 使用XBF字体
    7 m9 t) l' }0 n% y- c3 p
  55. *        形    参:无
    5 F6 ^5 `7 ^; X  j9 y0 R
  56. *        返 回 值: 无/ k9 K5 M  [' D! Z; V6 R" n% b
  57. *********************************************************************************************************
    0 y" [+ [7 Z9 ?9 \6 S5 r
  58. */
    ' @/ i5 |6 l9 Y  ~
  59. static void _ShowXBF(void)
    * `7 |9 z+ b$ P. \
  60. {8 i/ y4 _* m0 `& c$ T3 M
  61. result = f_open(&Fontfile, "YaHe.xbf", FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);(2)
    $ s# w9 o# T: ~9 f
  62. if (result != FR_OK)
    ! _, ~1 q$ T& B4 X4 q* ^
  63. {
    ( i2 U0 Y; I( _8 C' ]% O: W, ^
  64. return;
    5 h4 \, m) m# V: ~
  65. ) B- Z! E2 L1 h& I( U5 T# s" M
  66. }, V  M+ f% b* y8 I  T( w+ R6 O

  67. ' _9 |5 P  C) r9 L1 i
  68. //% e0 d, ?8 Y8 C: i1 F4 B
  69. // Create XBF font
    - n' \8 l5 a* j/ }7 x
  70. //
    8 f5 H, v4 Y7 I6 o9 i% k
  71. GUI_XBF_CreateFont(&XBF_Font,       // Pointer to GUI_FONT structure in RAM(3)
    - d; Q% }; T$ U6 D# e% `
  72. &XBF_Data,         // Pointer to GUI_XBF_DATA structure in RAM
    ) O' K% m' H$ g
  73. GUI_XBF_TYPE_PROP_AA4_EXT, // Font type to be created
    - E4 Y" K' y$ _( b
  74. _cbGetData,        // Pointer to callback function' L0 i3 ^9 g( y8 t+ R. Y5 F
  75. &Fontfile);        // Pointer to be passed to GetData function
    % d$ h" |, P$ [/ N* f
  76. }
复制代码
1. 从SD卡中读取字体文件的方法。
2. 由于没有开启FatFS的长文件名,文件的名字要符合8.3格式。
3. 创建XBF_Font字体。默认情况下,每个字符的数据字节最大值限制为200。这应该满足大部分要求。如果加载使用更多字节的字符,在调试版本中将生成警告。通过向文件GUIConf.h添加以下定义可增加默认值:
    #define GUI_MAX_XBF_BYTES 500 // Sets the maximum number of bytes/chars to 500
    默认的定义在文件GUI_ConfDefaults.h文件里面:
    #ifndef   GUI_MAX_XBF_BYTES
      #define GUI_MAX_XBF_BYTES 200
    #endif
20.2.2 主函数
  1. /*
    % y8 h( y: L4 j$ R
  2. *********************************************************************************************************5 b% j$ f; |5 q  D" w+ Z: E( ]6 s6 X
  3. *        对话框信息: i! m) C7 @3 {3 a
  4. *********************************************************************************************************8 c- r, G; e7 F0 C
  5. */' X9 \- K( N% |" ?
  6. static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {0 Q* i+ h, l/ w0 p! `
  7.     { FRAMEWIN_CreateIndirect,  "armfly",            0,                       0,  0,  800,480,FRAMEWIN_CF_MOVEABLE,0},1 f: w$ N/ ~* R  K; I2 ?, p; E
  8.     { BUTTON_CreateIndirect,    "安富莱电子",        GUI_ID_BUTTON0,          390,40,360,100,0,0},
    6 D! f) y! U+ _0 @; x
  9.     { TEXT_CreateIndirect,      "安富莱电子",        GUI_ID_TEXT0,            5, 10, 300, 70, 0,0},
    6 E8 G9 _' d$ n
  10.     { TEXT_CreateIndirect,      "安富莱电子",        GUI_ID_TEXT1,            5, 80,300, 70, 0,0},
    " g7 F0 }8 n. H. _
  11.     { TEXT_CreateIndirect,      "安富莱电子",        GUI_ID_TEXT2,            5, 160,300, 70, 0,0}+ C8 P5 G- ?& A; ~7 _+ i; ]
  12. };
    , m8 b/ d8 u! p& J, }

  13. # E* U( U% S, ]6 w9 f5 o
  14. /*
    7 P8 F5 X2 Y# X0 u" h
  15. *********************************************************************************************************. a9 y7 i- q" V, X  b
  16. *        函 数 名: PaintDialog
    ; {. }( F& O/ P  `- {
  17. *        功能说明: 重绘函数" A! r( x& x2 _, D- D
  18. *        形    参:pMsg 消息指针; q9 A* K6 Z+ Q/ K1 }- I
  19. *        返 回 值: 无
    ( q. V$ u) X* ~2 L
  20. *********************************************************************************************************( R$ h3 m7 n  g& h; @1 E2 S
  21. */
    + v+ ]2 I$ |2 O/ [2 Y
  22. void PaintDialog(WM_MESSAGE * pMsg): {, \: c) K# L
  23. {8 I. k' y1 J  E
  24.     WM_HWIN hWin = pMsg->hWin;
    * k8 s$ C9 u& s  F
  25. }4 ?* X* W3 i# K! R8 z' r4 Y
  26. - R) a/ L% Y& b( O  {9 O& H7 d
  27. /*
    4 g. }; [, o8 r8 N
  28. *********************************************************************************************************$ N. O3 C" x  J% G8 E( o) o
  29. *        函 数 名: InitDialog0 v6 y4 M: N/ a+ t. y
  30. *        功能说明: 对话框初始化
    * ]$ x& T# w' F! l7 c% S- j
  31. *        形    参:pMsg 消息指针/ \* _  u4 e4 O
  32. *        返 回 值: 无
    ; ~+ ~0 B) O( j& F7 |# M
  33. *********************************************************************************************************. x: Z/ e5 h% `% i
  34. */( e' o+ {' {: ]$ y
  35. void InitDialog(WM_MESSAGE * pMsg)# p0 |5 ^' E# A/ }4 y, L
  36. {
    ) B! }) e- w1 v9 Y
  37.     WM_HWIN hWin = pMsg->hWin;
    6 o6 D2 z/ N3 @2 ]
  38.     //
    0 T% d" q5 Z1 ^. L
  39.     //FRAMEWIN/ ^/ B* a6 K* B" A  G8 U3 q0 q2 A
  40.     //
    1 T3 }' g/ Z3 y& h8 N
  41.     FRAMEWIN_SetFont(hWin,&GUI_Font32B_ASCII);! J( L. ~8 M2 W) i, D* M
  42.     FRAMEWIN_SetTextAlign(hWin,GUI_TA_VCENTER|GUI_TA_CENTER);( g/ F/ L9 B+ f1 V9 T
  43.     FRAMEWIN_AddCloseButton(hWin, FRAMEWIN_BUTTON_RIGHT, 0);/ ]3 C+ g( B) z( N3 e
  44.     FRAMEWIN_AddMaxButton(hWin, FRAMEWIN_BUTTON_RIGHT, 1);: @. b- c6 C+ e3 x+ k  u: Q
  45.     FRAMEWIN_AddMinButton(hWin, FRAMEWIN_BUTTON_RIGHT, 2);0 i% ]/ ~# D1 Y% P6 G
  46.     FRAMEWIN_SetTitleHeight(hWin,35);
    ( H. u" g2 I6 Y: o
  47.     //) H' r5 e; \" C6 |1 X/ J
  48.     //GUI_ID_BUTTON0: K6 \: F" u8 e9 [
  49.     //
    $ f7 B' V. ^* t3 E* ]
  50. _ShowXBF();(1)% _9 ^$ f% v/ w5 W
  51. GUI_UC_SetEncodeUTF8();(2)  v$ B) M* I7 d; |7 m! J9 u
  52.     BUTTON_SetFont(WM_GetDialogItem(hWin,GUI_ID_BUTTON0),&XBF_Font);(3)
    2 v" N  u- h$ K5 q9 @# H
  53.     //2 C7 @( K+ I6 ~: D
  54.     //GUI_ID_TEXT08 b' N+ V; V! y, d* s6 ?* {9 p
  55.     //4 h5 `8 v# r' W3 M: _. b
  56. TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT0), GUI_RED);
    $ D& D( f* [3 g2 x/ t% G8 m1 b
  57.     TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT0),&XBF_Font);" v- ^9 ~! s* j
  58. TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT1), GUI_GREEN);
    6 I. L/ B5 ^+ y& `
  59. TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT1),&XBF_Font);
    ! S! D1 _/ Z8 A  G
  60. TEXT_SetTextColor(WM_GetDialogItem(hWin,GUI_ID_TEXT2), GUI_BLUE);
    " W' O3 ]- _1 j
  61. TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT2),&XBF_Font);
    " l! _# c) a' N' H6 Y
  62. //         GUI_UC_SetEncodeNone();: H: b% E, O: I' _: ~) m7 r
  63. }$ }2 C! I: {! G( ?! k1 t
  64. ! [) ]( u, _, P" @7 q7 k% l
  65. /*
    3 Q: o! ?* V" L0 w' r7 j1 h
  66. *********************************************************************************************************
    0 B+ X$ W4 ]- Q6 i  ^+ G5 p  P
  67. *        函 数 名: _cbCallback
    6 ]/ I; O& {- Q; L) |
  68. *        功能说明: 对话框回调函数7 p. f: M4 z1 T6 y! Z6 K
  69. *        形    参:无3 P7 l: {. A' H7 L# F5 C( a
  70. *        返 回 值: 无9 W  V& \. y7 ]! Q9 B# {6 ^$ N
  71. *********************************************************************************************************
    * F$ p5 r) r5 N0 O1 F0 j/ [
  72. */
    * y) p- S" R) m$ d1 H
  73. static void _cbCallback(WM_MESSAGE * pMsg) 3 ?" K5 s( R3 Q! ]
  74. {- F3 L+ \. M3 Q6 o
  75.     int NCode, Id;
    ! P( p: \* b$ D3 W, [- t, g3 ~! Q
  76.     WM_HWIN hWin = pMsg->hWin;
    % |; o, J; f- D
  77.     switch (pMsg->MsgId)
    , _; I9 ?9 D( L4 h3 @
  78.     {
    & E8 A  Z0 h. V) |
  79.         case WM_PAINT:
    8 v2 _$ \0 K# b6 j% l7 q# V4 D
  80.             PaintDialog(pMsg);
    6 b( n) I: b  f9 A% U
  81.             break;
    # G% Z( K6 G: h; v9 s- r
  82.         case WM_INIT_DIALOG:
    : h, V4 j( I$ {6 z9 ?3 t- Z
  83.             InitDialog(pMsg);# f: }( A5 }& C  i4 h
  84.             break;3 j3 n0 J0 e- a: n$ c! s
  85.         case WM_KEY:( {1 @0 F8 q1 t) k( ]
  86.             switch (((WM_KEY_INFO*)(pMsg->Data.p))->Key) 0 N* T, a" S# ?# L" m* ^
  87.             {; z& f/ G. c" t* `7 I" J6 u% k
  88.                 case GUI_KEY_ESCAPE:! [& ]' p! ^; S# J" ~
  89.                     GUI_EndDialog(hWin, 1);( }* S: W) e( P: R$ w) v4 V; @& [* r- ]
  90.                     break;' e4 y7 t: D7 y
  91.                 case GUI_KEY_ENTER:
    + ?% I- }9 p' {5 s. j7 \* D( J# [2 e
  92.                     GUI_EndDialog(hWin, 0);
    7 X. J4 G7 d( v# M! L
  93.                     break;5 B% [6 G" T2 G( @
  94.             }0 s( x# A7 S( z0 a: z
  95.             break;0 b0 w4 a/ N- f
  96.         case WM_NOTIFY_PARENT:  B9 O, j2 L# P. }- ~5 G2 e& H
  97.             Id = WM_GetId(pMsg->hWinSrc);
    ) m) g4 e! o: i( M+ H1 \+ l
  98.             NCode = pMsg->Data.v;        
    ! V# X/ e$ F; J6 _0 G: Z/ ?) |1 r) }
  99.             switch (Id)
    ) [/ A( Y9 t1 f/ S( Z5 o
  100.             {. P) M, r$ ]  @8 X' H
  101.                 case GUI_ID_OK:2 R) T1 g$ ~7 ?& x
  102.                     if(NCode==WM_NOTIFICATION_RELEASED)/ L4 z4 k3 T" \+ Z- N6 Z( d" `3 T  _
  103.                         GUI_EndDialog(hWin, 0);2 t$ z. J/ w4 k; _2 `4 e
  104.                     break;' @8 K$ r0 V( ~1 k2 H, k! m
  105.                 case GUI_ID_CANCEL:
    4 {* [1 y# j9 z3 j2 f" A" z
  106.                     if(NCode==WM_NOTIFICATION_RELEASED)1 J+ @' e6 X: Y# l7 A
  107.                         GUI_EndDialog(hWin, 0);
    $ F( I5 Y8 [4 m  D3 p% P! N; b$ k
  108.                     break;; _& X: M( w! T, \0 J
  109. - A  B# |4 P, a8 s  N1 }
  110.             }3 j/ K: c: v: q+ t6 @" s8 G+ ]
  111.             break;4 M0 L  I: J* g% ~( W1 \9 a9 W) W- n! x
  112.         default:
    8 J3 P" Z* n6 j. b  j
  113.             WM_DefaultProc(pMsg);. A( f3 {  F6 }, o) I
  114.     }5 {: X( y8 d  |8 j2 `0 K+ a
  115. }
    : ^  F7 Q$ O* Z6 l. R8 P( j$ {/ p9 A
  116. 2 R" V8 H' J3 T9 \% s# u+ e
  117. ' {- N) t, Z! Z  Q0 d2 H4 H  t
  118. /*, L8 P( K! N* X* S/ X, k! T
  119. *********************************************************************************************************
    + s( F3 J0 [- h% I  p
  120. *        函 数 名: MainTask2 _) @' q6 _8 l0 D
  121. *        功能说明: GUI主函数6 l4 m) C* N3 q- ~  L& q
  122. *        形    参:无
    ( N( A% n. V! I# \5 a
  123. *        返 回 值: 无: I8 @$ u0 k; p
  124. *********************************************************************************************************
    1 E; ^. n! M1 U" P6 j4 P5 T: C/ g
  125. */
    5 `# D% O* N0 O' x' Z$ X6 j7 r' ?
  126. void MainTask(void) 3 B/ A4 k) O+ |/ L
  127. {
    . e7 Z3 q/ a" N) r
  128.     GUI_Init();
    9 z1 w/ C$ z2 b3 ]1 i2 P+ H
  129.     WM_SetDesktopColor(GUI_WHITE);       /* Automacally update desktop window */
    8 `7 O. w* V0 Y2 D
  130.     WM_SetCreateFlags(WM_CF_MEMDEV);     /* Use memory devices on all windows to avoid flicker */- j: M4 q. A- ]  y9 M0 a! v& N9 X
  131. PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX);
    . a6 i$ A& b  o7 M
  132. FRAMEWIN_SetDefaultSkin(FRAMEWIN_SKIN_FLEX);/ Z1 A9 v& E! o) `
  133. PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX);7 |+ `9 e. C9 {+ H/ C
  134. BUTTON_SetDefaultSkin(BUTTON_SKIN_FLEX);
    * [# T& F3 G7 N1 n) Z
  135. CHECKBOX_SetDefaultSkin(CHECKBOX_SKIN_FLEX);
    ! h/ Y9 H2 N6 u& t8 q
  136. DROPDOWN_SetDefaultSkin(DROPDOWN_SKIN_FLEX);
    & q* R6 N0 Y  k; G' w1 U
  137. SCROLLBAR_SetDefaultSkin(SCROLLBAR_SKIN_FLEX);) ]; O7 p( j$ C* F) @7 m+ V) ~
  138. SLIDER_SetDefaultSkin(SLIDER_SKIN_FLEX);
    4 T+ T: q# F: V0 Y. K
  139. HEADER_SetDefaultSkin(HEADER_SKIN_FLEX);" e9 ~, ^7 J  E9 m0 o- p  l4 V
  140. RADIO_SetDefaultSkin(RADIO_SKIN_FLEX);
    + J( `3 s: [4 M; i2 \' O4 V- J
  141.     GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), &_cbCallback, 0, 0, 0);
    * C8 T. |* s$ S# y9 a$ f8 [+ A/ {
  142. while(1)
    ; Y/ I9 {( _  p8 I( _
  143. {$ l8 s1 F+ m- m, D. H/ E- n
  144. GUI_Delay(10);: K! ?8 Y3 X/ n+ z1 B7 B
  145. }
    1 P; I" ^& `) N. L$ S& d
  146. }<span style="font-family: 新宋体; font-size: 9pt; line-height: 1.5;"> </span>
复制代码
1. 创建XBF字体。
2. 使能UTF-8解码
3. 在按钮中显示的字体使用XBF字体。
4. 还有最重要的一条,上面的这些函数都是在MainTask.c文件里面的,这个文件的编码格式必须得是UTF-8,设置方法在前面18.1.6小节有说明。
    实际显示效果如下:
20.6.png
    特别注意,如果使用的是800*480分辨率的屏可以完成显示出来,如果是小于这个分辨率的屏只能显示出一部分,大家可以按照上面的设计方法做一个适合自己屏大小的显示或者直接拖动这个对话框即可。
20.3 总结
    推荐大家在以后的工程中采用这种方式,这种显示方式有个问题就是显示速度有点慢。比如本期教程显示微软雅黑36号字体,4位抗锯齿。显示就有缓慢,显示小字体不带抗锯齿还是没问题的。
9 I" b  T( ?8 ?/ m  }
收藏 评论1 发布时间:2015-1-29 11:59

举报

1个回答
stary666 回答时间:2015-1-29 12:26:52

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版