/**
* SimpleCaptcha
* Simple image-based macthematical captcha
*
* @version 2.6.0
* https://github.com/foo123/simple-captcha
*
**/
!function(root, name, factory) {
"use strict";
if (('object' === typeof module) && module.exports) /* CommonJS */
(module.$deps = module.$deps||{}) && (module.exports = module.$deps[name] = factory.call(root));
else if (('function' === typeof define) && define.amd && ('function' === typeof require) && ('function' === typeof require.specified) && require.specified(name) /*&& !require.defined(name)*/) /* AMD */
define(name, ['module'], function(module) {factory.moduleUri = module.uri; return factory.call(root);});
else if (!(name in root)) /* Browser/WebWorker/.. */
(root[name] = factory.call(root)||1) && ('function' === typeof(define)) && define.amd && define(function() {return root[name];});
}( /* current root */ 'undefined' !== typeof self ? self : this,
/* module name */ "SimpleCaptcha",
/* module factory */ function ModuleFactory__SimpleCaptcha(undef) {
"use strict";
var HAS = Object.prototype.hasOwnProperty,
toString = Object.prototype.toString,
stdMath = Math,
isNode = ("undefined" !== typeof global) && ("[object global]" === toString.call(global)),
isBrowser = ("undefined" !== typeof window) && ("[object Window]" === toString.call(window)),
padStart = String.prototype.padStart
? function(s, n, p) {return s.padStart(n, p);}
: function(s, n, p) {return s.length < n ? (new Array(n-s.length+1)).join(p) + s : s;}
;
class SimpleCaptcha
{
static VERSION = '2.6.0';
opts = null;
captcha = null;
hmac = null;
constructor() {
this.captcha = null;
this.hmac = null;
this.opts = {};
this.option('secret_key', 'SECRET_KEY');
this.option('secret_salt', 'SECRET_SALT_');
this.option('difficulty', 1); // 0 (very easy) to 3 (more difficult)
this.option('distortion_type', 1); // distortion type: 1: position distortion, 2: scale distortion
this.option('distortion', null); // distortion amplitudes by difficulty
this.option('num_terms', 2); // default
this.option('max_num_terms', -1); // default, same as num_terms
this.option('min_term', 1); // default
this.option('max_term', 20); // default
this.option('has_multiplication', true); // default
this.option('has_division', true); // default
this.option('has_equal_sign', true); // default
this.option('color', 0x121212); // text color
this.option('background', 0xffffff); // background color
}
option(key, val = null) {
var nargs = arguments.length;
if (1 == nargs)
{
return HAS.call(this.opts, key) ? this.opts[key] : undef;
}
else if (1 < nargs)
{
this.opts[key] = val;
}
return this;
}
async getCaptcha() {
if (!this.captcha) await this.generate();
return this.captcha;
}
async getHash() {
if (!this.captcha) await this.generate();
return this.hmac;
}
reset() {
this.captcha = null;
this.hmac = null;
return this;
}
async validate(answer = null, hmac = null) {
if ((null == answer) || (null == hmac)) return false;
var hash = await createHash(String(this.option('secret_key')), String(this.option('secret_salt') ? this.option('secret_salt') : '') + String(answer));
return hash_equals(hash, hmac);
}
async generate() {
var difficulty = stdMath.min(3, stdMath.max(0, parseInt(this.option('difficulty')))),
distortion_type = stdMath.max(0, stdMath.min(2, parseInt(this.option('distortion_type')))),
distortion = this.option('distortion'),
num_terms = stdMath.max(1, parseInt(this.option('num_terms'))),
max_num_terms = parseInt(this.option('max_num_terms')),
min_term = stdMath.max(0, parseInt(this.option('min_term'))),
max_term = stdMath.max(0, parseInt(this.option('max_term'))),
has_mult = !!this.option('has_multiplication'),
has_div = !!this.option('has_division'),
has_equal = !!this.option('has_equal_sign'),
color = this.option('color'),
background = this.option('background'),
formula, result, captcha, width, height
;
if (!is_array(color) && !is_callable(color)) color = [color];
if (!is_array(background) && !is_callable(background)) background = [background];
if (is_array(color)) color = color.map(int);
if (is_array(background)) background = background.map(int);
if (max_num_terms > num_terms)
{
num_terms = rand(num_terms, max_num_terms);
}
// generate mathematical formula
[formula, result] = this.formula(num_terms, min_term, max_term, has_mult, has_div, has_equal, difficulty);
// compute hmac of result
this.hmac = await createHash(String(this.option('secret_key')), String(this.option('secret_salt') ? this.option('secret_salt') : '') + String(result));
// create image captcha with formula depending on difficulty
[captcha, width, height] = this.image(formula, color, background, difficulty, distortion_type, distortion);
// output image
this.captcha = await imagepng(captcha, width, height);
return this;
}
formula(terms, min, max, has_mult, has_div, has_equal, difficulty) {
// generate mathematical formula
var formula = [], result = 0, factor = 0, divider = 0, i, x;
for (i=0; i<terms; ++i)
{
x = rand(min, max);
if ((result > x) && rand(0, 1))
{
// randomly use plus or minus operator
x = -x;
}
else if (has_mult && (x <= 10) && rand(0, 1))
{
// randomly use multiplication factor
factor = rand(2, 3);
}
else if (has_div && (0 === x % 2) && rand(0, 1))
{
// randomly use division factor
divider = 0 === x % 3 ? rand(2, 3) : 2;
}
if (0 < factor)
{
result += x * factor;
if (0 > x)
{
formula.push('-');
formula.push.apply(formula, split(stdMath.abs(x)));
formula.push('×');
formula.push.apply(formula, split(factor));
}
else
{
if (0 < i) formula.push('+');
formula.push.apply(formula, split(x));
formula.push('×');
formula.push.apply(formula, split(factor));
}
}
else if (0 < divider)
{
result += stdMath.floor(x / divider);
if (0 > x)
{
formula.push('-');
formula.push.apply(formula, split(stdMath.abs(x)));
formula.push('÷');
formula.push.apply(formula, split(divider));
}
else
{
if (0 < i) formula.push('+');
formula.push.apply(formula, split(x));
formula.push('÷');
formula.push.apply(formula, split(divider));
}
}
else
{
result += x;
if (0 > x)
{
formula.push('-');
formula.push.apply(formula, split(stdMath.abs(x)));
}
else
{
if (0 < i) formula.push('+');
formula.push.apply(formula, split(x));
}
}
factor = 0;
divider = 0;
}
if (has_equal)
{
formula.push('=');
formula.push('?');
}
return [formula, result];
}
image(chars, color, background, difficulty, distortion_type, distortion) {
var bitmaps = _chars(),
cw = bitmaps.width,
ch = bitmaps.height,
n = chars.length,
space = 1,
x0 = 10,
y0 = 10,
w = n * cw + (n-1) * space + 2 * x0,
h = ch + 2 * y0,
wh = w*h, sw, sh,
imgb = new Uint8Array(wh),
img = new Uint8Array(wh << 2),
charbmp, c, i, j, k,
x1, y1, x2, y2,
x, y, yw, xs, ys, xc, yc, alpha,
phase, amplitude, scale
;
// img bitmap
x1 = 0;
y1 = h/2;
x2 = w;
y2 = h/2;
for (j=0,i=0,x=0,y=0; i<wh; ++i,++x,j+=4)
{
if (x >= w) {x = 0; ++y;}
imgb[i] = 0;
c = colorAt(x, y, background, x1, y1, x2, y2);
img[j + 0] = c[0];
img[j + 1] = c[1];
img[j + 2] = c[2];
img[j + 3] = 255;
}
// render chars
for (i=0; i<n; ++i)
{
c = chars[i];
charbmp = bitmaps.chars[c].bitmap;
x1 = 0;
y1 = rand(0, ch-1);
x2 = cw-1;
y2 = rand(0, ch-1);
for (x=0; x<cw; ++x)
{
for (y=0; y<ch; ++y)
{
alpha = charbmp[x + cw*y];
if (0 < alpha)
{
imgb[x0+x + w*(y0+y)] = alpha;
}
}
}
x0 += cw + space;
}
if ((0 < difficulty) && (0 < distortion_type))
{
switch(distortion_type)
{
case 2:
// create scale-distorted image data based on difficulty level
phase = rand(0, 2) * 3.14 / 2.0;
amplitude = distortion && ('object' === typeof distortion) && HAS.call(distortion, String(difficulty)) ? parseFloat(distortion[String(difficulty)]) : (3 === difficulty ? 0.5 : (2 === difficulty ? 0.25 : 0.15));
x0 = stdMath.max(0, stdMath.round((w - n*(1.0+amplitude)*cw - (n-1)*space) / 2));
for (k=0; k<n; ++k)
{
scale = (1.0 + amplitude * stdMath.sin(phase + 6.28 * 2 * k / n));
sw = stdMath.min(w, stdMath.round(scale * cw));
sh = stdMath.min(h, stdMath.round(scale * ch));
y0 = stdMath.max(0, stdMath.round((h - sh) / 2));
x1 = 0;
y1 = sh/2;
x2 = sw;
y2 = sh/2;
for (ys=0; ys<sh; ++ys)
{
y = stdMath.max(0, stdMath.min(h-1, stdMath.round(10 + ys / scale)));
for (xs=0; xs<sw; ++xs)
{
x = stdMath.max(0, stdMath.min(w-1, stdMath.round(10 + k*(cw+space) + xs / scale)));
alpha = imgb[x + y*w];
if (0 < alpha)
{
alpha /= 255.0;
c = colorAt(xs, ys, color, x1, y1, x2, y2);
j = ((x0+xs + (y0+ys)*w) << 2);
img[j ] = clamp(img[j ]*(1-alpha) + alpha*c[0]);
img[j+1] = clamp(img[j+1]*(1-alpha) + alpha*c[1]);
img[j+2] = clamp(img[j+2]*(1-alpha) + alpha*c[2]);
}
}
}
x0 += space + sw;
}
break;
case 1:
default:
// create position-distorted image data based on difficulty level
phase = rand(0, 2) * 3.14 / 2.0;
amplitude = distortion && ('object' === typeof distortion) && HAS.call(distortion, String(difficulty)) ? parseFloat(distortion[String(difficulty)]) : (3 === difficulty ? 5.0 : (2 === difficulty ? 3.0 : 1.5));
x1 = 0;
y1 = ch/2;
x2 = cw;
y2 = ch/2;
for (y=0,yw=0; y<h; ++y,yw+=w)
{
y0 = y;
for (x=0; x<w; ++x)
{
x0 = x;
y0 = stdMath.max(0, stdMath.min(h-1, stdMath.round(y + amplitude * stdMath.sin(phase + 6.28 * 2 * x / w))));
alpha = imgb[x0 + y0*w];
if (0 < alpha)
{
alpha /= 255.0;
xc = x - 10 + space - stdMath.floor((x - 10 + space)/(cw + space))*(cw + space);
yc = y - 10;
c = colorAt(xc, yc, color, x1, y1, x2, y2);
j = ((x + yw) << 2);
img[j ] = clamp(img[j ]*(1-alpha) + alpha*c[0]);
img[j+1] = clamp(img[j+1]*(1-alpha) + alpha*c[1]);
img[j+2] = clamp(img[j+2]*(1-alpha) + alpha*c[2]);
}
}
}
}
}
else
{
// create non-distorted image data
x1 = 0;
y1 = ch/2;
x2 = cw;
y2 = ch/2;
for (y=0,yw=0; y<h; ++y,yw+=w)
{
for (x=0; x<w; ++x)
{
alpha = imgb[i];
if (0 < alpha)
{
alpha /= 255.0;
// x = x0 + i*cw + (i-1)*space + xc
// xc = x - x0 + space - i*(cw + space)
xc = x - 10 + space - stdMath.floor((x - 10 + space)/(cw + space))*(cw + space);
yc = y - 10;
c = colorAt(xc, yc, color, x1, y1, x2, y2);
j = (i << 2);
img[j ] = clamp(img[j ]*(1-alpha) + alpha*c[0]);
img[j+1] = clamp(img[j+1]*(1-alpha) + alpha*c[1]);
img[j+2] = clamp(img[j+2]*(1-alpha) + alpha*c[2]);
}
}
}
}
// free memory
bitmaps = null;
imgb = null;
return [img, w, h];
}
}
function rand(m, M)
{
return stdMath.round(m + (M - m) * stdMath.random());
}
function split(s)
{
return String(s).split('');
}
function hex(s)
{
return String(s).split('').map(function(c) {return padStart(c.charCodeAt(0).toString(16), 8, '0');}).join('');
}
function is_array(x)
{
return '[object Array]' === toString.call(x);
}
function is_object(x)
{
return '[object Object]' === toString.call(x);
}
function is_callable(x)
{
return 'function' === typeof x;
}
function int(x)
{
return parseInt(x);
}
function hash_equals(h1, h2)
{
var n1 = h1.length, n2 = h2.length,
n = stdMath.max(n1, n2), i, res = true;
for (i=0; i<n; ++i)
{
if (i >= n1)
{
res = res && false;
}
else if (i >= n2)
{
res = res && false;
}
else
{
res = res && (h1.charAt(i) === h2.charAt(i));
}
}
return res;
}
async function createHash(key, data)
{
var hmac = '';
if (isNode)
{
try {
hmac = require('crypto').createHmac('sha256', key).update(data).digest('hex');
} catch (e) {
hmac = hex(data);
}
}
else if (isBrowser)
{
try {
hmac = Array.from(new Uint8Array(await crypto.subtle.digest('SHA-256', (new TextEncoder()).encode(data)))).map(function(b) {return padStart(b.toString(16), 2, '0');}).join('');
} catch (e) {
hmac = hex(data);
}
}
else
{
hmac = hex(data);
}
return hmac;
}
async function imagepng(img, width, height, metaData)
{
metaData = metaData || {};
if (isNode)
{
return 'data:image/png;base64,' + (await (new PNGPacker(metaData)).toPNG(img, width, height)).toString('base64');
}
else if (isBrowser)
{
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'), imgData;
canvas.width = width;
canvas.height = height;
ctx.createImageData(width, height);
imgData = ctx.getImageData(0, 0, width, height);
imgData.data.set(img, 0);
ctx.putImageData(imgData, 0, 0);
return canvas.toDataURL('image/png');
}
return '';
}
function colorAt(x, y, colors, x1, y1, x2, y2)
{
//if (colors.image && colors.width && colors.height) return patternAt(x, y, colors);
if (is_callable(colors)) return colors(x, y);
// linear gradient interpolation between colors
var dx = x2 - x1, dy = y2 - y1,
vert = 0 === dx, hor = 0 === dy, f = 2*dx*dy,
t, px, py, c0, c1, l = colors.length - 1, rgb0, rgb1;
px = x - x1; py = y - y1;
t = hor && vert ? 0 : (vert ? py/dy : (hor ? px/dx : (px*dy + py*dx)/f));
if (0 >= t)
{
c0 = c1 = 0;
t = 0;
}
else if (1 <= t)
{
c0 = c1 = l;
t = 1;
}
else
{
c0 = stdMath.floor(l*t);
c1 = l === c0 ? c0 : (c0 + 1);
}
rgb0 = colors[c0];
rgb1 = colors[c1];
t = c1 > c0 ? (l*t - c0)/(c1 - c0) : t;
return [
clamp((1-t)*((rgb0 >>> 16) & 255) + t*((rgb1 >>> 16) & 255)),
clamp((1-t)*((rgb0 >>> 8) & 255) + t*((rgb1 >>> 8) & 255)),
clamp((1-t)*((rgb0) & 255) + t*((rgb1) & 255))
];
}
/*function patternAt(x, y, pattern)
{
x = stdMath.round(x) % pattern.width;
y = stdMath.round(y) % pattern.height;
if (0 > x) x += pattern.width;
if (0 > y) y += pattern.height;
var i = (x + y*pattern.width) << 2;
return [
pattern.image[i + 0],
pattern.image[i + 1],
pattern.image[i + 2]
];
}*/
function _chars()
{
return {
"fontSize": 20,
"width": 12,
"height": 15,
"chars": {
"0": {
"width": 12,
"height": 15,
"bitmap": [
0,
0,
0,
222,
255,
255,
255,
222,
0,
0,
0,
0,
0,
0,
222,
255,
255,
255,
255,
255,
255,
0,
0,
0,
0,
94,
255,
255,
0,
0,
0,
222,
255,
139,
0,
0,
0,
182,
255,
48,
0,
0,
0,
48,
255,
182,
0,
0,
0,
222,
255,
0,
0,
0,
0,
0,
222,
255,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
255,
222,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
255,
222,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
255,
222,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
255,
222,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
222,
255,
0,
0,
0,
0,
0,
222,
255,
0,
0,
0,
182,
255,
48,
0,
0,
0,
0,
255,
222,
0,
0,
0,
94,
255,
255,
0,
0,
0,
222,
255,
139,
0,
0,
0,
0,
255,
255,
255,
255,
255,
255,
255,
0,
0,
0,
0,
0,
0,
222,
255,
255,
255,
255,
0,
0,
0,
0
]
},
"1": {
"width": 12,
"height": 15,
"bitmap": [
0,
0,
0,
0,
0,
0,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
222,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
222,
255,
255,
139,
0,
0,
0,
0,
0,
0,
94,
255,
255,
222,
255,
139,
0,
0,
0,
0,
0,
0,
222,
255,
48,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0
]
},
"2": {
"width": 12,
"height": 15,
"bitmap": [
0,
0,
0,
255,
255,
255,
255,
182,
0,
0,
0,
0,
0,
48,
255,
255,
255,
255,
255,
255,
255,
0,
0,
0,
0,
222,
255,
139,
0,
0,
0,
222,
255,
139,
0,
0,
0,
255,
182,
0,
0,
0,
0,
48,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
0,
48,
255,
182,
0,
0,
0,
0,
0,
0,
0,
0,
0,
139,
255,
94,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
182,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
222,
255,
182,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
182,
0,
0,
0,
0,
0,
0,
0,
0,
48,
255,
255,
255,
255,
255,
255,
255,
255,
255,
0,
0,
94,
255,
255,
255,
255,
255,
255,
255,
255,
255,
0,
0
]
},
"3": {
"width": 12,
"height": 15,
"bitmap": [
0,
0,
0,
222,
255,
255,
255,
139,
0,
0,
0,
0,
0,
0,
255,
255,
255,
255,
255,
255,
182,
0,
0,
0,
0,
139,
255,
182,
0,
0,
0,
255,
255,
48,
0,
0,
0,
222,
255,
0,
0,
0,
0,
139,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
139,
255,
94,
0,
0,
0,
0,
0,
0,
0,
0,
48,
255,
255,
0,
0,
0,
0,
0,
0,
0,
139,
255,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
139,
255,
255,
255,
255,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
222,
255,
48,
0,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
255,
222,
0,
0,
0,
0,
0,
222,
255,
0,
0,
0,
182,
255,
139,
0,
0,
0,
139,
255,
182,
0,
0,
0,
0,
255,
255,
255,
255,
255,
255,
255,
0,
0,
0,
0,
0,
0,
222,
255,
255,
255,
182,
0,
0,
0,
0
]
},
"4": {
"width": 12,
"height": 15,
"bitmap": [
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
255,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
139,
255,
255,
139,
0,
0,
0,
0,
0,
0,
0,
48,
255,
182,
255,
139,
0,
0,
0,
0,
0,
0,
0,
222,
182,
94,
255,
139,
0,
0,
0,
0,
0,
0,
139,
255,
48,
94,
255,
139,
0,
0,
0,
0,
0,
48,
255,
139,
0,
94,
255,
139,
0,
0,
0,
0,
0,
222,
222,
0,
0,
94,
255,
139,
0,
0,
0,
0,
139,
255,
48,
0,
0,
94,
255,
139,
0,
0,
0,
48,
255,
139,
0,
0,
0,
94,
255,
139,
0,
0,
0,
139,
255,
255,
255,
255,
255,
255,
255,
255,
255,
48,
0,
139,
255,
255,
255,
255,
255,
255,
255,
255,
255,
48,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0
]
},
"5": {
"width": 12,
"height": 15,
"bitmap": [
0,
0,
94,
255,
255,
255,
255,
255,
255,
139,
0,
0,
0,
0,
182,
255,
255,
255,
255,
255,
255,
139,
0,
0,
0,
0,
222,
222,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
255,
182,
0,
0,
0,
0,
0,
0,
0,
0,
0,
48,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
94,
255,
255,
255,
222,
0,
0,
0,
0,
0,
139,
255,
255,
255,
255,
255,
255,
255,
0,
0,
0,
0,
182,
255,
139,
0,
0,
0,
94,
255,
182,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
222,
255,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
255,
222,
0,
0,
0,
0,
0,
222,
255,
0,
0,
0,
182,
255,
139,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
255,
255,
255,
255,
255,
255,
222,
0,
0,
0,
0,
0,
0,
222,
255,
255,
255,
182,
0,
0,
0,
0
]
},
"6": {
"width": 12,
"height": 15,
"bitmap": [
0,
0,
0,
94,
255,
255,
255,
222,
0,
0,
0,
0,
0,
0,
182,
255,
255,
255,
255,
255,
255,
0,
0,
0,
0,
94,
255,
182,
0,
0,
0,
182,
255,
139,
0,
0,
0,
222,
255,
48,
0,
0,
0,
0,
255,
222,
0,
0,
0,
255,
182,
0,
0,
0,
0,
0,
0,
0,
0,
0,
48,
255,
139,
0,
255,
255,
255,
222,
0,
0,
0,
0,
94,
255,
222,
255,
255,
255,
255,
255,
255,
0,
0,
0,
94,
255,
255,
222,
0,
0,
0,
139,
255,
182,
0,
0,
94,
255,
255,
0,
0,
0,
0,
0,
222,
255,
0,
0,
94,
255,
182,
0,
0,
0,
0,
0,
182,
255,
48,
0,
48,
255,
222,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
255,
255,
48,
0,
0,
0,
0,
222,
255,
0,
0,
0,
139,
255,
222,
0,
0,
0,
139,
255,
182,
0,
0,
0,
0,
222,
255,
255,
255,
255,
255,
255,
0,
0,
0,
0,
0,
0,
139,
255,
255,
255,
182,
0,
0,
0,
0
]
},
"7": {
"width": 12,
"height": 15,
"bitmap": [
0,
255,
255,
255,
255,
255,
255,
255,
255,
255,
48,
0,
0,
255,
255,
255,
255,
255,
255,
255,
255,
255,
48,
0,
0,
0,
0,
0,
0,
0,
0,
139,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
48,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
182,
0,
0,
0,
0,
0,
0,
0,
0,
0,
222,
255,
48,
0,
0,
0,
0,
0,
0,
0,
0,
48,
255,
182,
0,
0,
0,
0,
0,
0,
0,
0,
0,
139,
255,
94,
0,
0,
0,
0,
0,
0,
0,
0,
0,
222,
255,
0,
0,
0,
0,
0,
0,
0,
0,
0,
48,
255,
182,
0,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
0,
0,
0,
0,
0,
0,
0,
222,
255,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
222,
255,
0,
0,
0,
0,
0,
0,
0
]
},
"8": {
"width": 12,
"height": 15,
"bitmap": [
0,
0,
0,
182,
255,
255,
255,
182,
0,
0,
0,
0,
0,
0,
222,
255,
255,
255,
255,
255,
222,
0,
0,
0,
0,
94,
255,
182,
0,
0,
0,
182,
255,
139,
0,
0,
0,
139,
255,
94,
0,
0,
0,
48,
255,
182,
0,
0,
0,
139,
255,
94,
0,
0,
0,
48,
255,
182,
0,
0,
0,
48,
255,
182,
0,
0,
0,
139,
255,
94,
0,
0,
0,
0,
94,
255,
255,
255,
255,
255,
94,
0,
0,
0,
0,
0,
182,
255,
255,
255,
255,
255,
182,
0,
0,
0,
0,
139,
255,
139,
0,
0,
0,
94,
255,
182,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
222,
255,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
255,
222,
0,
0,
0,
0,
0,
222,
255,
48,
0,
0,
182,
255,
139,
0,
0,
0,
94,
255,
222,
0,
0,
0,
0,
255,
255,
255,
255,
255,
255,
255,
48,
0,
0,
0,
0,
0,
182,
255,
255,
255,
222,
0,
0,
0,
0
]
},
"9": {
"width": 12,
"height": 15,
"bitmap": [
0,
0,
0,
182,
255,
255,
255,
139,
0,
0,
0,
0,
0,
0,
222,
255,
255,
255,
255,
255,
182,
0,
0,
0,
0,
139,
255,
182,
0,
0,
0,
139,
255,
94,
0,
0,
0,
222,
255,
0,
0,
0,
0,
0,
222,
222,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
182,
255,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
255,
255,
0,
0,
0,
0,
0,
222,
255,
48,
0,
0,
182,
255,
182,
0,
0,
0,
182,
255,
255,
48,
0,
0,
0,
255,
255,
255,
255,
255,
255,
222,
255,
48,
0,
0,
0,
0,
222,
255,
255,
255,
0,
182,
255,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
222,
222,
0,
0,
0,
182,
255,
48,
0,
0,
0,
48,
255,
182,
0,
0,
0,
139,
255,
222,
0,
0,
0,
222,
255,
48,
0,
0,
0,
0,
255,
255,
255,
255,
255,
255,
139,
0,
0,
0,
0,
0,
0,
222,
255,
255,
255,
94,
0,
0,
0,
0
]
},
"+": {
"width": 12,
"height": 10,
"bitmap": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
0,
222,
255,
255,
255,
255,
255,
255,
255,
255,
182,
0,
0,
222,
255,
255,
255,
255,
255,
255,
255,
255,
182,
0,
0,
0,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
},
"-": {
"width": 7,
"height": 2,
"bitmap": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
222,
255,
255,
255,
255,
182,
0,
0,
0,
0,
0,
0,
222,
255,
255,
255,
255,
182,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
},
"×": {
"width": 12,
"height": 9,
"bitmap": [
0,
0,
222,
48,
0,
0,
0,
0,
182,
94,
0,
0,
0,
0,
255,
255,
48,
0,
0,
139,
255,
139,
0,
0,
0,
0,
0,
255,
255,
0,
139,
255,
182,
0,
0,
0,
0,
0,
0,
48,
255,
255,
255,
182,
0,
0,
0,
0,
0,
0,
0,
0,
94,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
48,
255,
255,
255,
182,
0,
0,
0,
0,
0,
0,
0,
255,
255,
0,
139,
255,
182,
0,
0,
0,
0,
0,
255,
255,
48,
0,
0,
139,
255,
139,
0,
0,
0,
0,
222,
48,
0,
0,
0,
0,
182,
94,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
},
"÷": {
"width": 11,
"height": 8,
"bitmap": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
255,
255,
255,
255,
255,
255,
255,
255,
0,
0,
182,
255,
255,
255,
255,
255,
255,
255,
255,
255,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
},
"=": {
"width": 12,
"height": 6,
"bitmap": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
222,
255,
255,
255,
255,
255,
255,
255,
255,
139,
0,
0,
222,
255,
255,
255,
255,
255,
255,
255,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
222,
255,
255,
255,
255,
255,
255,
255,
255,
139,
0,
0,
222,
255,
255,
255,
255,
255,
255,
255,
255,
139,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
},
"?": {
"width": 12,
"height": 15,
"bitmap": [
0,
0,
0,
222,
255,
255,
255,
255,
0,
0,
0,
0,
0,
0,
255,
255,
255,
255,
255,
255,
255,
94,
0,
0,
0,
182,
255,
182,
0,
0,
0,
139,
255,
255,
0,
0,
0,
255,
222,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
48,
0,
0,
0,
0,
0,
0,
0,
0,
139,
255,
182,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
182,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
48,
255,
222,
0,
0,
0,
0,
0,
0,
0,
0,
0,
139,
255,
94,
0,
0,
0,
0,
0,
0,
0,
0,
0,
139,
255,
94,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
139,
255,
94,
0,
0,
0,
0,
0,
0,
0,
0,
0,
139,
255,
94,
0,
0,
0,
0,
0
]
}
}
};
}
// PNG utilities
var PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a],
TYPE_IHDR = 0x49484452,
TYPE_gAMA = 0x67414d41,
TYPE_tRNS = 0x74524e53,
TYPE_PLTE = 0x504c5445,
TYPE_IDAT = 0x49444154,
TYPE_IEND = 0x49454e44,
// color-type bits
COLORTYPE_GRAYSCALE = 0,
COLORTYPE_PALETTE = 1,
COLORTYPE_COLOR = 2,
COLORTYPE_ALPHA = 4, // e.g. grayscale and alpha
// color-type combinations
COLORTYPE_PALETTE_COLOR = 3,
COLORTYPE_COLOR_ALPHA = 6,
COLORTYPE_TO_BPP_MAP = {
0: 1,
2: 3,
3: 1,
4: 2,
6: 4
},
GAMMA_DIVISION = 100000
;
function clamp(value)
{
return stdMath.max(0, stdMath.min(255, stdMath.round(value)));
}
function paethPredictor(left, above, upLeft)
{
var paeth = left + above - upLeft,
pLeft = stdMath.abs(paeth - left),
pAbove = stdMath.abs(paeth - above),
pUpLeft = stdMath.abs(paeth - upLeft)
;
if (pLeft <= pAbove && pLeft <= pUpLeft) return left;
if (pAbove <= pUpLeft) return above;
return upLeft;
}
function filterNone(pxData, pxPos, byteWidth, rawData, rawPos)
{
pxData.copy(rawData, rawPos, pxPos, pxPos + byteWidth);
}
function filterSumNone(pxData, pxPos, byteWidth)
{
var sum = 0, i, length = pxPos + byteWidth;
for (i = pxPos; i < length; i++)
{
sum += stdMath.abs(pxData[i]);
}
return sum;
}
function filterSub(pxData, pxPos, byteWidth, rawData, rawPos, bpp)
{
for (var x = 0; x < byteWidth; x++)
{
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0,
val = pxData[pxPos + x] - left
;
rawData[rawPos + x] = ubyte(val);
}
}
function filterSumSub(pxData, pxPos, byteWidth, bpp)
{
var sum = 0, x;
for (x = 0; x < byteWidth; x++)
{
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0,
val = pxData[pxPos + x] - left
;
sum += stdMath.abs(val);
}
return sum;
}
function filterUp(pxData, pxPos, byteWidth, rawData, rawPos)
{
for (var x = 0; x < byteWidth; x++)
{
var up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0,
val = pxData[pxPos + x] - up
;
rawData[rawPos + x] = ubyte(val);
}
}
function filterSumUp(pxData, pxPos, byteWidth)
{
var sum = 0, x, length = pxPos + byteWidth;
for (x = pxPos; x < length; x++)
{
var up = pxPos > 0 ? pxData[x - byteWidth] : 0,
val = pxData[x] - up
;
sum += stdMath.abs(val);
}
return sum;
}
function filterAvg(pxData, pxPos, byteWidth, rawData, rawPos, bpp)
{
for (var x = 0; x < byteWidth; x++)
{
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0,
up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0,
val = pxData[pxPos + x] - ((left + up) >> 1)
;
rawData[rawPos + x] = ubyte(val);
}
}
function filterSumAvg(pxData, pxPos, byteWidth, bpp)
{
var sum = 0, x;
for (x = 0; x < byteWidth; x++)
{
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0,
up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0,
val = pxData[pxPos + x] - ((left + up) >> 1)
;
sum += stdMath.abs(val);
}
return sum;
}
function filterPaeth(pxData, pxPos, byteWidth, rawData, rawPos, bpp)
{
for (var x = 0; x < byteWidth; x++)
{
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0,
up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0,
upleft = pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0,
val = pxData[pxPos + x] - paethPredictor(left, up, upleft)
;
rawData[rawPos + x] = ubyte(val);
}
}
function filterSumPaeth(pxData, pxPos, byteWidth, bpp)
{
var sum = 0, x;
for (x = 0; x < byteWidth; x++)
{
var left = x >= bpp ? pxData[pxPos + x - bpp] : 0,
up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0,
upleft = pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0,
val = pxData[pxPos + x] - paethPredictor(left, up, upleft)
;
sum += stdMath.abs(val);
}
return sum;
}
async function deflate(data, compressionLevel, chunkSize)
{
var opts = {
chunkSize: null == chunkSize ? 16*1024 : chunkSize,
};
if (null != compressionLevel) opts.level = compressionLevel;
return await (new Promise(function(resolve) {
require('zlib').deflate(data instanceof Buffer ? data : Buffer.from(data), opts, function(err, zdata) {
resolve(err ? null : zdata);
});
}));
}
var crcTable = null;
function getCRCTable()
{
if (null == crcTable)
{
crcTable = new Int32Array(256);
var i, j, currentCrc;
for (i=0; i<256; ++i)
{
currentCrc = i;
for (j=0; j<8; ++j)
{
currentCrc = currentCrc & 1 ? (0xedb88320 ^ (currentCrc >>> 1)) : (currentCrc >>> 1);
}
crcTable[i] = currentCrc;
}
}
return crcTable;
}
function crc32(buffer)
{
var crcTable = getCRCTable(), crc = -1, i, l;
for (i=0,l=buffer.length; i<l; ++i)
{
crc = crcTable[(crc ^ buffer[i]) & 255] ^ (crc >>> 8);
}
return crc ^ (-1);
}
function ubyte(value)
{
return value & 255;
}
function I1(value, buffer = null, pos = 0)
{
if (null == buffer) buffer = Buffer.alloc(1);
if (null == pos) pos = 0;
buffer[pos] = value & 255;
return buffer;
}
function I4(value, buffer = null, pos = 0)
{
if (null == buffer) buffer = Buffer.alloc(4);
if (null == pos) pos = 0;
buffer.writeUInt32BE(value & 0xffffffff, pos);
return buffer;
}
function i4(value, buffer = null, pos = 0)
{
if (null == buffer) buffer = Buffer.alloc(4);
if (null == pos) pos = 0;
buffer.writeInt32BE(value, pos);
return buffer;
}
class PNGPacker
{
_options = null;
constructor(options) {
options = options || {};
options.deflateChunkSize = stdMath.max(1024, parseInt(options.deflateChunkSize || 32 * 1024));
options.deflateLevel = stdMath.min(9, stdMath.max(0, parseInt(options.deflateLevel != null ? options.deflateLevel : 9)));
options.deflateStrategy = stdMath.min(3, stdMath.max(0, parseInt(options.deflateStrategy != null ? options.deflateStrategy : 3)));
options.inputHasAlpha = !!(options.inputHasAlpha != null ? options.inputHasAlpha : true);
options.bitDepth = 8//options.bitDepth || 8;
options.colorType = stdMath.min(6, stdMath.max(0, parseInt(('number' === typeof options.colorType) ? options.colorType : COLORTYPE_COLOR_ALPHA)));
if (options.colorType !== COLORTYPE_COLOR && options.colorType !== COLORTYPE_COLOR_ALPHA)
{
throw new Error('option color type:' + options.colorType + ' is not supported at present');
}
/*if (options.bitDepth !== 8)
{
throw new Error('option bit depth:' + options.bitDepth + ' is not supported at present');
}*/
this._options = options;
}
async toPNG(data, width, height) {
var png = [], filteredData, compressedData, deflateOpts;
// Signature
png.push(Buffer.from(PNG_SIGNATURE));
// Header
png.push(this.packIHDR(width, height));
// gAMA
if (this._options.gamma) png.push(this.packGAMA(this._options.gamma));
// filter data
filteredData = this.filterData(Buffer.from(data), width, height);
// compress data
deflateOpts = this.getDeflateOptions();
compressedData = await deflate(filteredData, deflateOpts.level, deflateOpts.chuckSize);
filteredData = null;
if (!compressedData || !compressedData.length)
throw new Error('bad png - invalid compressed data response');
// Data
png.push(this.packIDAT(Buffer.from(compressedData)));
compressedData = null;
// End
png.push(this.packIEND());
return Buffer.concat(png);
}
getDeflateOptions() {
return {
chunkSize: this._options.deflateChunkSize,
level: this._options.deflateLevel,
strategy: this._options.deflateStrategy
};
}
filterData(data, width, height) {
// convert to correct format for filtering (e.g. right bpp and bit depth)
// and filter pixel data
return this._filter(this._bitPack(data, width, height), width, height);
}
packIHDR(width, height) {
var buffer = Buffer.alloc(13);
I4(width, buffer, 0);
I4(height, buffer, 4);
I1(this._options.bitDepth, buffer, 8); // bit depth
I1(this._options.colorType, buffer, 9); // colorType
I1(0, buffer, 10); // compression
I1(0, buffer, 11); // filter
I1(0, buffer, 12); // interlace
return this._packChunk(TYPE_IHDR, buffer);
}
packGAMA(gamma) {
return this._packChunk(TYPE_gAMA, I4(stdMath.floor(parseFloat(gamma) * GAMMA_DIVISION)));
}
packIDAT(data) {
return this._packChunk(TYPE_IDAT, data);
}
packIEND() {
return this._packChunk(TYPE_IEND, null);
}
_bitPack(data, width, height) {
var inputHasAlpha = this._options.inputHasAlpha,
outHasAlpha = this._options.colorType === COLORTYPE_COLOR_ALPHA;
if (inputHasAlpha && outHasAlpha)
{
return data;
}
if (!inputHasAlpha && !outHasAlpha)
{
return data;
}
var outBpp = outHasAlpha ? 4 : 3,
outData = Buffer.alloc(width * height * outBpp),
inBpp = inputHasAlpha ? 4 : 3,
inIndex = 0,
outIndex = 0,
bgColor = this._options.bgColor || {},
x, y, red, green, blue, alpha,
bgRed, bgGreen, bgBlue
;
bgRed = clamp(bgColor.red != null ? bgColor.red : 255);
bgGreen = clamp(bgColor.green != null ? bgColor.green : 255);
bgBlue = clamp(bgColor.blue != null ? bgColor.blue : 255);
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
red = data[inIndex];
green = data[inIndex + 1];
blue = data[inIndex + 2];
if (inputHasAlpha)
{
alpha = data[inIndex + 3];
if (!outHasAlpha)
{
alpha /= 255.0;
red = (1 - alpha) * bgRed + alpha * red;
green = (1 - alpha) * bgGreen + alpha * green;
blue = (1 - alpha) * bgBlue + alpha * blue;
}
}
else
{
alpha = 255;
}
outData[outIndex] = clamp(red);
outData[outIndex + 1] = clamp(green);
outData[outIndex + 2] = clamp(blue);
if (outHasAlpha) outData[outIndex + 3] = clamp(alpha);
inIndex += inBpp;
outIndex += outBpp;
}
}
return outData;
}
_filter(pxData, width, height) {
var filters = [
filterNone,
filterSub,
filterUp,
filterAvg,
filterPaeth
];
var filterSums = [
filterSumNone,
filterSumSub,
filterSumUp,
filterSumAvg,
filterSumPaeth
];
var filterTypes = [0]; // make it default
/*if ((null == this._options.filterType) || (-1 === this._options.filterType))
{
filterTypes = [0, 1, 2, 3, 4];
}
else if ('number' === typeof this._options.filterType)
{
filterTypes = [this._options.filterType];
}
else
{
throw new Error('unrecognised filter types');
}*/
var bpp = COLORTYPE_TO_BPP_MAP[this._options.colorType],
byteWidth = width * bpp,
rawPos = 0, pxPos = 0,
rawData = Buffer.alloc((byteWidth + 1) * height),
sel = filterTypes[0],
y, i, n = filterTypes.length, min, sum
;
for (y = 0; y < height; y++)
{
if (n > 1)
{
// find best filter for this line (with lowest sum of values)
min = Infinity;
for (i=0; i<n; i++)
{
sum = filterSums[filterTypes[i]](pxData, pxPos, byteWidth, bpp);
if (sum < min)
{
sel = filterTypes[i];
min = sum;
}
}
}
rawData[rawPos] = sel;
rawPos++;
filters[sel](pxData, pxPos, byteWidth, rawData, rawPos, bpp);
rawPos += byteWidth;
pxPos += byteWidth;
}
return rawData;
}
_packChunk(type, data = null) {
var length = data ? data.length : 0,
buffer = Buffer.alloc(length + 12)
;
I4(length, buffer, 0);
I4(type, buffer, 4);
if (data) data.copy(buffer, 8);
i4(crc32(buffer.slice(4, buffer.length - 4)), buffer, buffer.length - 4);
return buffer;
}
}
// export it
return SimpleCaptcha;
});
|