1+ // FIX: Destructure the required module to get the specific components needed.
2+ // This mirrors the 'import { Jimp, loadFont } from "jimp"' behavior.
3+ const JimpModule = require ( 'jimp' ) ;
4+ const { Jimp, loadFont } = JimpModule ;
5+ const fonts = require ( "@jimp/plugin-print/fonts" ) ;
6+ // Jimp is the constructor class (new Jimp(config))
7+ // loadFont is the function (await loadFont(Jimp.FONT_...))
8+
9+ const crypto = require ( 'crypto' ) ;
10+
11+ // The font constants (like FONT_SANS_32_BLACK) are exposed on the Jimp class itself.
12+ const NOISE_WORDS = [ 'apple' , 'banana' , 'cat' , 'dog' , 'sun' , 'moon' , 'star' , 'tree' , 'rant' , 'robot' ] ;
13+
14+ async function generateCaptchaJPG ( code ) {
15+ const width = 200 ;
16+ const height = 50 ;
17+
18+ const backgroundColor = 0xcc9966ff ;
19+ const colorWhite = 0xffffffff ;
20+
21+ try {
22+ const config = {
23+ width : width ,
24+ height : height ,
25+ color : backgroundColor
26+ } ;
27+
28+ // 1. Instantiation: Use the destructured 'Jimp' constructor with the config object
29+ const image = await new Jimp ( config ) ;
30+
31+ // 2. Font Loading: Use the destructured 'loadFont' function
32+ // Pass constants from the Jimp class (like in the docs)
33+ const mainFont = await loadFont ( fonts . SANS_32_BLACK ) ;
34+ const noiseFont = await loadFont ( fonts . SANS_16_WHITE ) ;
35+
36+ // 3. Add Background Noise Text
37+ image . opacity ( 0.3 ) ;
38+ for ( let i = 0 ; i < 20 ; i ++ ) {
39+ const noiseWord = NOISE_WORDS [ Math . floor ( Math . random ( ) * NOISE_WORDS . length ) ] ;
40+ const x = Math . floor ( Math . random ( ) * ( width - 50 ) ) ;
41+ const y = Math . floor ( Math . random ( ) * ( height - 15 ) ) ;
42+
43+ image . print ( {
44+ font : noiseFont ,
45+ x : x ,
46+ y : y ,
47+ text : noiseWord
48+ } ) ;
49+ }
50+
51+ image . opacity ( 1.0 ) ;
52+
53+ // 4. Print the Main CAPTCHA Code
54+ await image . print ( {
55+ font : mainFont ,
56+ x : 30 ,
57+ y : 8 ,
58+ text : code ,
59+ horizontalAlign : Jimp . HORIZONTAL_ALIGN_CENTER ,
60+ alignmentY : Jimp . VERTICAL_ALIGN_MIDDLE ,
61+ // Include maximum width/height constraints for alignment/wrapping
62+ maxWidth : width ,
63+ maxHeight : height
64+ } ) ;
65+
66+ image . rotate ( ( Math . random ( ) - 0.5 ) * 10 ) ;
67+
68+ for ( let i = 0 ; i < 50 ; i ++ ) {
69+ const x = Math . floor ( Math . random ( ) * width ) ;
70+ const y = Math . floor ( Math . random ( ) * height ) ;
71+ image . setPixelColor ( colorWhite , x , y ) ;
72+ }
73+
74+ // 6. Convert to compressed JPEG and return the Buffer
75+ return await image . getBuffer ( 'image/jpeg' , { quality : 30 } ) ;
76+
77+ } catch ( error ) {
78+ // Log the error to see if any new problems arise
79+ console . error ( 'Error in generateCaptchaJPG:' , error ) ;
80+ throw new Error ( 'Failed to generate CAPTCHA image.' ) ;
81+ }
82+ }
83+
84+ function generateCaptchaCode ( length = 7 ) {
85+ return crypto . randomBytes ( Math . ceil ( length / 2 ) )
86+ . toString ( 'hex' )
87+ . slice ( 0 , length )
88+ . toUpperCase ( ) ;
89+ }
90+
91+ module . exports = {
92+ generateCaptchaJPG,
93+ generateCaptchaCode
94+ } ;
0 commit comments