1+ import { IInsetParams } from '../components/styleParser' ;
2+
3+ export type ImageRenderMode = 'simple' | 'sliced' | 'tiled' ;
4+
5+ export interface IImageRenderOptions {
6+ img : HTMLImageElement ;
7+ x : number ;
8+ y : number ;
9+ width : number ;
10+ height : number ;
11+ mode : ImageRenderMode ;
12+ inset ?: IInsetParams ;
13+ }
14+
15+ /**
16+ * 图像渲染器 - 统一处理图像渲染逻辑
17+ */
18+ export class ImageRenderer {
19+ /**
20+ * 渲染图像
21+ */
22+ static render ( ctx : CanvasRenderingContext2D , options : IImageRenderOptions ) : void {
23+ const { img, x, y, width, height, mode, inset } = options ;
24+
25+ switch ( mode ) {
26+ case 'simple' :
27+ ImageRenderer . renderSimple ( ctx , img , x , y , width , height ) ;
28+ break ;
29+ case 'sliced' :
30+ ImageRenderer . renderSliced ( ctx , img , x , y , width , height , inset ) ;
31+ break ;
32+ case 'tiled' :
33+ ImageRenderer . renderTiled ( ctx , img , x , y , width , height ) ;
34+ break ;
35+ }
36+ }
37+
38+ /**
39+ * 简单拉伸渲染
40+ */
41+ private static renderSimple (
42+ ctx : CanvasRenderingContext2D ,
43+ img : HTMLImageElement ,
44+ x : number ,
45+ y : number ,
46+ width : number ,
47+ height : number
48+ ) : void {
49+ ctx . drawImage ( img , x , y , width , height ) ;
50+ }
51+
52+ /**
53+ * 九宫格渲染
54+ */
55+ private static renderSliced (
56+ ctx : CanvasRenderingContext2D ,
57+ img : HTMLImageElement ,
58+ x : number ,
59+ y : number ,
60+ width : number ,
61+ height : number ,
62+ inset ?: IInsetParams
63+ ) : void {
64+ if ( ! inset ) {
65+ console . warn ( '[Layout] sliced render need inset parameters' ) ;
66+ ImageRenderer . renderSimple ( ctx , img , x , y , width , height ) ;
67+ return ;
68+ }
69+
70+ const { left, top, right, bottom } = inset ;
71+ const imgWidth = img . width ;
72+ const imgHeight = img . height ;
73+
74+ // 计算源区域尺寸
75+ const centerSrcWidth = imgWidth - left - right ;
76+ const centerSrcHeight = imgHeight - top - bottom ;
77+
78+ // 计算目标区域尺寸
79+ const targetCenterWidth = Math . max ( 0 , width - left - right ) ;
80+ const targetCenterHeight = Math . max ( 0 , height - top - bottom ) ;
81+
82+ // 1. 渲染四个角(保持原样)
83+ ImageRenderer . renderCorners ( ctx , img , x , y , width , height , imgWidth , imgHeight , left , top , right , bottom ) ;
84+
85+ // 2. 渲染四条边(拉伸)
86+ ImageRenderer . renderEdges ( ctx , img , x , y , width , height , imgWidth , imgHeight , left , top , right , bottom , centerSrcWidth , centerSrcHeight , targetCenterWidth , targetCenterHeight ) ;
87+
88+ // 3. 渲染中心区域(拉伸)
89+ if ( targetCenterWidth > 0 && targetCenterHeight > 0 && centerSrcWidth > 0 && centerSrcHeight > 0 ) {
90+ ctx . drawImage ( img , left , top , centerSrcWidth , centerSrcHeight ,
91+ x + left , y + top , targetCenterWidth , targetCenterHeight ) ;
92+ }
93+ }
94+
95+ /**
96+ * 平铺渲染
97+ */
98+ private static renderTiled (
99+ ctx : CanvasRenderingContext2D ,
100+ img : HTMLImageElement ,
101+ x : number ,
102+ y : number ,
103+ width : number ,
104+ height : number
105+ ) : void {
106+ const pattern = ctx . createPattern ( img , 'repeat' ) ;
107+ if ( ! pattern ) return ;
108+
109+ ctx . save ( ) ;
110+
111+ // 设置裁剪区域
112+ ctx . beginPath ( ) ;
113+ ctx . rect ( x , y , width , height ) ;
114+ ctx . clip ( ) ;
115+
116+ // 设置pattern并填充
117+ ctx . fillStyle = pattern ;
118+ ctx . fillRect ( x , y , width , height ) ;
119+
120+ ctx . restore ( ) ;
121+ }
122+
123+ /**
124+ * 渲染九宫格的四个角
125+ */
126+ private static renderCorners (
127+ ctx : CanvasRenderingContext2D ,
128+ img : HTMLImageElement ,
129+ x : number ,
130+ y : number ,
131+ width : number ,
132+ height : number ,
133+ imgWidth : number ,
134+ imgHeight : number ,
135+ left : number ,
136+ top : number ,
137+ right : number ,
138+ bottom : number
139+ ) : void {
140+ // 左上角
141+ if ( left > 0 && top > 0 ) {
142+ ctx . drawImage ( img , 0 , 0 , left , top , x , y , left , top ) ;
143+ }
144+
145+ // 右上角
146+ if ( right > 0 && top > 0 ) {
147+ ctx . drawImage ( img , imgWidth - right , 0 , right , top ,
148+ x + width - right , y , right , top ) ;
149+ }
150+
151+ // 左下角
152+ if ( left > 0 && bottom > 0 ) {
153+ ctx . drawImage ( img , 0 , imgHeight - bottom , left , bottom ,
154+ x , y + height - bottom , left , bottom ) ;
155+ }
156+
157+ // 右下角
158+ if ( right > 0 && bottom > 0 ) {
159+ ctx . drawImage ( img , imgWidth - right , imgHeight - bottom , right , bottom ,
160+ x + width - right , y + height - bottom , right , bottom ) ;
161+ }
162+ }
163+
164+ /**
165+ * 渲染九宫格的四条边
166+ */
167+ private static renderEdges (
168+ ctx : CanvasRenderingContext2D ,
169+ img : HTMLImageElement ,
170+ x : number ,
171+ y : number ,
172+ width : number ,
173+ height : number ,
174+ imgWidth : number ,
175+ imgHeight : number ,
176+ left : number ,
177+ top : number ,
178+ right : number ,
179+ bottom : number ,
180+ centerSrcWidth : number ,
181+ centerSrcHeight : number ,
182+ targetCenterWidth : number ,
183+ targetCenterHeight : number
184+ ) : void {
185+ // 上边 - 水平拉伸
186+ if ( top > 0 && targetCenterWidth > 0 ) {
187+ ctx . drawImage ( img , left , 0 , centerSrcWidth , top ,
188+ x + left , y , targetCenterWidth , top ) ;
189+ }
190+
191+ // 下边 - 水平拉伸
192+ if ( bottom > 0 && targetCenterWidth > 0 ) {
193+ ctx . drawImage ( img , left , imgHeight - bottom , centerSrcWidth , bottom ,
194+ x + left , y + height - bottom , targetCenterWidth , bottom ) ;
195+ }
196+
197+ // 左边 - 垂直拉伸
198+ if ( left > 0 && targetCenterHeight > 0 ) {
199+ ctx . drawImage ( img , 0 , top , left , centerSrcHeight ,
200+ x , y + top , left , targetCenterHeight ) ;
201+ }
202+
203+ // 右边 - 垂直拉伸
204+ if ( right > 0 && targetCenterHeight > 0 ) {
205+ ctx . drawImage ( img , imgWidth - right , top , right , centerSrcHeight ,
206+ x + width - right , y + top , right , targetCenterHeight ) ;
207+ }
208+ }
209+ }
0 commit comments