WIP - add extractor, generate snippet_data

This commit is contained in:
Stefan Fejes
2019-08-20 15:52:05 +02:00
parent 88084d3d30
commit cc8f1d8a7a
37396 changed files with 4588842 additions and 133 deletions

21
node_modules/@jimp/plugin-color/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Oliver Moran
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

256
node_modules/@jimp/plugin-color/README.md generated vendored Normal file
View File

@ -0,0 +1,256 @@
<div align="center">
<img width="200" height="200"
src="https://s3.amazonaws.com/pix.iemoji.com/images/emoji/apple/ios-11/256/crayon.png">
<h1>@jimp/plugin-color</h1>
<p>Jimp color methods.</p>
</div>
Bitmap manipulation to adjust the color in an image.
## color
Apply multiple color modification rules
- @param {array} actions list of color modification rules, in following format: { apply: '<rule-name>', params: [ <rule-parameters> ] }
- @param {function(Error, Jimp)} cb (optional) a callback for when complete
```js
import jimp from 'jimp';
async function main() {
const image = await jimp.read('test/image.png');
image.color([{ apply: 'red', params: [100] }]);
}
main();
```
Jimp supports advanced colour manipulation using a single method as follows:
```js
image.color([
{ apply: 'hue', params: [-90] },
{ apply: 'lighten', params: [50] },
{ apply: 'xor', params: ['#06D'] }
]);
```
The method supports the following modifiers:
| Modifier | Description |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **lighten** {amount} | Lighten the color a given amount, from 0 to 100. Providing 100 will always return white (works through [TinyColor](https://github.com/bgrins/TinyColor)) |
| **brighten** {amount} | Brighten the color a given amount, from 0 to 100 (works through [TinyColor](https://github.com/bgrins/TinyColor)) |
| **darken** {amount} | Darken the color a given amount, from 0 to 100. Providing 100 will always return black (works through [TinyColor](https://github.com/bgrins/TinyColor)) |
| **desaturate** {amount} | Desaturate the color a given amount, from 0 to 100. Providing 100 will is the same as calling greyscale (works through [TinyColor](https://github.com/bgrins/TinyColor)) |
| **saturate** {amount} | Saturate the color a given amount, from 0 to 100 (works through [TinyColor](https://github.com/bgrins/TinyColor)) |
| **greyscale** {amount} | Completely desaturates a color into greyscale (works through [TinyColor](https://github.com/bgrins/TinyColor)) |
| **spin** {degree} | Spin the hue a given amount, from -360 to 360. Calling with 0, 360, or -360 will do nothing - since it sets the hue back to what it was before. (works through [TinyColor](https://github.com/bgrins/TinyColor)) |
| **hue** {degree} | Alias for **spin** |
| **mix** {color, amount} | Mixes colors by their RGB component values. Amount is opacity of overlaying color |
| **tint** {amount} | Same as applying **mix** with white color |
| **shade** {amount} | Same as applying **mix** with black color |
| **xor** {color} | Treats the two colors as bitfields and applies an XOR operation to the red, green, and blue components |
| **red** {amount} | Modify Red component by a given amount |
| **green** {amount} | Modify Green component by a given amount |
| **blue** {amount} | Modify Blue component by a given amount |
## brightness
Adjusts the brightness of the image
- @param {number} val the amount to adjust the brightness, a number between -1 and +1
- @param {function(Error, Jimp)} cb (optional) a callback for when complete
```js
import jimp from 'jimp';
async function main() {
const image = await jimp.read('test/image.png');
image.brightness(20);
}
main();
```
## contrast
Adjusts the contrast of the image
- @param {number} val the amount to adjust the contrast, a number between -1 and +1
- @param {function(Error, Jimp)} cb (optional) a callback for when complete
```js
import jimp from 'jimp';
async function main() {
const image = await jimp.read('test/image.png');
image.contrast(70);
}
main();
```
## posterize
Apply a posterize effect
- @param {number} n the amount to adjust the contrast, minimum threshold is two
- @param {function(Error, Jimp)} cb (optional) a callback for when complete
```js
import jimp from 'jimp';
async function main() {
const image = await jimp.read('test/image.png');
image.posterize(5);
}
main();
```
## opacity
Multiplies the opacity of each pixel by a factor between 0 and 1
- @param {number} f A number, the factor by which to multiply the opacity of each pixel
- @param {function(Error, Jimp)} cb (optional) a callback for when complete
```js
import jimp from 'jimp';
async function main() {
const image = await jimp.read('test/image.png');
image.opacity(80);
}
main();
```
## sepia
Applies a sepia tone to the image
- @param {function(Error, Jimp)} cb (optional) a callback for when complete
```js
import jimp from 'jimp';
async function main() {
const image = await jimp.read('test/image.png');
image.sepia();
}
main();
```
## fade
Fades each pixel by a factor between 0 and 1
- @param {number} f A number from 0 to 1. 0 will haven no effect. 1 will turn the image completely transparent.
- @param {function(Error, Jimp)} cb (optional) a callback for when complete
```js
import jimp from 'jimp';
async function main() {
const image = await jimp.read('test/image.png');
image.fade(0.7);
}
main();
```
## convolution
Sum neighbor pixels weighted by the kernel matrix. You can find a nice explanation with examples at [GIMP's Convolution Matrix plugin](https://docs.gimp.org/2.6/en/plug-in-convmatrix.html)
- @param {array} kernel a matrix to weight the neighbors sum
- @param {string} edgeHandling (optional) define how to sum pixels from outside the border
- @param {function(Error, Jimp)} cb (optional) a callback for when complete
```js
import jimp from 'jimp';
async function main() {
const image = await jimp.read('test/image.png');
// make me better
image.convolution(weights);
}
main();
```
## opaque
Set the alpha channel on every pixel to fully opaque
- @param {function(Error, Jimp)} cb (optional) a callback for when complete
```js
import jimp from 'jimp';
async function main() {
const image = await jimp.read('test/image.png');
image.opaque();
}
main();
```
## pixelate
Pixelates the image or a region
- @param {number} size the size of the pixels
- @param {number} x (optional) the x position of the region to pixelate
- @param {number} y (optional) the y position of the region to pixelate
- @param {number} w (optional) the width of the region to pixelate
- @param {number} h (optional) the height of the region to pixelate
- @param {function(Error, Jimp)} cb (optional) a callback for when complete
```js
import jimp from 'jimp';
async function main() {
const image = await jimp.read('test/image.png');
image.pixelate(10);
}
main();
```
## convolute
Applies a convolution kernel to the image or a region
- @param {array} kernel the convolution kernel
- @param {number} x (optional) the x position of the region to apply convolution to
- @param {number} y (optional) the y position of the region to apply convolution to
- @param {number} w (optional) the width of the region to apply convolution to
- @param {number} h (optional) the height of the region to apply convolution to
- @param {function(Error, Jimp)} cb (optional) a callback for when complete
```js
import jimp from 'jimp';
async function main() {
const image = await jimp.read('test/image.png');
// make me better
image.pixelate(kernal);
}
main();
```

595
node_modules/@jimp/plugin-color/dist/index.js generated vendored Normal file
View File

@ -0,0 +1,595 @@
"use strict";
require("core-js/modules/es6.object.define-property");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
require("core-js/modules/es6.string.iterator");
require("core-js/modules/es6.array.from");
require("core-js/modules/es6.regexp.to-string");
require("core-js/modules/es6.date.to-string");
require("core-js/modules/es7.symbol.async-iterator");
require("core-js/modules/es6.symbol");
require("core-js/modules/web.dom.iterable");
require("core-js/modules/es6.array.for-each");
require("core-js/modules/es6.array.map");
require("core-js/modules/es6.array.is-array");
var _tinycolor = _interopRequireDefault(require("tinycolor2"));
var _utils = require("@jimp/utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
function applyKernel(im, kernel, x, y) {
var value = [0, 0, 0];
var size = (kernel.length - 1) / 2;
for (var kx = 0; kx < kernel.length; kx += 1) {
for (var ky = 0; ky < kernel[kx].length; ky += 1) {
var idx = im.getPixelIndex(x + kx - size, y + ky - size);
value[0] += im.bitmap.data[idx] * kernel[kx][ky];
value[1] += im.bitmap.data[idx + 1] * kernel[kx][ky];
value[2] += im.bitmap.data[idx + 2] * kernel[kx][ky];
}
}
return value;
}
var isDef = function isDef(v) {
return typeof v !== 'undefined' && v !== null;
};
function greyscale(cb) {
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
var grey = parseInt(0.2126 * this.bitmap.data[idx] + 0.7152 * this.bitmap.data[idx + 1] + 0.0722 * this.bitmap.data[idx + 2], 10);
this.bitmap.data[idx] = grey;
this.bitmap.data[idx + 1] = grey;
this.bitmap.data[idx + 2] = grey;
});
if ((0, _utils.isNodePattern)(cb)) {
cb.call(this, null, this);
}
return this;
}
function mix(clr, clr2) {
var p = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 50;
return {
r: (clr2.r - clr.r) * (p / 100) + clr.r,
g: (clr2.g - clr.g) * (p / 100) + clr.g,
b: (clr2.b - clr.b) * (p / 100) + clr.b
};
}
function colorFn(actions, cb) {
var _this = this;
if (!actions || !Array.isArray(actions)) {
return _utils.throwError.call(this, 'actions must be an array', cb);
}
actions = actions.map(function (action) {
if (action.apply === 'xor' || action.apply === 'mix') {
action.params[0] = (0, _tinycolor.default)(action.params[0]).toRgb();
}
return action;
});
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
var clr = {
r: _this.bitmap.data[idx],
g: _this.bitmap.data[idx + 1],
b: _this.bitmap.data[idx + 2]
};
var colorModifier = function colorModifier(i, amount) {
return _this.constructor.limit255(clr[i] + amount);
};
actions.forEach(function (action) {
if (action.apply === 'mix') {
clr = mix(clr, action.params[0], action.params[1]);
} else if (action.apply === 'tint') {
clr = mix(clr, {
r: 255,
g: 255,
b: 255
}, action.params[0]);
} else if (action.apply === 'shade') {
clr = mix(clr, {
r: 0,
g: 0,
b: 0
}, action.params[0]);
} else if (action.apply === 'xor') {
clr = {
r: clr.r ^ action.params[0].r,
g: clr.g ^ action.params[0].g,
b: clr.b ^ action.params[0].b
};
} else if (action.apply === 'red') {
clr.r = colorModifier('r', action.params[0]);
} else if (action.apply === 'green') {
clr.g = colorModifier('g', action.params[0]);
} else if (action.apply === 'blue') {
clr.b = colorModifier('b', action.params[0]);
} else {
var _clr;
if (action.apply === 'hue') {
action.apply = 'spin';
}
clr = (0, _tinycolor.default)(clr);
if (!clr[action.apply]) {
return _utils.throwError.call(_this, 'action ' + action.apply + ' not supported', cb);
}
clr = (_clr = clr)[action.apply].apply(_clr, _toConsumableArray(action.params)).toRgb();
}
});
_this.bitmap.data[idx] = clr.r;
_this.bitmap.data[idx + 1] = clr.g;
_this.bitmap.data[idx + 2] = clr.b;
});
if ((0, _utils.isNodePattern)(cb)) {
cb.call(this, null, this);
}
return this;
}
var _default = function _default() {
return {
/**
* Adjusts the brightness of the image
* @param {number} val the amount to adjust the brightness, a number between -1 and +1
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
brightness: function brightness(val, cb) {
if (typeof val !== 'number') {
return _utils.throwError.call(this, 'val must be numbers', cb);
}
if (val < -1 || val > +1) {
return _utils.throwError.call(this, 'val must be a number between -1 and +1', cb);
}
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
if (val < 0.0) {
this.bitmap.data[idx] = this.bitmap.data[idx] * (1 + val);
this.bitmap.data[idx + 1] = this.bitmap.data[idx + 1] * (1 + val);
this.bitmap.data[idx + 2] = this.bitmap.data[idx + 2] * (1 + val);
} else {
this.bitmap.data[idx] = this.bitmap.data[idx] + (255 - this.bitmap.data[idx]) * val;
this.bitmap.data[idx + 1] = this.bitmap.data[idx + 1] + (255 - this.bitmap.data[idx + 1]) * val;
this.bitmap.data[idx + 2] = this.bitmap.data[idx + 2] + (255 - this.bitmap.data[idx + 2]) * val;
}
});
if ((0, _utils.isNodePattern)(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Adjusts the contrast of the image
* @param {number} val the amount to adjust the contrast, a number between -1 and +1
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
contrast: function contrast(val, cb) {
if (typeof val !== 'number') {
return _utils.throwError.call(this, 'val must be numbers', cb);
}
if (val < -1 || val > +1) {
return _utils.throwError.call(this, 'val must be a number between -1 and +1', cb);
}
var factor = (val + 1) / (1 - val);
function adjust(value) {
value = Math.floor(factor * (value - 127) + 127);
return value < 0 ? 0 : value > 255 ? 255 : value;
}
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
this.bitmap.data[idx] = adjust(this.bitmap.data[idx]);
this.bitmap.data[idx + 1] = adjust(this.bitmap.data[idx + 1]);
this.bitmap.data[idx + 2] = adjust(this.bitmap.data[idx + 2]);
});
if ((0, _utils.isNodePattern)(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Apply a posterize effect
* @param {number} n the amount to adjust the contrast, minimum threshold is two
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
posterize: function posterize(n, cb) {
if (typeof n !== 'number') {
return _utils.throwError.call(this, 'n must be numbers', cb);
}
if (n < 2) {
n = 2;
} // minimum of 2 levels
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
this.bitmap.data[idx] = Math.floor(this.bitmap.data[idx] / 255 * (n - 1)) / (n - 1) * 255;
this.bitmap.data[idx + 1] = Math.floor(this.bitmap.data[idx + 1] / 255 * (n - 1)) / (n - 1) * 255;
this.bitmap.data[idx + 2] = Math.floor(this.bitmap.data[idx + 2] / 255 * (n - 1)) / (n - 1) * 255;
});
if ((0, _utils.isNodePattern)(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Removes colour from the image using ITU Rec 709 luminance values
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
greyscale: greyscale,
// Alias of greyscale for our American friends
grayscale: greyscale,
/**
* Multiplies the opacity of each pixel by a factor between 0 and 1
* @param {number} f A number, the factor by which to multiply the opacity of each pixel
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
opacity: function opacity(f, cb) {
if (typeof f !== 'number') return _utils.throwError.call(this, 'f must be a number', cb);
if (f < 0 || f > 1) return _utils.throwError.call(this, 'f must be a number from 0 to 1', cb);
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
var v = this.bitmap.data[idx + 3] * f;
this.bitmap.data[idx + 3] = v;
});
if ((0, _utils.isNodePattern)(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Applies a sepia tone to the image
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
sepia: function sepia(cb) {
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
var red = this.bitmap.data[idx];
var green = this.bitmap.data[idx + 1];
var blue = this.bitmap.data[idx + 2];
red = red * 0.393 + green * 0.769 + blue * 0.189;
green = red * 0.349 + green * 0.686 + blue * 0.168;
blue = red * 0.272 + green * 0.534 + blue * 0.131;
this.bitmap.data[idx] = red < 255 ? red : 255;
this.bitmap.data[idx + 1] = green < 255 ? green : 255;
this.bitmap.data[idx + 2] = blue < 255 ? blue : 255;
});
if ((0, _utils.isNodePattern)(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Fades each pixel by a factor between 0 and 1
* @param {number} f A number from 0 to 1. 0 will haven no effect. 1 will turn the image completely transparent.
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
fade: function fade(f, cb) {
if (typeof f !== 'number') {
return _utils.throwError.call(this, 'f must be a number', cb);
}
if (f < 0 || f > 1) {
return _utils.throwError.call(this, 'f must be a number from 0 to 1', cb);
} // this method is an alternative to opacity (which may be deprecated)
this.opacity(1 - f);
if ((0, _utils.isNodePattern)(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Adds each element of the image to its local neighbors, weighted by the kernel
* @param {array} kernel a matrix to weight the neighbors sum
* @param {string} edgeHandling (optional) define how to sum pixels from outside the border
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
convolution: function convolution(kernel, edgeHandling, cb) {
if (typeof edgeHandling === 'function' && typeof cb === 'undefined') {
cb = edgeHandling;
edgeHandling = null;
}
if (!edgeHandling) {
edgeHandling = this.constructor.EDGE_EXTEND;
}
var newData = Buffer.from(this.bitmap.data);
var kRows = kernel.length;
var kCols = kernel[0].length;
var rowEnd = Math.floor(kRows / 2);
var colEnd = Math.floor(kCols / 2);
var rowIni = -rowEnd;
var colIni = -colEnd;
var weight;
var rSum;
var gSum;
var bSum;
var ri;
var gi;
var bi;
var xi;
var yi;
var idxi;
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
bSum = 0;
gSum = 0;
rSum = 0;
for (var row = rowIni; row <= rowEnd; row++) {
for (var col = colIni; col <= colEnd; col++) {
xi = x + col;
yi = y + row;
weight = kernel[row + rowEnd][col + colEnd];
idxi = this.getPixelIndex(xi, yi, edgeHandling);
if (idxi === -1) {
bi = 0;
gi = 0;
ri = 0;
} else {
ri = this.bitmap.data[idxi + 0];
gi = this.bitmap.data[idxi + 1];
bi = this.bitmap.data[idxi + 2];
}
rSum += weight * ri;
gSum += weight * gi;
bSum += weight * bi;
}
}
if (rSum < 0) {
rSum = 0;
}
if (gSum < 0) {
gSum = 0;
}
if (bSum < 0) {
bSum = 0;
}
if (rSum > 255) {
rSum = 255;
}
if (gSum > 255) {
gSum = 255;
}
if (bSum > 255) {
bSum = 255;
}
newData[idx + 0] = rSum;
newData[idx + 1] = gSum;
newData[idx + 2] = bSum;
});
this.bitmap.data = newData;
if ((0, _utils.isNodePattern)(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Set the alpha channel on every pixel to fully opaque
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
opaque: function opaque(cb) {
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
this.bitmap.data[idx + 3] = 255;
});
if ((0, _utils.isNodePattern)(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Pixelates the image or a region
* @param {number} size the size of the pixels
* @param {number} x (optional) the x position of the region to pixelate
* @param {number} y (optional) the y position of the region to pixelate
* @param {number} w (optional) the width of the region to pixelate
* @param {number} h (optional) the height of the region to pixelate
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
pixelate: function pixelate(size, x, y, w, h, cb) {
if (typeof x === 'function') {
cb = x;
h = null;
w = null;
y = null;
x = null;
} else {
if (typeof size !== 'number') {
return _utils.throwError.call(this, 'size must be a number', cb);
}
if (isDef(x) && typeof x !== 'number') {
return _utils.throwError.call(this, 'x must be a number', cb);
}
if (isDef(y) && typeof y !== 'number') {
return _utils.throwError.call(this, 'y must be a number', cb);
}
if (isDef(w) && typeof w !== 'number') {
return _utils.throwError.call(this, 'w must be a number', cb);
}
if (isDef(h) && typeof h !== 'number') {
return _utils.throwError.call(this, 'h must be a number', cb);
}
}
var kernel = [[1 / 16, 2 / 16, 1 / 16], [2 / 16, 4 / 16, 2 / 16], [1 / 16, 2 / 16, 1 / 16]];
x = x || 0;
y = y || 0;
w = isDef(w) ? w : this.bitmap.width - x;
h = isDef(h) ? h : this.bitmap.height - y;
var source = this.cloneQuiet();
this.scanQuiet(x, y, w, h, function (xx, yx, idx) {
xx = size * Math.floor(xx / size);
yx = size * Math.floor(yx / size);
var value = applyKernel(source, kernel, xx, yx);
this.bitmap.data[idx] = value[0];
this.bitmap.data[idx + 1] = value[1];
this.bitmap.data[idx + 2] = value[2];
});
if ((0, _utils.isNodePattern)(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Applies a convolution kernel to the image or a region
* @param {array} kernel the convolution kernel
* @param {number} x (optional) the x position of the region to apply convolution to
* @param {number} y (optional) the y position of the region to apply convolution to
* @param {number} w (optional) the width of the region to apply convolution to
* @param {number} h (optional) the height of the region to apply convolution to
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
convolute: function convolute(kernel, x, y, w, h, cb) {
if (!Array.isArray(kernel)) return _utils.throwError.call(this, 'the kernel must be an array', cb);
if (typeof x === 'function') {
cb = x;
x = null;
y = null;
w = null;
h = null;
} else {
if (isDef(x) && typeof x !== 'number') {
return _utils.throwError.call(this, 'x must be a number', cb);
}
if (isDef(y) && typeof y !== 'number') {
return _utils.throwError.call(this, 'y must be a number', cb);
}
if (isDef(w) && typeof w !== 'number') {
return _utils.throwError.call(this, 'w must be a number', cb);
}
if (isDef(h) && typeof h !== 'number') {
return _utils.throwError.call(this, 'h must be a number', cb);
}
}
var ksize = (kernel.length - 1) / 2;
x = isDef(x) ? x : ksize;
y = isDef(y) ? y : ksize;
w = isDef(w) ? w : this.bitmap.width - x;
h = isDef(h) ? h : this.bitmap.height - y;
var source = this.cloneQuiet();
this.scanQuiet(x, y, w, h, function (xx, yx, idx) {
var value = applyKernel(source, kernel, xx, yx);
this.bitmap.data[idx] = this.constructor.limit255(value[0]);
this.bitmap.data[idx + 1] = this.constructor.limit255(value[1]);
this.bitmap.data[idx + 2] = this.constructor.limit255(value[2]);
});
if ((0, _utils.isNodePattern)(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Apply multiple color modification rules
* @param {array} actions list of color modification rules, in following format: { apply: '<rule-name>', params: [ <rule-parameters> ] }
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
color: colorFn,
colour: colorFn
};
};
exports.default = _default;
module.exports = exports.default;
//# sourceMappingURL=index.js.map

1
node_modules/@jimp/plugin-color/dist/index.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

560
node_modules/@jimp/plugin-color/es/index.js generated vendored Normal file
View File

@ -0,0 +1,560 @@
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
import tinyColor from 'tinycolor2';
import { throwError, isNodePattern } from '@jimp/utils';
function applyKernel(im, kernel, x, y) {
var value = [0, 0, 0];
var size = (kernel.length - 1) / 2;
for (var kx = 0; kx < kernel.length; kx += 1) {
for (var ky = 0; ky < kernel[kx].length; ky += 1) {
var idx = im.getPixelIndex(x + kx - size, y + ky - size);
value[0] += im.bitmap.data[idx] * kernel[kx][ky];
value[1] += im.bitmap.data[idx + 1] * kernel[kx][ky];
value[2] += im.bitmap.data[idx + 2] * kernel[kx][ky];
}
}
return value;
}
var isDef = function isDef(v) {
return typeof v !== 'undefined' && v !== null;
};
function greyscale(cb) {
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
var grey = parseInt(0.2126 * this.bitmap.data[idx] + 0.7152 * this.bitmap.data[idx + 1] + 0.0722 * this.bitmap.data[idx + 2], 10);
this.bitmap.data[idx] = grey;
this.bitmap.data[idx + 1] = grey;
this.bitmap.data[idx + 2] = grey;
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
}
function mix(clr, clr2) {
var p = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 50;
return {
r: (clr2.r - clr.r) * (p / 100) + clr.r,
g: (clr2.g - clr.g) * (p / 100) + clr.g,
b: (clr2.b - clr.b) * (p / 100) + clr.b
};
}
function colorFn(actions, cb) {
var _this = this;
if (!actions || !Array.isArray(actions)) {
return throwError.call(this, 'actions must be an array', cb);
}
actions = actions.map(function (action) {
if (action.apply === 'xor' || action.apply === 'mix') {
action.params[0] = tinyColor(action.params[0]).toRgb();
}
return action;
});
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
var clr = {
r: _this.bitmap.data[idx],
g: _this.bitmap.data[idx + 1],
b: _this.bitmap.data[idx + 2]
};
var colorModifier = function colorModifier(i, amount) {
return _this.constructor.limit255(clr[i] + amount);
};
actions.forEach(function (action) {
if (action.apply === 'mix') {
clr = mix(clr, action.params[0], action.params[1]);
} else if (action.apply === 'tint') {
clr = mix(clr, {
r: 255,
g: 255,
b: 255
}, action.params[0]);
} else if (action.apply === 'shade') {
clr = mix(clr, {
r: 0,
g: 0,
b: 0
}, action.params[0]);
} else if (action.apply === 'xor') {
clr = {
r: clr.r ^ action.params[0].r,
g: clr.g ^ action.params[0].g,
b: clr.b ^ action.params[0].b
};
} else if (action.apply === 'red') {
clr.r = colorModifier('r', action.params[0]);
} else if (action.apply === 'green') {
clr.g = colorModifier('g', action.params[0]);
} else if (action.apply === 'blue') {
clr.b = colorModifier('b', action.params[0]);
} else {
var _clr;
if (action.apply === 'hue') {
action.apply = 'spin';
}
clr = tinyColor(clr);
if (!clr[action.apply]) {
return throwError.call(_this, 'action ' + action.apply + ' not supported', cb);
}
clr = (_clr = clr)[action.apply].apply(_clr, _toConsumableArray(action.params)).toRgb();
}
});
_this.bitmap.data[idx] = clr.r;
_this.bitmap.data[idx + 1] = clr.g;
_this.bitmap.data[idx + 2] = clr.b;
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
}
export default (function () {
return {
/**
* Adjusts the brightness of the image
* @param {number} val the amount to adjust the brightness, a number between -1 and +1
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
brightness: function brightness(val, cb) {
if (typeof val !== 'number') {
return throwError.call(this, 'val must be numbers', cb);
}
if (val < -1 || val > +1) {
return throwError.call(this, 'val must be a number between -1 and +1', cb);
}
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
if (val < 0.0) {
this.bitmap.data[idx] = this.bitmap.data[idx] * (1 + val);
this.bitmap.data[idx + 1] = this.bitmap.data[idx + 1] * (1 + val);
this.bitmap.data[idx + 2] = this.bitmap.data[idx + 2] * (1 + val);
} else {
this.bitmap.data[idx] = this.bitmap.data[idx] + (255 - this.bitmap.data[idx]) * val;
this.bitmap.data[idx + 1] = this.bitmap.data[idx + 1] + (255 - this.bitmap.data[idx + 1]) * val;
this.bitmap.data[idx + 2] = this.bitmap.data[idx + 2] + (255 - this.bitmap.data[idx + 2]) * val;
}
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Adjusts the contrast of the image
* @param {number} val the amount to adjust the contrast, a number between -1 and +1
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
contrast: function contrast(val, cb) {
if (typeof val !== 'number') {
return throwError.call(this, 'val must be numbers', cb);
}
if (val < -1 || val > +1) {
return throwError.call(this, 'val must be a number between -1 and +1', cb);
}
var factor = (val + 1) / (1 - val);
function adjust(value) {
value = Math.floor(factor * (value - 127) + 127);
return value < 0 ? 0 : value > 255 ? 255 : value;
}
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
this.bitmap.data[idx] = adjust(this.bitmap.data[idx]);
this.bitmap.data[idx + 1] = adjust(this.bitmap.data[idx + 1]);
this.bitmap.data[idx + 2] = adjust(this.bitmap.data[idx + 2]);
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Apply a posterize effect
* @param {number} n the amount to adjust the contrast, minimum threshold is two
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
posterize: function posterize(n, cb) {
if (typeof n !== 'number') {
return throwError.call(this, 'n must be numbers', cb);
}
if (n < 2) {
n = 2;
} // minimum of 2 levels
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
this.bitmap.data[idx] = Math.floor(this.bitmap.data[idx] / 255 * (n - 1)) / (n - 1) * 255;
this.bitmap.data[idx + 1] = Math.floor(this.bitmap.data[idx + 1] / 255 * (n - 1)) / (n - 1) * 255;
this.bitmap.data[idx + 2] = Math.floor(this.bitmap.data[idx + 2] / 255 * (n - 1)) / (n - 1) * 255;
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Removes colour from the image using ITU Rec 709 luminance values
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
greyscale: greyscale,
// Alias of greyscale for our American friends
grayscale: greyscale,
/**
* Multiplies the opacity of each pixel by a factor between 0 and 1
* @param {number} f A number, the factor by which to multiply the opacity of each pixel
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
opacity: function opacity(f, cb) {
if (typeof f !== 'number') return throwError.call(this, 'f must be a number', cb);
if (f < 0 || f > 1) return throwError.call(this, 'f must be a number from 0 to 1', cb);
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
var v = this.bitmap.data[idx + 3] * f;
this.bitmap.data[idx + 3] = v;
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Applies a sepia tone to the image
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
sepia: function sepia(cb) {
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
var red = this.bitmap.data[idx];
var green = this.bitmap.data[idx + 1];
var blue = this.bitmap.data[idx + 2];
red = red * 0.393 + green * 0.769 + blue * 0.189;
green = red * 0.349 + green * 0.686 + blue * 0.168;
blue = red * 0.272 + green * 0.534 + blue * 0.131;
this.bitmap.data[idx] = red < 255 ? red : 255;
this.bitmap.data[idx + 1] = green < 255 ? green : 255;
this.bitmap.data[idx + 2] = blue < 255 ? blue : 255;
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Fades each pixel by a factor between 0 and 1
* @param {number} f A number from 0 to 1. 0 will haven no effect. 1 will turn the image completely transparent.
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
fade: function fade(f, cb) {
if (typeof f !== 'number') {
return throwError.call(this, 'f must be a number', cb);
}
if (f < 0 || f > 1) {
return throwError.call(this, 'f must be a number from 0 to 1', cb);
} // this method is an alternative to opacity (which may be deprecated)
this.opacity(1 - f);
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Adds each element of the image to its local neighbors, weighted by the kernel
* @param {array} kernel a matrix to weight the neighbors sum
* @param {string} edgeHandling (optional) define how to sum pixels from outside the border
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
convolution: function convolution(kernel, edgeHandling, cb) {
if (typeof edgeHandling === 'function' && typeof cb === 'undefined') {
cb = edgeHandling;
edgeHandling = null;
}
if (!edgeHandling) {
edgeHandling = this.constructor.EDGE_EXTEND;
}
var newData = Buffer.from(this.bitmap.data);
var kRows = kernel.length;
var kCols = kernel[0].length;
var rowEnd = Math.floor(kRows / 2);
var colEnd = Math.floor(kCols / 2);
var rowIni = -rowEnd;
var colIni = -colEnd;
var weight;
var rSum;
var gSum;
var bSum;
var ri;
var gi;
var bi;
var xi;
var yi;
var idxi;
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
bSum = 0;
gSum = 0;
rSum = 0;
for (var row = rowIni; row <= rowEnd; row++) {
for (var col = colIni; col <= colEnd; col++) {
xi = x + col;
yi = y + row;
weight = kernel[row + rowEnd][col + colEnd];
idxi = this.getPixelIndex(xi, yi, edgeHandling);
if (idxi === -1) {
bi = 0;
gi = 0;
ri = 0;
} else {
ri = this.bitmap.data[idxi + 0];
gi = this.bitmap.data[idxi + 1];
bi = this.bitmap.data[idxi + 2];
}
rSum += weight * ri;
gSum += weight * gi;
bSum += weight * bi;
}
}
if (rSum < 0) {
rSum = 0;
}
if (gSum < 0) {
gSum = 0;
}
if (bSum < 0) {
bSum = 0;
}
if (rSum > 255) {
rSum = 255;
}
if (gSum > 255) {
gSum = 255;
}
if (bSum > 255) {
bSum = 255;
}
newData[idx + 0] = rSum;
newData[idx + 1] = gSum;
newData[idx + 2] = bSum;
});
this.bitmap.data = newData;
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Set the alpha channel on every pixel to fully opaque
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
opaque: function opaque(cb) {
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function (x, y, idx) {
this.bitmap.data[idx + 3] = 255;
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Pixelates the image or a region
* @param {number} size the size of the pixels
* @param {number} x (optional) the x position of the region to pixelate
* @param {number} y (optional) the y position of the region to pixelate
* @param {number} w (optional) the width of the region to pixelate
* @param {number} h (optional) the height of the region to pixelate
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
pixelate: function pixelate(size, x, y, w, h, cb) {
if (typeof x === 'function') {
cb = x;
h = null;
w = null;
y = null;
x = null;
} else {
if (typeof size !== 'number') {
return throwError.call(this, 'size must be a number', cb);
}
if (isDef(x) && typeof x !== 'number') {
return throwError.call(this, 'x must be a number', cb);
}
if (isDef(y) && typeof y !== 'number') {
return throwError.call(this, 'y must be a number', cb);
}
if (isDef(w) && typeof w !== 'number') {
return throwError.call(this, 'w must be a number', cb);
}
if (isDef(h) && typeof h !== 'number') {
return throwError.call(this, 'h must be a number', cb);
}
}
var kernel = [[1 / 16, 2 / 16, 1 / 16], [2 / 16, 4 / 16, 2 / 16], [1 / 16, 2 / 16, 1 / 16]];
x = x || 0;
y = y || 0;
w = isDef(w) ? w : this.bitmap.width - x;
h = isDef(h) ? h : this.bitmap.height - y;
var source = this.cloneQuiet();
this.scanQuiet(x, y, w, h, function (xx, yx, idx) {
xx = size * Math.floor(xx / size);
yx = size * Math.floor(yx / size);
var value = applyKernel(source, kernel, xx, yx);
this.bitmap.data[idx] = value[0];
this.bitmap.data[idx + 1] = value[1];
this.bitmap.data[idx + 2] = value[2];
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Applies a convolution kernel to the image or a region
* @param {array} kernel the convolution kernel
* @param {number} x (optional) the x position of the region to apply convolution to
* @param {number} y (optional) the y position of the region to apply convolution to
* @param {number} w (optional) the width of the region to apply convolution to
* @param {number} h (optional) the height of the region to apply convolution to
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
convolute: function convolute(kernel, x, y, w, h, cb) {
if (!Array.isArray(kernel)) return throwError.call(this, 'the kernel must be an array', cb);
if (typeof x === 'function') {
cb = x;
x = null;
y = null;
w = null;
h = null;
} else {
if (isDef(x) && typeof x !== 'number') {
return throwError.call(this, 'x must be a number', cb);
}
if (isDef(y) && typeof y !== 'number') {
return throwError.call(this, 'y must be a number', cb);
}
if (isDef(w) && typeof w !== 'number') {
return throwError.call(this, 'w must be a number', cb);
}
if (isDef(h) && typeof h !== 'number') {
return throwError.call(this, 'h must be a number', cb);
}
}
var ksize = (kernel.length - 1) / 2;
x = isDef(x) ? x : ksize;
y = isDef(y) ? y : ksize;
w = isDef(w) ? w : this.bitmap.width - x;
h = isDef(h) ? h : this.bitmap.height - y;
var source = this.cloneQuiet();
this.scanQuiet(x, y, w, h, function (xx, yx, idx) {
var value = applyKernel(source, kernel, xx, yx);
this.bitmap.data[idx] = this.constructor.limit255(value[0]);
this.bitmap.data[idx + 1] = this.constructor.limit255(value[1]);
this.bitmap.data[idx + 2] = this.constructor.limit255(value[2]);
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Apply multiple color modification rules
* @param {array} actions list of color modification rules, in following format: { apply: '<rule-name>', params: [ <rule-parameters> ] }
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
color: colorFn,
colour: colorFn
};
});
//# sourceMappingURL=index.js.map

1
node_modules/@jimp/plugin-color/es/index.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

64
node_modules/@jimp/plugin-color/package.json generated vendored Normal file
View File

@ -0,0 +1,64 @@
{
"_from": "@jimp/plugin-color@^0.6.4",
"_id": "@jimp/plugin-color@0.6.4",
"_inBundle": false,
"_integrity": "sha512-6Nfr2l9KSb6zH2fij8G6fQOw85TTkyRaBlqMvDmsQp/I1IlaDbXzA2C2Eh9jkQYZQDPu61B1MkmlEhJp/TUx6Q==",
"_location": "/@jimp/plugin-color",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "@jimp/plugin-color@^0.6.4",
"name": "@jimp/plugin-color",
"escapedName": "@jimp%2fplugin-color",
"scope": "@jimp",
"rawSpec": "^0.6.4",
"saveSpec": null,
"fetchSpec": "^0.6.4"
},
"_requiredBy": [
"/@jimp/plugins"
],
"_resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.6.4.tgz",
"_shasum": "d5ce139a0e665437ef9d5df7642be66f33735645",
"_spec": "@jimp/plugin-color@^0.6.4",
"_where": "/Users/stefanfejes/Projects/30-seconds-of-python-code/node_modules/@jimp/plugins",
"author": "",
"bundleDependencies": false,
"dependencies": {
"@jimp/utils": "^0.6.4",
"core-js": "^2.5.7",
"tinycolor2": "^1.4.1"
},
"deprecated": false,
"description": "Bitmap manipulation to adjust the color in an image.",
"devDependencies": {
"@jimp/custom": "^0.6.4",
"@jimp/test-utils": "^0.6.4",
"@jimp/types": "^0.6.4"
},
"gitHead": "7c9d3c817cade88d4a20422be10670d3c1528429",
"license": "MIT",
"main": "dist/index.js",
"module": "es/index.js",
"name": "@jimp/plugin-color",
"peerDependencies": {
"@jimp/custom": ">=0.3.5"
},
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "npm run build:node:production && npm run build:module",
"build:debug": "npm run build:node:debug",
"build:module": "cross-env BABEL_ENV=module babel src -d es --source-maps --config-file ../../babel.config.js",
"build:node": "babel src -d dist --source-maps --config-file ../../babel.config.js",
"build:node:debug": "cross-env BABEL_ENV=development npm run build:node",
"build:node:production": "cross-env BABEL_ENV=production npm run build:node",
"build:watch": "npm run build:node:debug -- -- --watch --verbose",
"test": "cross-env BABEL_ENV=test mocha --require @babel/register",
"test:coverage": "nyc npm run test",
"test:watch": "npm run test -- --reporter min --watch"
},
"version": "0.6.4"
}

616
node_modules/@jimp/plugin-color/src/index.js generated vendored Normal file
View File

@ -0,0 +1,616 @@
import tinyColor from 'tinycolor2';
import { throwError, isNodePattern } from '@jimp/utils';
function applyKernel(im, kernel, x, y) {
const value = [0, 0, 0];
const size = (kernel.length - 1) / 2;
for (let kx = 0; kx < kernel.length; kx += 1) {
for (let ky = 0; ky < kernel[kx].length; ky += 1) {
const idx = im.getPixelIndex(x + kx - size, y + ky - size);
value[0] += im.bitmap.data[idx] * kernel[kx][ky];
value[1] += im.bitmap.data[idx + 1] * kernel[kx][ky];
value[2] += im.bitmap.data[idx + 2] * kernel[kx][ky];
}
}
return value;
}
const isDef = v => typeof v !== 'undefined' && v !== null;
function greyscale(cb) {
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function(
x,
y,
idx
) {
const grey = parseInt(
0.2126 * this.bitmap.data[idx] +
0.7152 * this.bitmap.data[idx + 1] +
0.0722 * this.bitmap.data[idx + 2],
10
);
this.bitmap.data[idx] = grey;
this.bitmap.data[idx + 1] = grey;
this.bitmap.data[idx + 2] = grey;
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
}
function mix(clr, clr2, p = 50) {
return {
r: (clr2.r - clr.r) * (p / 100) + clr.r,
g: (clr2.g - clr.g) * (p / 100) + clr.g,
b: (clr2.b - clr.b) * (p / 100) + clr.b
};
}
function colorFn(actions, cb) {
if (!actions || !Array.isArray(actions)) {
return throwError.call(this, 'actions must be an array', cb);
}
actions = actions.map(action => {
if (action.apply === 'xor' || action.apply === 'mix') {
action.params[0] = tinyColor(action.params[0]).toRgb();
}
return action;
});
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, (x, y, idx) => {
let clr = {
r: this.bitmap.data[idx],
g: this.bitmap.data[idx + 1],
b: this.bitmap.data[idx + 2]
};
const colorModifier = (i, amount) =>
this.constructor.limit255(clr[i] + amount);
actions.forEach(action => {
if (action.apply === 'mix') {
clr = mix(clr, action.params[0], action.params[1]);
} else if (action.apply === 'tint') {
clr = mix(clr, { r: 255, g: 255, b: 255 }, action.params[0]);
} else if (action.apply === 'shade') {
clr = mix(clr, { r: 0, g: 0, b: 0 }, action.params[0]);
} else if (action.apply === 'xor') {
clr = {
r: clr.r ^ action.params[0].r,
g: clr.g ^ action.params[0].g,
b: clr.b ^ action.params[0].b
};
} else if (action.apply === 'red') {
clr.r = colorModifier('r', action.params[0]);
} else if (action.apply === 'green') {
clr.g = colorModifier('g', action.params[0]);
} else if (action.apply === 'blue') {
clr.b = colorModifier('b', action.params[0]);
} else {
if (action.apply === 'hue') {
action.apply = 'spin';
}
clr = tinyColor(clr);
if (!clr[action.apply]) {
return throwError.call(
this,
'action ' + action.apply + ' not supported',
cb
);
}
clr = clr[action.apply](...action.params).toRgb();
}
});
this.bitmap.data[idx] = clr.r;
this.bitmap.data[idx + 1] = clr.g;
this.bitmap.data[idx + 2] = clr.b;
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
}
export default () => ({
/**
* Adjusts the brightness of the image
* @param {number} val the amount to adjust the brightness, a number between -1 and +1
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
brightness(val, cb) {
if (typeof val !== 'number') {
return throwError.call(this, 'val must be numbers', cb);
}
if (val < -1 || val > +1) {
return throwError.call(
this,
'val must be a number between -1 and +1',
cb
);
}
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function(
x,
y,
idx
) {
if (val < 0.0) {
this.bitmap.data[idx] = this.bitmap.data[idx] * (1 + val);
this.bitmap.data[idx + 1] = this.bitmap.data[idx + 1] * (1 + val);
this.bitmap.data[idx + 2] = this.bitmap.data[idx + 2] * (1 + val);
} else {
this.bitmap.data[idx] =
this.bitmap.data[idx] + (255 - this.bitmap.data[idx]) * val;
this.bitmap.data[idx + 1] =
this.bitmap.data[idx + 1] + (255 - this.bitmap.data[idx + 1]) * val;
this.bitmap.data[idx + 2] =
this.bitmap.data[idx + 2] + (255 - this.bitmap.data[idx + 2]) * val;
}
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Adjusts the contrast of the image
* @param {number} val the amount to adjust the contrast, a number between -1 and +1
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
contrast(val, cb) {
if (typeof val !== 'number') {
return throwError.call(this, 'val must be numbers', cb);
}
if (val < -1 || val > +1) {
return throwError.call(
this,
'val must be a number between -1 and +1',
cb
);
}
const factor = (val + 1) / (1 - val);
function adjust(value) {
value = Math.floor(factor * (value - 127) + 127);
return value < 0 ? 0 : value > 255 ? 255 : value;
}
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function(
x,
y,
idx
) {
this.bitmap.data[idx] = adjust(this.bitmap.data[idx]);
this.bitmap.data[idx + 1] = adjust(this.bitmap.data[idx + 1]);
this.bitmap.data[idx + 2] = adjust(this.bitmap.data[idx + 2]);
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Apply a posterize effect
* @param {number} n the amount to adjust the contrast, minimum threshold is two
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
posterize(n, cb) {
if (typeof n !== 'number') {
return throwError.call(this, 'n must be numbers', cb);
}
if (n < 2) {
n = 2;
} // minimum of 2 levels
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function(
x,
y,
idx
) {
this.bitmap.data[idx] =
(Math.floor((this.bitmap.data[idx] / 255) * (n - 1)) / (n - 1)) * 255;
this.bitmap.data[idx + 1] =
(Math.floor((this.bitmap.data[idx + 1] / 255) * (n - 1)) / (n - 1)) *
255;
this.bitmap.data[idx + 2] =
(Math.floor((this.bitmap.data[idx + 2] / 255) * (n - 1)) / (n - 1)) *
255;
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Removes colour from the image using ITU Rec 709 luminance values
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
greyscale,
// Alias of greyscale for our American friends
grayscale: greyscale,
/**
* Multiplies the opacity of each pixel by a factor between 0 and 1
* @param {number} f A number, the factor by which to multiply the opacity of each pixel
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
opacity(f, cb) {
if (typeof f !== 'number')
return throwError.call(this, 'f must be a number', cb);
if (f < 0 || f > 1)
return throwError.call(this, 'f must be a number from 0 to 1', cb);
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function(
x,
y,
idx
) {
const v = this.bitmap.data[idx + 3] * f;
this.bitmap.data[idx + 3] = v;
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Applies a sepia tone to the image
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
sepia(cb) {
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function(
x,
y,
idx
) {
let red = this.bitmap.data[idx];
let green = this.bitmap.data[idx + 1];
let blue = this.bitmap.data[idx + 2];
red = red * 0.393 + green * 0.769 + blue * 0.189;
green = red * 0.349 + green * 0.686 + blue * 0.168;
blue = red * 0.272 + green * 0.534 + blue * 0.131;
this.bitmap.data[idx] = red < 255 ? red : 255;
this.bitmap.data[idx + 1] = green < 255 ? green : 255;
this.bitmap.data[idx + 2] = blue < 255 ? blue : 255;
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Fades each pixel by a factor between 0 and 1
* @param {number} f A number from 0 to 1. 0 will haven no effect. 1 will turn the image completely transparent.
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
fade(f, cb) {
if (typeof f !== 'number') {
return throwError.call(this, 'f must be a number', cb);
}
if (f < 0 || f > 1) {
return throwError.call(this, 'f must be a number from 0 to 1', cb);
}
// this method is an alternative to opacity (which may be deprecated)
this.opacity(1 - f);
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Adds each element of the image to its local neighbors, weighted by the kernel
* @param {array} kernel a matrix to weight the neighbors sum
* @param {string} edgeHandling (optional) define how to sum pixels from outside the border
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
convolution(kernel, edgeHandling, cb) {
if (typeof edgeHandling === 'function' && typeof cb === 'undefined') {
cb = edgeHandling;
edgeHandling = null;
}
if (!edgeHandling) {
edgeHandling = this.constructor.EDGE_EXTEND;
}
const newData = Buffer.from(this.bitmap.data);
const kRows = kernel.length;
const kCols = kernel[0].length;
const rowEnd = Math.floor(kRows / 2);
const colEnd = Math.floor(kCols / 2);
const rowIni = -rowEnd;
const colIni = -colEnd;
let weight;
let rSum;
let gSum;
let bSum;
let ri;
let gi;
let bi;
let xi;
let yi;
let idxi;
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function(
x,
y,
idx
) {
bSum = 0;
gSum = 0;
rSum = 0;
for (let row = rowIni; row <= rowEnd; row++) {
for (let col = colIni; col <= colEnd; col++) {
xi = x + col;
yi = y + row;
weight = kernel[row + rowEnd][col + colEnd];
idxi = this.getPixelIndex(xi, yi, edgeHandling);
if (idxi === -1) {
bi = 0;
gi = 0;
ri = 0;
} else {
ri = this.bitmap.data[idxi + 0];
gi = this.bitmap.data[idxi + 1];
bi = this.bitmap.data[idxi + 2];
}
rSum += weight * ri;
gSum += weight * gi;
bSum += weight * bi;
}
}
if (rSum < 0) {
rSum = 0;
}
if (gSum < 0) {
gSum = 0;
}
if (bSum < 0) {
bSum = 0;
}
if (rSum > 255) {
rSum = 255;
}
if (gSum > 255) {
gSum = 255;
}
if (bSum > 255) {
bSum = 255;
}
newData[idx + 0] = rSum;
newData[idx + 1] = gSum;
newData[idx + 2] = bSum;
});
this.bitmap.data = newData;
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Set the alpha channel on every pixel to fully opaque
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
opaque(cb) {
this.scanQuiet(0, 0, this.bitmap.width, this.bitmap.height, function(
x,
y,
idx
) {
this.bitmap.data[idx + 3] = 255;
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Pixelates the image or a region
* @param {number} size the size of the pixels
* @param {number} x (optional) the x position of the region to pixelate
* @param {number} y (optional) the y position of the region to pixelate
* @param {number} w (optional) the width of the region to pixelate
* @param {number} h (optional) the height of the region to pixelate
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
pixelate(size, x, y, w, h, cb) {
if (typeof x === 'function') {
cb = x;
h = null;
w = null;
y = null;
x = null;
} else {
if (typeof size !== 'number') {
return throwError.call(this, 'size must be a number', cb);
}
if (isDef(x) && typeof x !== 'number') {
return throwError.call(this, 'x must be a number', cb);
}
if (isDef(y) && typeof y !== 'number') {
return throwError.call(this, 'y must be a number', cb);
}
if (isDef(w) && typeof w !== 'number') {
return throwError.call(this, 'w must be a number', cb);
}
if (isDef(h) && typeof h !== 'number') {
return throwError.call(this, 'h must be a number', cb);
}
}
const kernel = [
[1 / 16, 2 / 16, 1 / 16],
[2 / 16, 4 / 16, 2 / 16],
[1 / 16, 2 / 16, 1 / 16]
];
x = x || 0;
y = y || 0;
w = isDef(w) ? w : this.bitmap.width - x;
h = isDef(h) ? h : this.bitmap.height - y;
const source = this.cloneQuiet();
this.scanQuiet(x, y, w, h, function(xx, yx, idx) {
xx = size * Math.floor(xx / size);
yx = size * Math.floor(yx / size);
const value = applyKernel(source, kernel, xx, yx);
this.bitmap.data[idx] = value[0];
this.bitmap.data[idx + 1] = value[1];
this.bitmap.data[idx + 2] = value[2];
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Applies a convolution kernel to the image or a region
* @param {array} kernel the convolution kernel
* @param {number} x (optional) the x position of the region to apply convolution to
* @param {number} y (optional) the y position of the region to apply convolution to
* @param {number} w (optional) the width of the region to apply convolution to
* @param {number} h (optional) the height of the region to apply convolution to
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
convolute(kernel, x, y, w, h, cb) {
if (!Array.isArray(kernel))
return throwError.call(this, 'the kernel must be an array', cb);
if (typeof x === 'function') {
cb = x;
x = null;
y = null;
w = null;
h = null;
} else {
if (isDef(x) && typeof x !== 'number') {
return throwError.call(this, 'x must be a number', cb);
}
if (isDef(y) && typeof y !== 'number') {
return throwError.call(this, 'y must be a number', cb);
}
if (isDef(w) && typeof w !== 'number') {
return throwError.call(this, 'w must be a number', cb);
}
if (isDef(h) && typeof h !== 'number') {
return throwError.call(this, 'h must be a number', cb);
}
}
const ksize = (kernel.length - 1) / 2;
x = isDef(x) ? x : ksize;
y = isDef(y) ? y : ksize;
w = isDef(w) ? w : this.bitmap.width - x;
h = isDef(h) ? h : this.bitmap.height - y;
const source = this.cloneQuiet();
this.scanQuiet(x, y, w, h, function(xx, yx, idx) {
const value = applyKernel(source, kernel, xx, yx);
this.bitmap.data[idx] = this.constructor.limit255(value[0]);
this.bitmap.data[idx + 1] = this.constructor.limit255(value[1]);
this.bitmap.data[idx + 2] = this.constructor.limit255(value[2]);
});
if (isNodePattern(cb)) {
cb.call(this, null, this);
}
return this;
},
/**
* Apply multiple color modification rules
* @param {array} actions list of color modification rules, in following format: { apply: '<rule-name>', params: [ <rule-parameters> ] }
* @param {function(Error, Jimp)} cb (optional) a callback for when complete
* @returns {Jimp }this for chaining of methods
*/
color: colorFn,
colour: colorFn
});

49
node_modules/@jimp/plugin-color/test/color.test.js generated vendored Normal file
View File

@ -0,0 +1,49 @@
import { Jimp, donutJGD } from '@jimp/test-utils';
import configure from '@jimp/custom';
import color from '../src';
const jimp = configure({ plugins: [color] }, Jimp);
describe('canvas color transformation', () => {
const redDonutJGD = donutJGD(0x00000000, 0xff000088, 0xff0000ff);
it('can apply more than one color transformation', async () => {
const image = await jimp.read(redDonutJGD);
const newJGD = image
.color([
{ apply: 'hue', params: [-180] },
{ apply: 'lighten', params: [25] }
])
.getJGDSync();
newJGD.should.be.sameJGD(donutJGD(0x40404000, 0x80ffff88, 0x80ffffff));
});
it('lighten', async () => {
const image = await jimp.read(redDonutJGD);
image
.color([{ apply: 'lighten', params: [25] }])
.getJGDSync()
.should.be.sameJGD(donutJGD(0x40404000, 0xff808088, 0xff8080ff));
});
it('brighten', async () => {
const image = await jimp.read(redDonutJGD);
image
.color([{ apply: 'brighten', params: [25] }])
.getJGDSync()
.should.be.sameJGD(donutJGD(0x40404000, 0xff404088, 0xff4040ff));
});
it('spin hue', async () => {
const image = await jimp.read(redDonutJGD);
image
.color([{ apply: 'hue', params: [150] }])
.getJGDSync()
.should.be.sameJGD(donutJGD(0x00000000, 0x00ff8088, 0x00ff80ff));
});
});

View File

@ -0,0 +1,184 @@
import { Jimp, mkJGD, getTestDir } from '@jimp/test-utils';
import configure from '@jimp/custom';
import types from '@jimp/types';
import color from '../src';
const jimp = configure({ types: [types], plugins: [color] }, Jimp);
describe('Convolution', function() {
this.timeout(15000);
const imgs = [
jimp.read(
mkJGD(
'22222222',
'22222222',
'22888822',
'22888822',
'22888822',
'22888822',
'22222222',
'22222222'
)
),
jimp.read(
mkJGD(
'88222222',
'88222222',
'22222222',
'22222222',
'22222222',
'22222222',
'22222222',
'22222222'
)
)
];
let imgMid;
let imgTopLeft; // stores the Jimp instances of the JGD images above.
before(done => {
Promise.all(imgs)
.then(imgs => {
imgMid = imgs[0];
imgTopLeft = imgs[1];
done();
})
.catch(done);
});
const sharpM = [[-1, -1, 0], [-1, 1, 1], [0, 1, 1]];
it('3x3 sharp matrix on EDGE_EXTEND', done => {
imgMid
.clone()
.convolution(sharpM)
.getJGDSync()
.should.be.sameJGD(
mkJGD(
'22222222',
'28EEE822',
'2EFFF802',
'2EF88002',
'2EF88002',
'28800002',
'22000002',
'22222222'
),
'Mid light block'
);
imgTopLeft
.clone()
.convolution(sharpM)
.getJGDSync()
.should.be.sameJGD(
mkJGD(
'80022222',
'00022222',
'00022222',
'22222222',
'22222222',
'22222222',
'22222222',
'22222222'
),
'Top left light block'
);
done();
});
it('3x3 sharp matrix on EDGE_WRAP', done => {
imgMid
.clone()
.convolution(sharpM, jimp.EDGE_WRAP)
.getJGDSync()
.should.be.sameJGD(
mkJGD(
'66666666',
'28EEE822',
'2EFFF802',
'2EF88002',
'2EF88002',
'28800002',
'22000002',
'22222222'
),
'Mid light block'
);
imgTopLeft
.clone()
.convolution(sharpM, jimp.EDGE_WRAP)
.getJGDSync()
.should.be.sameJGD(
mkJGD(
'FC06666F',
'80022228',
'00022222',
'22222222',
'22222222',
'22222222',
'22222222',
'E8222228'
),
'Top left light block'
);
done();
});
it('3x3 sharp matrix on EDGE_CROP', done => {
imgMid
.clone()
.convolution(sharpM, jimp.EDGE_CROP)
.getJGDSync()
.should.be.sameJGD(
mkJGD(
'86666662',
'68EEE820',
'6EFFF800',
'6EF88000',
'6EF88000',
'68800000',
'62000000',
'20000000'
),
'Mid light block'
);
imgTopLeft
.clone()
.convolution(sharpM, jimp.EDGE_CROP)
.getJGDSync()
.should.be.sameJGD(
mkJGD(
'FC066662',
'C0022220',
'00022220',
'62222220',
'62222220',
'62222220',
'62222220',
'20000000'
),
'Top left light block'
);
done();
});
it('new pixel value is greater than 255', async () => {
const expectedImg = await jimp.read(
getTestDir(__dirname) + '/images/qr-convoluted.png'
);
const image = await jimp.read(getTestDir(__dirname) + '/images/qr.jpg');
image
.convolution([
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 1, 0, 1, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0]
])
.bitmap.data.should.be.deepEqual(expectedImg.bitmap.data);
});
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

BIN
node_modules/@jimp/plugin-color/test/images/qr.jpg generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB