diff --git a/assets/captcha/default.png b/assets/captcha/default.png index 9322378..e5c886b 100644 Binary files a/assets/captcha/default.png and b/assets/captcha/default.png differ diff --git a/js-script/CaptchaGenerator.d.ts b/js-script/CaptchaGenerator.d.ts index 7e816d3..7f17fe2 100644 --- a/js-script/CaptchaGenerator.d.ts +++ b/js-script/CaptchaGenerator.d.ts @@ -28,7 +28,7 @@ export declare class CaptchaGenerator { * @type {string} * @since 2.0.3 */ - get text(): string; + get text(): string | undefined; /** * set dimension for your captcha image * @param {integer} height Height of captcha image. diff --git a/js-script/CaptchaGenerator.js b/js-script/CaptchaGenerator.js index 46ec47f..54563fa 100644 --- a/js-script/CaptchaGenerator.js +++ b/js-script/CaptchaGenerator.js @@ -23,7 +23,7 @@ class CaptchaGenerator { this.captcha = constants_1.defaultCaptchaOption; this.trace = constants_1.defaultTraceOptions; this.decoy = constants_1.defaultDecoyOptions; - this.captcha.text = (0, util_1.randomText)(this.captcha.characters); + this.captcha.text = (0, util_1.randomText)(this.captcha.characters || 6); } /** * Get the text of captcha. diff --git a/js-script/captcha.d.ts b/js-script/captcha.d.ts index c2d3429..01518ca 100644 --- a/js-script/captcha.d.ts +++ b/js-script/captcha.d.ts @@ -28,9 +28,9 @@ export declare class Captcha { get text(): string; /** * Get png image of captcha. - * @returns {Buffer} Get png image of captcha created. + * @returns {Buffer | Promise} Get png image of captcha created. */ - get png(): Buffer; + get png(): Buffer | Promise; /** * Draw image on your captcha. * @param {Image} image Choose image you want to add. @@ -57,4 +57,5 @@ export declare class Captcha { * @returns {Captcha} */ drawCaptcha(captchaOption?: SetCaptchaOption): Captcha; + toBuffer(): void; } diff --git a/js-script/captcha.js b/js-script/captcha.js index 7cef369..ba2ee52 100644 --- a/js-script/captcha.js +++ b/js-script/captcha.js @@ -38,7 +38,7 @@ class Captcha { } /** * Get png image of captcha. - * @returns {Buffer} Get png image of captcha created. + * @returns {Buffer | Promise} Get png image of captcha created. */ get png() { this._canvas.async = this.async; @@ -50,7 +50,7 @@ class Captcha { * @returns {Captcha} */ drawImage(image) { - this._ctx.drawImage(image, 0, 0); + this._ctx.drawImage(image, 0, 0, this._width, this._height); return this; } /** @@ -105,9 +105,9 @@ class Captcha { if (captchaOption.text) option.characters = captchaOption.text.length; if (!captchaOption.text && captchaOption.characters) - option.text = (0, util_1.randomText)(option.characters); + option.text = (0, util_1.randomText)(option.characters || 6); if (!option.text) - option.text = (0, util_1.randomText)(option.characters); + option.text = (0, util_1.randomText)(option.characters || 6); this._captcha = option; if (!this._coordinates[0]) this._coordinates = (0, util_1.getRandomCoordinate)(this._height, this._width, option.characters || 6); @@ -121,10 +121,10 @@ class Captcha { if (option.skew) { this._ctx.transform(1, Math.random(), (0, util_1.getRandom)(20) / 100, 1, 0, 0); } - if (option.rotate > 0) { + if (option.rotate && option.rotate > 0) { this._ctx.rotate((0, util_1.getRandom)(-option.rotate, option.rotate) * Math.PI / 180); } - if (((_a = option.colors) === null || _a === void 0 ? void 0 : _a.length) > 2) { + if (option.colors && ((_a = option.colors) === null || _a === void 0 ? void 0 : _a.length) > 2) { this._ctx.fillStyle = option.colors[(0, util_1.getRandom)(option.colors.length - 1)]; } this._ctx.fillText(option.text[n], 0, 0); @@ -133,5 +133,8 @@ class Captcha { ; return this; } + toBuffer() { + this._canvas.toBuffer('png'); + } } exports.Captcha = Captcha; diff --git a/js-script/extra.d.ts b/js-script/extra.d.ts index e7be30a..72cd062 100644 --- a/js-script/extra.d.ts +++ b/js-script/extra.d.ts @@ -1,5 +1,6 @@ /// -declare const captchaValue: {}; +import { Image } from "skia-canvas"; +import { SetCaptchaOption, SetDecoyOption, SetTraceOption } from "./constants"; interface captchaValueSync { image: Buffer; text: string; @@ -8,6 +9,12 @@ interface captchaValue { image: Promise; text: string; } +interface CreateCaptchaOptions { + captcha?: SetCaptchaOption; + trace?: SetTraceOption; + decoy?: SetDecoyOption; + background?: Image; +} /** * Create custom captcha from scratch. * @async @@ -16,13 +23,13 @@ interface captchaValue { * @param {string} [text] Captcha text. * @returns */ -export declare function createCaptcha(width: number, height: number, text?: string): captchaValue; +export declare function createCaptcha(width: number, height: number, option?: CreateCaptchaOptions): captchaValue; /** * Create captcha in sync mode. * @param {number} width captcha image width. * @param {number} height captcha image height. - * @param {string} [text] Captcha text. + * @param {CreateCaptchaOptions} [option] Captcha text. * @returns */ -export declare function createCaptchaSync(width: number, height: number, text?: string): captchaValueSync; +export declare function createCaptchaSync(width: number, height: number, option?: CreateCaptchaOptions): captchaValueSync; export {}; diff --git a/js-script/extra.js b/js-script/extra.js index 0382234..c6108d9 100644 --- a/js-script/extra.js +++ b/js-script/extra.js @@ -2,7 +2,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.createCaptchaSync = exports.createCaptcha = void 0; const _1 = require("."); -const captchaValue = {}; /** * Create custom captcha from scratch. * @async @@ -11,21 +10,17 @@ const captchaValue = {}; * @param {string} [text] Captcha text. * @returns */ -function createCaptcha(width, height, text) { +function createCaptcha(width, height, option = {}) { const captcha = new _1.Captcha(width, height); const decoyCount = Math.floor(width * height / 2500); - captcha.addDecoy({ - total: decoyCount, - opacity: 1 - }); - if (text) { - captcha.drawCaptcha({ text: text }); - } - else { - captcha.drawCaptcha(); - text = captcha.text; - } - captcha.drawTrace(); + if (!option.decoy) + option.decoy = {}; + if (!option.decoy.total) + option.decoy.total = decoyCount; + captcha.addDecoy(option.decoy); + captcha.drawCaptcha(option.captcha); + const text = captcha.text; + captcha.drawTrace(option.trace); captcha.addDecoy({ opacity: 1 }); return { image: captcha.png, text: captcha.text }; } @@ -35,25 +30,21 @@ exports.createCaptcha = createCaptcha; * Create captcha in sync mode. * @param {number} width captcha image width. * @param {number} height captcha image height. - * @param {string} [text] Captcha text. + * @param {CreateCaptchaOptions} [option] Captcha text. * @returns */ -function createCaptchaSync(width, height, text) { +function createCaptchaSync(width, height, option = {}) { const captcha = new _1.Captcha(width, height); const decoyCount = Math.floor(width * height / 2500); captcha.async = false; - captcha.addDecoy({ - total: decoyCount, - opacity: 1 - }); - if (text) { - captcha.drawCaptcha({ text: text }); - } - else { - captcha.drawCaptcha(); - text = captcha.text; - } - captcha.drawTrace(); + if (!option.decoy) + option.decoy = {}; + if (!option.decoy.total) + option.decoy.total = decoyCount; + captcha.addDecoy(option.decoy); + captcha.drawCaptcha(option.captcha); + const text = captcha.text; + captcha.drawTrace(option.trace); captcha.addDecoy({ opacity: 1 }); return { image: captcha.png, text: captcha.text }; } diff --git a/package-lock.json b/package-lock.json index d894d90..9f7c304 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "captcha-canvas", - "version": "3.0.3", + "version": "3.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "captcha-canvas", - "version": "3.0.3", + "version": "3.1.0", "license": "Apache-2.0", "dependencies": { "skia-canvas": "^0.9.25" @@ -15,6 +15,7 @@ "@types/node": "^14.11.8", "@types/skia-canvas": "^0.9.2", "better-docs": "^2.3.2", + "canvas": "^2.8.0", "eslint": "^7.27.0", "jsdoc": "^3.6.7", "typescript": "^4.0.2" @@ -971,6 +972,56 @@ "url": "https://opencollective.com/browserslist" } }, + "node_modules/canvas": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.8.0.tgz", + "integrity": "sha512-gLTi17X8WY9Cf5GZ2Yns8T5lfBOcGgFehDFb+JQwDqdOoBOcECS9ZWMEAqMSVcMYwXD659J8NyzjRY/2aE+C2Q==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.14.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/canvas/node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "dev": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/canvas/node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/canvas/node_modules/simple-get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", + "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "dev": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/catharsis": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", @@ -2424,6 +2475,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "dev": true + }, "node_modules/nanocolors": { "version": "0.2.12", "resolved": "https://registry.npmjs.org/nanocolors/-/nanocolors-0.2.12.tgz", @@ -4638,6 +4695,45 @@ "integrity": "sha512-doiV5dft6yzWO1WwU19kt8Qz8R0/8DgEziz6/9n2FxUasteZNwNNYSmJO3GLBH8lCVE73AB1RPDPAeYbcO5Cvw==", "dev": true }, + "canvas": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.8.0.tgz", + "integrity": "sha512-gLTi17X8WY9Cf5GZ2Yns8T5lfBOcGgFehDFb+JQwDqdOoBOcECS9ZWMEAqMSVcMYwXD659J8NyzjRY/2aE+C2Q==", + "dev": true, + "requires": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.14.0", + "simple-get": "^3.0.3" + }, + "dependencies": { + "decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "dev": true, + "requires": { + "mimic-response": "^2.0.0" + } + }, + "mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "dev": true + }, + "simple-get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", + "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "dev": true, + "requires": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + } + } + }, "catharsis": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", @@ -5768,6 +5864,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "dev": true + }, "nanocolors": { "version": "0.2.12", "resolved": "https://registry.npmjs.org/nanocolors/-/nanocolors-0.2.12.tgz", diff --git a/package.json b/package.json index 8da922a..f2c9eb7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "captcha-canvas", - "version": "3.0.4", + "version": "3.1.0", "description": "A captcha generator by using skia-canvas module.", "main": "./js-script/index.js", "files": [ @@ -32,6 +32,7 @@ "@types/node": "^14.11.8", "@types/skia-canvas": "^0.9.2", "better-docs": "^2.3.2", + "canvas": "^2.8.0", "eslint": "^7.27.0", "jsdoc": "^3.6.7", "typescript": "^4.0.2" diff --git a/test.js b/test.js index e87e650..7b9ee0d 100644 --- a/test.js +++ b/test.js @@ -1,9 +1,10 @@ -"use strict"; -exports.__esModule = true; -var fs_1 = require("fs"); -var js_script_1 = require("./js-script"); -var captcha = new js_script_1.CaptchaGenerator() - .setDimension(200, 200); -console.log(__filename + captcha.text); -(0, fs_1.writeFileSync)('assets/CaptchaGenerator/' + captcha.text + 'captcha.png', captcha.generateSync()); -console.log(captcha.text); +const { writeFileSync } = require('fs'); +const { createCaptchaSync } = require('./js-script/extra'); + +const captcha = createCaptchaSync(900, 300, { + captcha: { + size: 80, + }, +}); + +writeFileSync('assets/captcha/default.png', captcha.image); \ No newline at end of file diff --git a/test.ts b/test.ts deleted file mode 100644 index 02c1c0f..0000000 --- a/test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { writeFileSync } from "fs"; -import { CaptchaGenerator } from "./js-script"; - -const captcha = new CaptchaGenerator() -.setDimension(200, 200); -console.log(__filename + captcha.text); -writeFileSync('assets/CaptchaGenerator/' + captcha.text + 'captcha.png', captcha.generateSync()); - -console.log(captcha.text); diff --git a/ts-script/CaptchaGenerator.ts b/ts-script/CaptchaGenerator.ts index 522aa9f..7e11275 100644 --- a/ts-script/CaptchaGenerator.ts +++ b/ts-script/CaptchaGenerator.ts @@ -26,14 +26,14 @@ export class CaptchaGenerator { this.captcha = defaultCaptchaOption; this.trace = defaultTraceOptions; this.decoy = defaultDecoyOptions; - this.captcha.text = randomText(this.captcha.characters); + this.captcha.text = randomText(this.captcha.characters || 6); } /** * Get the text of captcha. * @type {string} * @since 2.0.3 */ - get text(): string { + get text(): string | undefined { return this.captcha.text; } /** diff --git a/ts-script/captcha.ts b/ts-script/captcha.ts index ea37812..4710583 100644 --- a/ts-script/captcha.ts +++ b/ts-script/captcha.ts @@ -45,9 +45,9 @@ export class Captcha { } /** * Get png image of captcha. - * @returns {Buffer} Get png image of captcha created. + * @returns {Buffer | Promise} Get png image of captcha created. */ - get png(): Buffer { + get png(): Buffer | Promise { this._canvas.async = this.async; return this._canvas.png; } @@ -57,7 +57,7 @@ export class Captcha { * @returns {Captcha} */ drawImage(image: Image): Captcha { - this._ctx.drawImage(image, 0, 0); + this._ctx.drawImage(image, 0, 0, this._width, this._height); return this; } /** @@ -111,8 +111,8 @@ export class Captcha { drawCaptcha(captchaOption: SetCaptchaOption = {}): Captcha { const option = { ...this._captcha, ...captchaOption }; if(captchaOption.text) option.characters = captchaOption.text.length; - if(!captchaOption.text && captchaOption.characters) option.text = randomText(option.characters); - if(!option.text) option.text = randomText(option.characters); + if(!captchaOption.text && captchaOption.characters) option.text = randomText(option.characters || 6); + if(!option.text) option.text = randomText(option.characters || 6); this._captcha = option; if(!this._coordinates[0]) this._coordinates = getRandomCoordinate(this._height, this._width, option.characters || 6); @@ -126,12 +126,16 @@ export class Captcha { this._ctx.save(); this._ctx.translate(coordinates[n][0], coordinates[n][1]); if (option.skew) {this._ctx.transform(1, Math.random(), getRandom(20) / 100, 1, 0, 0);} - if (option.rotate > 0) {this._ctx.rotate(getRandom(-option.rotate, option.rotate) * Math.PI / 180);} - if (option.colors?.length > 2) {this._ctx.fillStyle = option.colors[getRandom(option.colors.length - 1)];} + if (option.rotate && option.rotate > 0) {this._ctx.rotate(getRandom(-option.rotate, option.rotate) * Math.PI / 180);} + if (option.colors && option.colors?.length > 2) {this._ctx.fillStyle = option.colors[getRandom(option.colors.length - 1)];} this._ctx.fillText(option.text[n], 0, 0); this._ctx.restore(); }; return this; } + + toBuffer() { + this._canvas.toBuffer('png'); + } } diff --git a/ts-script/extra.ts b/ts-script/extra.ts index 26314bb..d5e1ee6 100644 --- a/ts-script/extra.ts +++ b/ts-script/extra.ts @@ -1,6 +1,7 @@ +import { Image } from "skia-canvas"; import { Captcha } from "."; +import { SetCaptchaOption, SetDecoyOption, SetTraceOption } from "./constants"; -const captchaValue = {} interface captchaValueSync { image: Buffer, text: string @@ -10,6 +11,13 @@ interface captchaValue { image: Promise, text: string } + +interface CreateCaptchaOptions { + captcha?: SetCaptchaOption; + trace?: SetTraceOption; + decoy?: SetDecoyOption; + background?: Image; +} /** * Create custom captcha from scratch. * @async @@ -18,24 +26,22 @@ interface captchaValue { * @param {string} [text] Captcha text. * @returns */ -export function createCaptcha(width: number, height: number, text?: string): captchaValue { +export function createCaptcha(width: number, height: number, option: CreateCaptchaOptions = {}): captchaValue { const captcha = new Captcha(width, height); const decoyCount = Math.floor(width*height/2500); - captcha.addDecoy({ - total: decoyCount, - opacity: 1 - }); + if(!option.decoy) option.decoy = {}; + if(!option.decoy.total) option.decoy.total = decoyCount; + + captcha.addDecoy(option.decoy); - if (text) { - captcha.drawCaptcha({ text: text }); - } else { - captcha.drawCaptcha(); - text = captcha.text; - } + + captcha.drawCaptcha(option.captcha); + const text = captcha.text; - captcha.drawTrace(); - captcha.addDecoy({opacity: 1}); + captcha.drawTrace(option.trace); + + captcha.addDecoy({ opacity: 1 }); return { image: captcha.png, text: captcha.text }; }; @@ -43,28 +49,26 @@ export function createCaptcha(width: number, height: number, text?: string): cap * Create captcha in sync mode. * @param {number} width captcha image width. * @param {number} height captcha image height. - * @param {string} [text] Captcha text. + * @param {CreateCaptchaOptions} [option] Captcha text. * @returns */ -export function createCaptchaSync(width: number, height: number, text?: string): captchaValueSync { +export function createCaptchaSync(width: number, height: number, option: CreateCaptchaOptions = {}): captchaValueSync { const captcha = new Captcha(width, height); const decoyCount = Math.floor(width*height/2500); captcha.async = false; - captcha.addDecoy({ - total: decoyCount, - opacity: 1 - }); + if(!option.decoy) option.decoy = {}; + if(!option.decoy.total) option.decoy.total = decoyCount; + + captcha.addDecoy(option.decoy); + + + captcha.drawCaptcha(option.captcha); + const text = captcha.text; - if (text) { - captcha.drawCaptcha({ text: text }); - } else { - captcha.drawCaptcha(); - text = captcha.text; - } + captcha.drawTrace(option.trace); - captcha.drawTrace(); - captcha.addDecoy({opacity: 1}); + captcha.addDecoy({ opacity: 1 }); return { image: captcha.png, text: captcha.text }; };