[UPDATED] refactor so that user can load a new font
This commit is contained in:
parent
69bdacfcce
commit
594e118153
|
@ -0,0 +1,12 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[{package.json,*.yml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
|
@ -1,36 +1,19 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const path = require('path');
|
||||
const opentype = require('opentype.js');
|
||||
|
||||
const fontPath = path.join(__dirname, '../fonts/Comismsh.ttf');
|
||||
const font = opentype.loadSync(fontPath);
|
||||
const ascender = font.ascender;
|
||||
const descender = font.descender;
|
||||
|
||||
const defaultOption = {
|
||||
fontSize: 72,
|
||||
x: 0,
|
||||
y: 0,
|
||||
noise: 1
|
||||
};
|
||||
|
||||
module.exports = function (text, options) {
|
||||
options = Object.assign({}, defaultOption, options);
|
||||
|
||||
const ch = text.trim()[0];
|
||||
module.exports = function (text, opts) {
|
||||
const ch = text[0];
|
||||
assert(ch, 'expect a string');
|
||||
|
||||
const fontSize = options.fontSize;
|
||||
const fontScale = 1 / font.unitsPerEm * fontSize;
|
||||
const fontSize = opts.fontSize;
|
||||
const fontScale = 1 / opts.font.unitsPerEm * fontSize;
|
||||
|
||||
const glyph = font.charToGlyph(ch);
|
||||
const glyph = opts.font.charToGlyph(ch);
|
||||
const width = glyph.advanceWidth ? glyph.advanceWidth * fontScale : 0;
|
||||
const left = options.x - (width / 2);
|
||||
const left = opts.x - (width / 2);
|
||||
|
||||
const height = (ascender + descender) * fontScale;
|
||||
const top = options.y + (height / 2);
|
||||
const height = (opts.ascender + opts.descender) * fontScale;
|
||||
const top = opts.y + (height / 2);
|
||||
const path = glyph.getPath(left, top, fontSize);
|
||||
|
||||
const pathData = path.toPathData();
|
||||
|
|
52
lib/index.js
52
lib/index.js
|
@ -1,23 +1,25 @@
|
|||
'use strict';
|
||||
const chToPath = require('./ch-to-path');
|
||||
const random = require('./random');
|
||||
const optionMngr = require('./option-manager');
|
||||
|
||||
const opts = optionMngr.options;
|
||||
|
||||
const getLineNoise = function (width, height, options) {
|
||||
const hasColor = options.color;
|
||||
const noiseString = [];
|
||||
const noiseLines = [];
|
||||
let i = -1;
|
||||
|
||||
while (++i < options.noise) {
|
||||
const start = `${random.int(5, 25)} ${random.int(10, height - 10)}`;
|
||||
const end = `${random.int(width - 25, width - 5)} ${random.int(10, height - 10)}`;
|
||||
const mid1 = `${random.int((width / 2) - 25, (width / 2) + 25)} ${random.int(10, height - 10)}`;
|
||||
const mid2 = `${random.int((width / 2) - 25, (width / 2) + 25)} ${random.int(10, height - 10)}`;
|
||||
const start = `${random.int(1, 21)} ${random.int(1, height - 1)}`;
|
||||
const end = `${random.int(width - 21, width - 1)} ${random.int(1, height - 1)}`;
|
||||
const mid1 = `${random.int((width / 2) - 21, (width / 2) + 21)} ${random.int(1, height - 1)}`;
|
||||
const mid2 = `${random.int((width / 2) - 21, (width / 2) + 21)} ${random.int(1, height - 1)}`;
|
||||
const color = hasColor ? random.color() : random.greyColor();
|
||||
noiseString.push(`<path d="M${start} C${mid1},${mid2},${end}"
|
||||
stroke="${color}" fill="none"/>`);
|
||||
noiseLines.push(`<path d="M${start} C${mid1},${mid2},${end}" stroke="${color}" fill="none"/>`);
|
||||
}
|
||||
|
||||
return noiseString.join('');
|
||||
return noiseLines;
|
||||
};
|
||||
|
||||
const getText = function (text, width, height, options) {
|
||||
|
@ -29,30 +31,19 @@ const getText = function (text, width, height, options) {
|
|||
while (++i < len) {
|
||||
const x = spacing * (i + 1);
|
||||
const y = height / 2;
|
||||
const fontSize = height;
|
||||
const charPath = chToPath(
|
||||
text[i],
|
||||
Object.assign({x, y, fontSize}, options)
|
||||
);
|
||||
const charPath = chToPath(text[i], Object.assign({x, y}, options));
|
||||
|
||||
const color = options.color ?
|
||||
random.color(options.background) : random.greyColor(0, 4);
|
||||
out.push(`<path fill="${color}" d="${charPath}"/>`);
|
||||
}
|
||||
|
||||
return out.join('');
|
||||
return out;
|
||||
};
|
||||
|
||||
const defaultOption = {
|
||||
width: 150,
|
||||
height: 50,
|
||||
noise: 1,
|
||||
color: false,
|
||||
background: ''
|
||||
};
|
||||
const createCaptcha = function (text, options) {
|
||||
text = text || random.captchaText();
|
||||
options = Object.assign({}, defaultOption, options);
|
||||
options = Object.assign({}, opts, options);
|
||||
const width = options.width;
|
||||
const height = options.height;
|
||||
const bg = options.background;
|
||||
|
@ -62,14 +53,15 @@ const createCaptcha = function (text, options) {
|
|||
|
||||
const bgRect = bg ?
|
||||
`<rect width="100%" height="100%" fill="${bg}"/>` : '';
|
||||
const lineNoise = getLineNoise(width, height, options);
|
||||
const textPath = getText(text, width, height, options);
|
||||
const xml = `<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="${width}" height="${height}">
|
||||
${bgRect} ${textPath} ${lineNoise}
|
||||
</svg>`;
|
||||
const paths =
|
||||
[].concat(getLineNoise(width, height, options))
|
||||
.concat(getText(text, width, height, options))
|
||||
.sort(() => Math.random() - 0.5)
|
||||
.join('');
|
||||
const start = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">`;
|
||||
const xml = `${start}${bgRect}${paths}</svg>`;
|
||||
|
||||
return xml.replace(/[\t]/g, '').replace(/\n(\W)/g, '$1');
|
||||
return xml;
|
||||
};
|
||||
|
||||
const create = function (options) {
|
||||
|
@ -91,3 +83,5 @@ module.exports = createCaptcha;
|
|||
module.exports.randomText = random.captchaText;
|
||||
module.exports.create = create;
|
||||
module.exports.createMathExpr = createMathExpr;
|
||||
module.exports.options = opts;
|
||||
module.exports.loadFont = optionMngr.loadFont;
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
'use strict';
|
||||
const path = require('path');
|
||||
const opentype = require('opentype.js');
|
||||
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: 150,
|
||||
height: 50,
|
||||
noise: 1,
|
||||
color: false,
|
||||
background: '',
|
||||
size: 4,
|
||||
ignoreChars: '',
|
||||
fontSize: 56,
|
||||
charPreset, font, ascender, descender
|
||||
};
|
||||
|
||||
const loadFont = filepath => {
|
||||
const font = opentype.loadSync(filepath);
|
||||
options.font = font;
|
||||
options.ascender = font.ascender;
|
||||
options.descender = font.descender;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
options, loadFont
|
||||
};
|
|
@ -1,6 +1,7 @@
|
|||
'use strict';
|
||||
const opts = require('./option-manager').options;
|
||||
|
||||
const presets = require('./char-preset');
|
||||
const presets = opts.charPreset;
|
||||
|
||||
const randomInt = function (min, max) {
|
||||
return Math.round(min + (Math.random() * (max - min)));
|
||||
|
@ -45,44 +46,15 @@ exports.captchaText = function (options) {
|
|||
return out;
|
||||
};
|
||||
|
||||
const ops = ['+', '-', '*', '/'];
|
||||
/**
|
||||
* returns an object that has the following props:
|
||||
* text, equation
|
||||
*/
|
||||
exports.mathExpr = function () {
|
||||
const op = ops[0];
|
||||
|
||||
let left;
|
||||
let right;
|
||||
let text;
|
||||
switch (op) {
|
||||
case '+':
|
||||
left = randomInt(1, 9);
|
||||
right = randomInt(1, 9);
|
||||
text = (left + right).toString();
|
||||
break;
|
||||
|
||||
case '-':
|
||||
right = randomInt(1, 9);
|
||||
left = right + randomInt(1, 8);
|
||||
text = (left - right).toString();
|
||||
break;
|
||||
|
||||
case '*':
|
||||
left = randomInt(1, 8);
|
||||
right = randomInt(2, 9);
|
||||
text = (left * right).toString();
|
||||
break;
|
||||
|
||||
default: // division
|
||||
right = randomInt(2, 8);
|
||||
left = right * randomInt(2, 9);
|
||||
text = Math.round(left / right).toString();
|
||||
break;
|
||||
}
|
||||
|
||||
const equation = left + op + right;
|
||||
const left = randomInt(1, 9);
|
||||
const right = randomInt(1, 9);
|
||||
const text = (left + right).toString();
|
||||
const equation = left + '+' + right;
|
||||
|
||||
return {text, equation};
|
||||
};
|
||||
|
|
|
@ -75,7 +75,7 @@ describe('random function', () => {
|
|||
assert(/^\d+$/.test(expr.text));
|
||||
|
||||
assert(typeof expr.equation === 'string');
|
||||
assert(/^\d+[\+\-\*\/]\d+$/.test(expr.equation));
|
||||
assert(/^\d+[+\-*/]\d+$/.test(expr.equation));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue