use matrix transformation to replace individual transform

replace unneccessary space
update readme
This commit is contained in:
Weilin 2016-05-28 11:16:48 +08:00
parent d573f66f82
commit 39397d0646
9 changed files with 92 additions and 26 deletions

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2016 Weilin Shi
Copyright (c) 2016 - present Weilin Shi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -9,11 +9,35 @@ generate svg captcha in node.js
- cannot or do not want to use google recaptcha
- have issue with install c++ addon
## usage
```
var svgCaptcha = require('svg-captcha');
// generate random text of length 4
var text = svgCaptcha.randomText();
// generate svg image
var captcha = svgCaptcha(text);
```
with express
```
var svgCaptcha = require('svg-captcha');
app.get('/captcha', function (req, res) {
var text = svgCaptcha.randomText();
var captcha = svgCaptcha(text);
req.session.captcha = text;
res.set('Content-Type', 'image/svg+xml');
res.status(200).send(captcha);
});
```
## sample image
![image](media/example.svg)
## why use svg?
My colleage and I have issue installing c++ addon on windows and we don't want to mess with python and visual studio.
Initially we thought that using svg will result in larger file,
but it turns out that it's smaller than the jpeg captcha.
It does not require any c++ addon.
It uses opentype.js underneath and the result image is smaller than jpeg image.
## Translations
[中文](README_CN.md)

View File

@ -9,11 +9,35 @@
- 无法使用 google recaptcha
- 无法安装 c++ 模块
## 使用方法
```
var svgCaptcha = require('svg-captcha');
// generate random text of length 4
var text = svgCaptcha.randomText();
// generate svg image
var captcha = svgCaptcha(text);
```
在 express中使用
```
var svgCaptcha = require('svg-captcha');
app.get('/captcha', function (req, res) {
var text = svgCaptcha.randomText();
var captcha = svgCaptcha(text);
req.session.captcha = text;
res.set('Content-Type', 'image/svg+xml');
res.status(200).send(captcha);
});
```
## 图片示例
![image](media/example.svg)
## 为什么使用 svg 格式?
我和我的同事都是用windows系统不想使用 c++ 模块。
但现有的验证码生成都是基于 c++ 的。
svg 格式的验证码竟然比 jpg 格式的还要小。
不需要引用 c++ 模块。
使用 opentype.js了而且svg图片比jpeg格式图片要小
## Translations
[中文](README_CN.md)

View File

@ -4,7 +4,7 @@ const textToSVG = require('text-to-svg').loadSync();
const random = require('./random');
const generateBackground = function (width, height) {
const seed = random.int(0, 1010101010);
const seed = random.int(0, 10);
return `<filter id="n" x="0" y="0">
<feTurbulence baseFrequency=".7,.07" seed="${seed}"/>
@ -34,33 +34,28 @@ const getLineNoise = function (lv, width, height) {
return noiseString.join('');
};
const getSVGOptions = function (width, height) {
const getSVGOptions = function (x, width, height) {
return {
x: 0, y: height / 2, fontSize: Math.floor(height * 0.72),
anchor: 'left middle',
x: x, y: height / 2, fontSize: Math.floor(height * 0.72),
anchor: 'center middle',
attributes: {fill: 'red', stroke: 'black'}
};
};
const getText = function (text, width, height) {
const toSVGOptions = getSVGOptions(width, height);
const len = text.length;
const spacing = (width - 10) / (len + 1);
const spacing = (width - 2) / (len + 1);
var i = -1;
var out = [];
while (++i < len) {
var charPath = textToSVG.getD(text[i], toSVGOptions);
var charPath = textToSVG.getD(text[i],
getSVGOptions((i + 1) * spacing, width, height));
// randomly scale it to 95% - 105%, skew
var randomScale = random.int(95, 105) / 100;
var randomTranslateX = (i + 1) * spacing + random.int(-2, 2);
var randomTranslateY = random.int(-3, 3);
var randomMatrix = random.matrix();
var color = random.greyColor(0, 4);
var randomSkewX = random.int(-7, 7);
out.push(`<path fill="${color}" d="${charPath}"
transform="scale(${randomScale})
translate(${randomTranslateX},${randomTranslateY})
skewX(${randomSkewX})"/>`);
transform="matrix(${randomMatrix})"/>`);
}
return out.join('');
@ -86,7 +81,7 @@ const createCaptcha = function (options) {
${bg}
</svg>`;
return xml.replace('\t', '');
return xml.replace(/[\t]/g, '').replace(/\n(\W)/g, '$1');
};
module.exports = createCaptcha;

9
media/example.svg Normal file
View File

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg"
width="150" height="50"><path fill="#333" d="M25.26 22.19L27.05 22.19Q29.35 22.19 30.21 21.54Q31.83 20.29 31.83 17.79Q31.83 13.36 27.81 13.36Q24.47 13.36 23.71 17.14L20.86 17.14Q21.25 14.77 22.52 13.22Q24.45 10.92 27.81 10.92Q30.62 10.92 32.45 12.54Q34.61 14.44 34.61 17.69Q34.61 22.06 30.69 23.42Q35.42 25.25 35.42 30.08Q35.42 33.17 33.66 35.16Q31.55 37.57 27.86 37.57Q24.40 37.57 22.34 35.20Q20.83 33.46 20.51 30.40L23.46 30.40Q23.83 35.09 27.86 35.09Q29.72 35.09 30.99 34.04Q32.57 32.68 32.57 30.08Q32.57 24.49 27.05 24.49L25.26 24.49L25.26 22.19Z"
transform="matrix(0.99 0 -0.1227845609029046 0.99 -1 0)"/><path fill="#333" d="M52.01 31.54Q52.48 35.14 56.21 35.14Q59.96 35.14 59.96 32.51Q59.96 31.24 59.09 30.54Q58.18 29.78 55.82 28.96L55.31 28.76Q52.71 27.87 51.54 26.97Q49.85 25.65 49.85 23.79Q49.85 21.55 51.80 20.20Q53.49 19.04 55.89 19.04Q61.33 19.04 62.19 23.98L59.39 23.98Q58.95 21.34 55.86 21.34Q52.55 21.34 52.55 23.68Q52.55 25.21 56.98 26.78Q59.48 27.65 60.57 28.45Q62.70 29.96 62.70 32.44Q62.70 34.84 60.80 36.25Q59.01 37.55 56.14 37.55Q49.87 37.55 49.16 31.54L52.01 31.54Z"
transform="matrix(1.02 0 -0.2679491924311227 1.02 -1 2)"/><path fill="#444" d="M77.85 11.64L80.52 11.64L80.52 27.09L86.81 19.74L90.17 19.74L84.74 25.83L91.58 36.85L88.22 36.85L83.07 27.72L80.52 30.47L80.52 36.85L77.85 36.85L77.85 11.64Z"
transform="matrix(1.01 0 -0.14054083470239145 1.01 -1 -3)"/><path fill="#444" d="M104.83 19.74L107.85 19.74L112 33.56L116.13 19.74L119.15 19.74L113.48 36.85L110.52 36.85L104.83 19.74Z"
transform="matrix(0.98 0 -0.0524077792830412 0.98 -1 1)"/><path d="M12 16 C66 36,94 17,140 26"
stroke="#888" fill="transparent"/><path d="M11 13 C98 22,97 13,130 38"
stroke="#888" fill="transparent"/><path d="M17 26 C58 39,78 24,143 39"
stroke="#333" fill="transparent"/><filter id="n" x="0" y="0"><feTurbulence baseFrequency=".7,.07" seed="145"/><feColorMatrix type="luminanceToAlpha"/></filter><rect width="150" height="50" filter="url(#n)" opacity="0.2"/></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,6 +1,6 @@
{
"name": "svg-captcha",
"version": "0.9.2",
"version": "0.9.4",
"description": "generate svg captcha in node.js or express.js",
"main": "index.js",
"scripts": {

View File

@ -16,13 +16,24 @@ exports.greyColor = function (min, max) {
return '#' + int + int + int;
};
// https://developer.mozilla.org/en/docs/Web/SVG/Attribute/transform
exports.matrix = function () {
var scale = randomInt(95, 105) / 100;
var dx = randomInt(-2, 2);
var dy = randomInt(-3, 3);
// - 15 to 15 deg
var skewX = randomInt(-267, 267) / 1000;
return `${scale} 0 ${skewX} ${scale} ${dx} ${dy}`;
};
exports.captchaText = function (size) {
size = size || 4;
var i = -1;
var out = '';
while (++i < size) {
out += presets[randomInt(0, 61)]
out += presets[randomInt(0, 61)];
}
return out;

View File

@ -2,7 +2,7 @@ const fs = require('fs');
const svg = require('./');
for (var i = 0; i < 10; i++) {
fs.writeFile(`test${i}.svg`, svg('d3e4'), 'utf8', (err) => {
fs.writeFile(`test${i}.svg`, svg(svg.randomText()), 'utf8', (err) => {
if (err) console.error(err)
else console.log('it\'s saved');
});

View File

@ -1,10 +1,13 @@
const assert = require('assert');
const svgCaptcha = require('./');
console.time('generate 50 images');
for (var i = 0; i < 50; i++) {
var text = svgCaptcha.randomText();
assert(/^[0-9a-zA-Z]+$/.test(text));
svgCaptcha(text);
}
console.timeEnd('generate 50 images');
const xmlReg = /^<svg[\s\S]+\/svg>$/;