add support for font option and multiple fonts
This commit is contained in:
parent
d557f8a42f
commit
d73f3d4c9e
19
README.md
19
README.md
|
@ -63,7 +63,7 @@ app.get('/captcha', function (req, res) {
|
|||
## API
|
||||
|
||||
#### `svgCaptcha.create(options)`
|
||||
If no option is passed, you will get a random string of four characters and corresponding svg.
|
||||
Get a random string of four characters and corresponding svg captcha.
|
||||
|
||||
* `size`: 4 // size of random string
|
||||
* `ignoreChars`: '0o1i' // filter out some characters like 0o1i
|
||||
|
@ -71,6 +71,7 @@ If no option is passed, you will get a random string of four characters and corr
|
|||
* `stroke`: 'black' // style/color of the svg path stroke
|
||||
* `fill`: 'black' // style/color of the svg strokes fill
|
||||
* style: '' // svg path style attribute, i.e.: 'stroke-width: 4;'
|
||||
* `font`: Font object (see svgCaptcha.loadFont) or Array of multiple Font objects
|
||||
|
||||
Options that change the variation of the path:
|
||||
|
||||
|
@ -97,12 +98,17 @@ This function returns an object that has the following property:
|
|||
* `data`: string // svg of the math expression
|
||||
* `text`: string // the answer of the math expression
|
||||
|
||||
#### `svgCaptcha.createCaptcha(text, options)`
|
||||
return a svg captcha based on text provided.
|
||||
Options same as create.
|
||||
Returns svg string.
|
||||
|
||||
#### `svgCaptcha.loadFont(url)`
|
||||
Load your own font and override the default font.
|
||||
Load your own font.
|
||||
* `url`: string // path to your font
|
||||
This api is a wrapper around loadFont api of opentype.js.
|
||||
Returns a Font object which you can use in options.
|
||||
(this api is a wrapper around loadFont api of opentype.js)
|
||||
Your may need experiment around various options to make your own font accessible.
|
||||
See the following api.
|
||||
|
||||
#### `svgCaptcha.options`
|
||||
Gain access to global setting object.
|
||||
|
@ -114,11 +120,6 @@ In addition to size, color, and background, you can also set the following prope
|
|||
* `fontSize`: number // captcha text size
|
||||
* `charPreset`: string // random character preset
|
||||
|
||||
#### `svgCaptcha.randomText([size|options])`
|
||||
return a random string.
|
||||
#### `svgCaptcha(text, options)`
|
||||
return a svg captcha based on text provided.
|
||||
|
||||
In pre 1.1.0 version you have to call these two functions,
|
||||
now you can call create() to save some key strokes ;).
|
||||
|
||||
|
|
|
@ -6,13 +6,16 @@ module.exports = function (text, opts) {
|
|||
assert(ch, 'expect a string');
|
||||
|
||||
const fontSize = opts.fontSize;
|
||||
const fontScale = fontSize / opts.font.unitsPerEm;
|
||||
const font = (Array.isArray(opts.font))
|
||||
? opts.font[Math.floor(Math.random() * opts.font.length)]
|
||||
: opts.font;
|
||||
const fontScale = fontSize / font.unitsPerEm;
|
||||
|
||||
const glyph = opts.font.charToGlyph(ch);
|
||||
const glyph = font.charToGlyph(ch);
|
||||
const width = glyph.advanceWidth ? glyph.advanceWidth * fontScale : 0;
|
||||
const left = opts.x - (width / 2);
|
||||
|
||||
const height = (opts.ascender + opts.descender) * fontScale;
|
||||
const height = (font.ascender + font.descender) * fontScale;
|
||||
const top = opts.y + (height / 2);
|
||||
const path = glyph.getPath(left, top, fontSize);
|
||||
|
||||
|
|
58
lib/index.js
58
lib/index.js
|
@ -6,6 +6,31 @@ const optionMngr = require('./option-manager');
|
|||
|
||||
const opts = optionMngr.options;
|
||||
|
||||
function shuffleArray(array) {
|
||||
let count = array.length,
|
||||
randomnumber,
|
||||
temp;
|
||||
while( count ){
|
||||
randomnumber = Math.random() * count-- | 0;
|
||||
temp = array[count];
|
||||
array[count] = array[randomnumber];
|
||||
array[randomnumber] = temp
|
||||
}
|
||||
}
|
||||
|
||||
function mergePaths(paths) {
|
||||
if (!paths.length) {
|
||||
return [];
|
||||
}
|
||||
const out = paths[0];
|
||||
for (let i = 1; i < paths.length; i += 1) {
|
||||
out.commands = out.commands.concat(
|
||||
paths[i].commands,
|
||||
);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const getTextPath = function (text, width, height, options) {
|
||||
const len = text.length;
|
||||
const spacing = (width - 2) / (len + 1);
|
||||
|
@ -22,22 +47,7 @@ const getTextPath = function (text, width, height, options) {
|
|||
return out;
|
||||
};
|
||||
|
||||
function mergePaths(paths) {
|
||||
if (!paths.length) {
|
||||
return [];
|
||||
}
|
||||
const out = paths[0];
|
||||
for (let i = 1; i < paths.length; i += 1) {
|
||||
out.commands = out.commands.concat(
|
||||
paths[i].commands,
|
||||
);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const createCaptcha = function (text, options) {
|
||||
text = text || random.captchaText();
|
||||
options = Object.assign({}, opts, options);
|
||||
const width = options.width;
|
||||
const height = options.height;
|
||||
const bg = options.background;
|
||||
|
@ -46,9 +56,8 @@ const createCaptcha = function (text, options) {
|
|||
`<rect width="100%" height="100%" fill="${bg}"/>` : '';
|
||||
|
||||
/* Create character paths and order them randomly */
|
||||
let path =
|
||||
[].concat(getTextPath(text, width, height, options))
|
||||
.sort(() => Math.random() - 0.5);
|
||||
let path = [].concat(getTextPath(text, width, height, options));
|
||||
shuffleArray(path);
|
||||
/* Join paths together to one */
|
||||
path = mergePaths(path);
|
||||
/* Randomize nodes and randomly split them */
|
||||
|
@ -65,24 +74,27 @@ const createCaptcha = function (text, options) {
|
|||
};
|
||||
|
||||
const create = function (options) {
|
||||
options = Object.assign({}, opts, options);
|
||||
|
||||
const text = random.captchaText(options);
|
||||
const data = createCaptcha(text, options);
|
||||
|
||||
return {text, data};
|
||||
};
|
||||
|
||||
const createMathExpr = function (options) {
|
||||
options = Object.assign({}, opts, options);
|
||||
|
||||
const expr = random.mathExpr(options.mathMin, options.mathMax, options.mathOperator);
|
||||
const text = expr.text;
|
||||
const data = createCaptcha(expr.equation, options);
|
||||
|
||||
return {text, data};
|
||||
};
|
||||
|
||||
module.exports = createCaptcha;
|
||||
module.exports.randomText = random.captchaText;
|
||||
module.exports.create = create;
|
||||
|
||||
module.exports.createMathExpr = createMathExpr;
|
||||
module.exports.createCaptcha = function (text, options) {
|
||||
options = Object.assign({}, opts, options);
|
||||
createCaptcha(text, options);
|
||||
}
|
||||
module.exports.options = opts;
|
||||
module.exports.loadFont = optionMngr.loadFont;
|
||||
|
|
|
@ -5,8 +5,6 @@ const charPreset = require('./char-preset');
|
|||
|
||||
const fontPath = path.join(__dirname, '../fonts/Comismsh.ttf');
|
||||
const font = opentype.loadSync(fontPath);
|
||||
const ascender = font.ascender;
|
||||
const descender = font.descender;
|
||||
|
||||
const options = {
|
||||
width: 500,
|
||||
|
@ -17,7 +15,8 @@ const options = {
|
|||
size: 4,
|
||||
ignoreChars: '',
|
||||
fontSize: 220,
|
||||
charPreset, font, ascender, descender,
|
||||
charPreset,
|
||||
font,
|
||||
truncateLineProbability: 0.5,
|
||||
truncateCurveProbability: 0.5,
|
||||
truncateCurvePositionMin: 0.4,
|
||||
|
@ -28,10 +27,7 @@ const options = {
|
|||
};
|
||||
|
||||
const loadFont = filepath => {
|
||||
const font = opentype.loadSync(filepath);
|
||||
options.font = font;
|
||||
options.ascender = font.ascender;
|
||||
options.descender = font.descender;
|
||||
return opentype.loadSync(filepath);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
'use strict';
|
||||
const opts = require('./option-manager').options;
|
||||
|
||||
const randomInt = function (min, max) {
|
||||
return Math.round(min + (Math.random() * (max - min)));
|
||||
|
@ -19,17 +18,16 @@ exports.greyColor = function (min, max) {
|
|||
return `#${int}${int}${int}`;
|
||||
};
|
||||
|
||||
/*
|
||||
* options must contain size, ignoreChars, charPreset
|
||||
*/
|
||||
exports.captchaText = function (options) {
|
||||
if (typeof options === 'number') {
|
||||
options = {size: options};
|
||||
}
|
||||
options = options || {};
|
||||
const size = options.size;
|
||||
const ignoreChars = options.ignoreChars;
|
||||
let chars = options.charPreset;
|
||||
|
||||
const size = options.size || 4;
|
||||
const ignoreChars = options.ignoreChars || '';
|
||||
let i = -1;
|
||||
let out = '';
|
||||
let chars = options.charPreset || opts.charPreset;
|
||||
|
||||
if (ignoreChars) {
|
||||
chars = stripCharsFromString(chars, ignoreChars);
|
||||
|
|
Loading…
Reference in New Issue