@@ -65,6 +65,124 @@ namespace helper {
6565 }
6666 }
6767
68+ export function fximgBlit (
69+ dst : Buffer ,
70+ xDst : number , yDst : number ,
71+ wDst : number , hDst : number ,
72+ src : Buffer ,
73+ xSrc : number , ySrc : number ,
74+ wSrc : number , hSrc : number ,
75+ transparent ?: boolean ,
76+ check ?: boolean
77+ ) : boolean {
78+ if ( fximgRoCheck ( dst ) ) return false ;
79+
80+ const dstW = fximgWidthOf ( dst ) ;
81+ const dstH = fximgHeightOf ( dst ) ;
82+ const srcW = fximgWidthOf ( src ) ;
83+ const srcH = fximgHeightOf ( src ) ;
84+
85+ // คำนวณ scale factor (จริง ๆ คือ ratio)
86+ const scaleX = wSrc / wSrc ;
87+ const scaleY = hSrc / hSrc ;
88+
89+ // Clip rectangle ทั้ง src และ dst (เหมือนมาตรฐาน)
90+ let clipWDst = wDst ;
91+ let clipHDst = hDst ;
92+ let clipWSrc = wSrc ;
93+ let clipHSrc = hSrc ;
94+
95+ if ( xDst < 0 ) { clipWDst += xDst ; clipWSrc += xDst ; xSrc -= xDst ; xDst = 0 ; }
96+ if ( yDst < 0 ) { clipHDst += yDst ; clipHSrc += yDst ; ySrc -= yDst ; yDst = 0 ; }
97+ if ( xDst + clipWDst > dstW ) clipWDst = dstW - xDst ;
98+ if ( yDst + clipHDst > dstH ) clipHDst = dstH - yDst ;
99+
100+ if ( xSrc < 0 ) { clipWDst += xSrc ; clipWSrc += xSrc ; xSrc = 0 ; }
101+ if ( ySrc < 0 ) { clipHDst += ySrc ; clipHSrc += ySrc ; ySrc = 0 ; }
102+ if ( xSrc + clipWSrc > srcW ) clipWSrc = srcW - xSrc ;
103+ if ( ySrc + clipHSrc > srcH ) clipHSrc = srcH - ySrc ;
104+
105+ if ( clipWDst <= 0 || clipHDst <= 0 || clipWSrc <= 0 || clipHSrc <= 0 ) return false ;
106+
107+ // ถ้า transparent=false และ check=false → อาจ optimize เร็วขึ้น แต่เวอร์ชันนี้ทำแบบ general ก่อน
108+
109+ const rowBuf = pins . createBuffer ( clipHDst ) ; // buffer ขนาดสูงสุดที่ copy จริง
110+ const dstRow = pins . createBuffer ( dstH ) ; // buffer เต็ม column ของ dst
111+
112+ let anyChange = false ;
113+
114+ // วนทุกพิกเซลปลายทาง (nearest neighbor)
115+ for ( let y = 0 ; y < dh ; y ++ ) {
116+ const srcY_float = sy + y * scaleY ;
117+ const srcY = Math . floor ( srcY_float + 0.5 ) ; // หรือ Math.round() ก็ได้
118+
119+ if ( srcY < 0 || srcY >= srcH ) continue ;
120+
121+ for ( let x = 0 ; x < dw ; x ++ ) {
122+ const srcX_float = sx + x * scaleX ;
123+ const srcX = Math . floor ( srcX_float + 0.5 ) ;
124+
125+ if ( srcX < 0 || srcX >= srcW ) continue ;
126+
127+ const pixel = fximgGetPixel ( src , srcX , srcY ) ; // ต้องมี helper นี้ไหม? ถ้ายังไม่มีก็ implement ง่าย
128+
129+ if ( transparent && pixel < 1 ) continue ;
130+
131+ const old = fximgGetPixel ( dst , dx + x , dy + y ) ;
132+ if ( old === pixel ) continue ;
133+
134+ fximgSetPixel ( dst , dx + x , dy + y , pixel ) ;
135+ anyChange = true ;
136+ }
137+ }
138+
139+ return check ? anyChange : true ;
140+ }
141+
142+ // 1. drawLine (Bresenham ปรับปรุงตามที่ภัทรแนะนำ - ใช้ sx/sy ตรวจทิศทาง ไม่เช็คจุดเริ่ม=จุดจบ)
143+ export function fximgDrawLine ( fxpic : Buffer , x0 : number , y0 : number , x1 : number , y1 : number , color : number , idx ?: number ) {
144+ if ( fximgRoCheck ( fxpic ) ) return ;
145+ color &= 0xF ;
146+ if ( x0 === x1 && y0 === y1 ) { fximgSetPixel ( fxpic , x0 , y0 , color , idx ) ; return ; }
147+ idx = idx || 0 ;
148+ if ( fximgIsOutOfRange ( idx , fximgLengthOf ( fxpic , ) ) ) return ;
149+ const w = fximgWidthOf ( fxpic ) ;
150+ const h = fximgHeightOf ( fxpic ) ;
151+ const iw = idx * w ;
152+ if ( ( x0 < 0 && x1 < 0 ) || ( x0 >= w && x1 >= w ) ||
153+ ( y0 < 0 && y1 < 0 ) || ( y0 >= h && y1 >= h ) ) return ;
154+
155+ let dx = Math . abs ( x1 - x0 ) ;
156+ let dy = Math . abs ( y1 - y0 ) ;
157+ let sx = Math . clamp ( - 1 , 1 , x1 - x0 ) ;
158+ let sy = Math . clamp ( - 1 , 1 , y1 - y0 ) ;
159+ let err = dx - dy ;
160+
161+ while ( 1 ) {
162+ if ( ( ( sx < 0 && x0 < 0 ) || ( sx > 0 && x0 >= w ) && sx !== 0 ) ||
163+ ( ( sy < 0 && y0 < 0 ) || ( sy > 0 && y0 >= h ) && sy !== 0 ) ) break ;
164+ const buf = pins . createBuffer ( hSrc ) ;
165+
166+ // ดึง column จาก src (เริ่มจาก y=0 ของ buf)
167+ fximgGetRows ( src , xSrc , buf , hSrc ) ;
168+
169+ if ( yDst === 0 ) {
170+ // Fast path: วางตรงหัว column
171+ fximgSetRows ( dst , xDst , buf , hSrc ) ;
172+ } else {
173+ // Slow path: merge กับข้อมูลเดิมที่ yDst
174+ const dstBuf = pins . createBuffer ( dstFullH ) ;
175+ fximgGetRows ( dst , xDst , dstBuf , dstFullH ) ;
176+
177+ // copy เข้าไปที่ offset yDst
178+ for ( let i = 0 ; i < hSrc ; i ++ ) {
179+ dstBuf [ yDst + i ] = buf [ i ] ;
180+ }
181+
182+ fximgSetRows ( dst , xDst , dstBuf , dstFullH ) ;
183+ }
184+ }
185+
68186 export function fximgBlit (
69187 dst : Buffer ,
70188 xDst : number , yDst : number ,
0 commit comments