@@ -5,7 +5,8 @@ import path from 'path'
55import { fileURLToPath } from 'url'
66
77/**
8- * Crop QR code image - cut 340px from top, 230px from bottom, 100px from left, 100px from right
8+ * Crop QR code image - cut 350px from top, 100px from bottom, 120px from left, 120px from right
9+ * Create 3-paper stack effect with rotated background papers
910 * Uses pure Node.js with Canvas API for image processing
1011 */
1112
@@ -17,8 +18,9 @@ const __dirname = path.dirname(__filename)
1718
1819async function cropImage ( ) {
1920 try {
21+ const fix = process . env . TEST ? '-test' : ''
2022 const inputPath = path . join ( __dirname , '../src/static/electerm-wechat-group-qr.jpg' )
21- const outputPath = path . join ( __dirname , '../src/static/electerm-wechat-group-qr.jpg' )
23+ const outputPath = path . join ( __dirname , '../src/static/electerm-wechat-group-qr' + fix + ' .jpg')
2224
2325 // Check if input file exists
2426 if ( ! fs . existsSync ( inputPath ) ) {
@@ -36,7 +38,7 @@ async function cropImage () {
3638 console . log ( `Original dimensions: ${ originalWidth } x${ originalHeight } ` )
3739
3840 // Calculate new dimensions
39- const cropTop = 340
41+ const cropTop = 350
4042 const cropBottom = 100
4143 const cropLeft = 120
4244 const cropRight = 120
@@ -53,25 +55,97 @@ async function cropImage () {
5355 console . log ( `New dimensions: ${ newWidth } x${ newHeight } ` )
5456 console . log ( `Cropping: ${ cropTop } px from top, ${ cropBottom } px from bottom, ${ cropLeft } px from left, ${ cropRight } px from right` )
5557
56- // Create canvas with new dimensions
57- const canvas = createCanvas ( newWidth , newHeight )
58+ // Paper stack settings
59+ const paperPadding = 60 // Extra space for rotated papers
60+ const rotationAngle = 5 * Math . PI / 180 // 5 degrees in radians
61+
62+ // Create canvas with extra space for rotated papers
63+ const canvasWidth = newWidth + paperPadding * 2
64+ const canvasHeight = newHeight + paperPadding * 2
65+ const canvas = createCanvas ( canvasWidth , canvasHeight )
5866 const ctx = canvas . getContext ( '2d' )
5967
60- // Draw the cropped portion of the image
68+ // Fill background with light color
69+ ctx . fillStyle = '#f8f8f8'
70+ ctx . fillRect ( 0 , 0 , canvasWidth , canvasHeight )
71+
72+ // Helper function to draw a paper with shadow
73+ function drawPaper ( x , y , width , height , rotation , shadowIntensity ) {
74+ ctx . save ( )
75+
76+ // Move to center of where paper should be
77+ ctx . translate ( x + width / 2 , y + height / 2 )
78+ ctx . rotate ( rotation )
79+
80+ // Draw shadow
81+ ctx . shadowColor = `rgba(0, 0, 0, ${ shadowIntensity } )`
82+ ctx . shadowBlur = 8
83+ ctx . shadowOffsetX = 4
84+ ctx . shadowOffsetY = 4
85+
86+ // Draw paper
87+ ctx . fillStyle = '#ffffff'
88+ ctx . fillRect ( - width / 2 , - height / 2 , width , height )
89+
90+ // Add subtle border
91+ ctx . shadowColor = 'transparent'
92+ ctx . strokeStyle = 'rgba(0, 0, 0, 0.1)'
93+ ctx . lineWidth = 1
94+ ctx . strokeRect ( - width / 2 , - height / 2 , width , height )
95+
96+ ctx . restore ( )
97+ }
98+
99+ // Draw background papers (rotated)
100+ const centerX = canvasWidth / 2 - newWidth / 2
101+ const centerY = canvasHeight / 2 - newHeight / 2
102+
103+ // Bottom paper (rotated left)
104+ drawPaper ( centerX - 3 , centerY + 6 , newWidth , newHeight , - rotationAngle , 0.15 )
105+
106+ // Middle paper (rotated right)
107+ drawPaper ( centerX + 3 , centerY + 3 , newWidth , newHeight , rotationAngle , 0.2 )
108+
109+ // Top paper (no rotation) - we'll draw the actual image on this one
110+ ctx . save ( )
111+ ctx . shadowColor = 'rgba(0, 0, 0, 0.25)'
112+ ctx . shadowBlur = 10
113+ ctx . shadowOffsetX = 2
114+ ctx . shadowOffsetY = 2
115+
116+ // Draw white background for top paper
117+ ctx . fillStyle = '#ffffff'
118+ ctx . fillRect ( centerX , centerY , newWidth , newHeight )
119+
120+ // Reset shadow for the actual image
121+ ctx . shadowColor = 'transparent'
122+ ctx . shadowBlur = 0
123+ ctx . shadowOffsetX = 0
124+ ctx . shadowOffsetY = 0
125+
126+ // Draw the cropped portion of the image onto the top paper
61127 ctx . drawImage (
62128 image ,
63129 cropLeft , cropTop , // Source x, y (start from cropLeft pixels right and cropTop pixels down)
64130 newWidth , newHeight , // Source width, height
65- 0 , 0 , // Destination x, y
131+ centerX , centerY , // Destination x, y (centered on top paper)
66132 newWidth , newHeight // Destination width, height
67133 )
134+
135+ // Add subtle border to top paper
136+ ctx . strokeStyle = 'rgba(0, 0, 0, 0.1)'
137+ ctx . lineWidth = 1
138+ ctx . strokeRect ( centerX , centerY , newWidth , newHeight )
139+
140+ ctx . restore ( )
68141
69142 // Save the cropped image
70143 const buffer = canvas . toBuffer ( 'image/jpeg' , { quality : 0.9 } )
71144 fs . writeFileSync ( outputPath , buffer )
72145
73- console . log ( 'Successfully cropped image saved to:' , outputPath )
74- console . log ( `Final dimensions: ${ newWidth } x${ newHeight } ` )
146+ console . log ( 'Successfully created 3-paper stack effect with QR code saved to:' , outputPath )
147+ console . log ( `Final dimensions: ${ canvasWidth } x${ canvasHeight } (including paper stack)` )
148+ console . log ( `QR code content: ${ newWidth } x${ newHeight } ` )
75149 } catch ( error ) {
76150 console . error ( 'Error processing image:' , error )
77151 process . exit ( 1 )
0 commit comments