Brunobkr/llama.cpp_AlgMor24_github
ΩFFFΣLLIa • llama.cpp • AlgMor24 ██████╗ ███████╗███████╗███████╗██╗ ██╗ ██╗ █████╗ ██╔═══██╗██╔════╝██╔════╝██╔════╝██║ ██║ ██║██╔══██╗ ██║ ██║█████╗ █████╗ █████╗ ██║ ██║ ██║███████║ ██║ ██║██╔══╝ ██╔══╝ ██╔══╝ ██║ ██║ ██║██╔══██║ ╚██████╔╝██║ ██║ ███████╗███████╗███████╗██║██║ ██║ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚═╝╚═╝ ╚═╝ High-Performance LLM / VLM Inference & Autonomous Agentic Ecosystem… See the full description on the dataset page: https://huggingface.co/datasets/Brunobkr/llama.cpp_AlgMor24_github.
03.1k
1/*!2 Copyright 2013 Lovell Fuller and others.3 SPDX-License-Identifier: Apache-2.04*/5 6const is = require('./is.cjs');7 8/**9 * How accurate an operation should be.10 * @member11 * @private12 */13const vipsPrecision = {14 integer: 'integer',15 float: 'float',16 approximate: 'approximate'17};18 19/**20 * Rotate the output image.21 *22 * The provided angle is converted to a valid positive degree rotation.23 * For example, `-450` will produce a 270 degree rotation.24 *25 * When rotating by an angle other than a multiple of 90,26 * the background colour can be provided with the `background` option.27 *28 * For backwards compatibility, if no angle is provided, `.autoOrient()` will be called.29 *30 * Only one rotation can occur per pipeline (aside from an initial call without31 * arguments to orient via EXIF data). Previous calls to `rotate` in the same32 * pipeline will be ignored.33 *34 * Multi-page images can only be rotated by 180 degrees.35 *36 * Method order is important when rotating, resizing and/or extracting regions,37 * for example `.rotate(x).extract(y)` will produce a different result to `.extract(y).rotate(x)`.38 *39 * @example40 * const rotateThenResize = await sharp(input)41 * .rotate(90)42 * .resize({ width: 16, height: 8, fit: 'fill' })43 * .toBuffer();44 * const resizeThenRotate = await sharp(input)45 * .resize({ width: 16, height: 8, fit: 'fill' })46 * .rotate(90)47 * .toBuffer();48 *49 * @param {number} [angle=auto] angle of rotation.50 * @param {Object} [options] - if present, is an Object with optional attributes.51 * @param {string|Object} [options.background="#000000"] parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.52 * @returns {Sharp}53 * @throws {Error} Invalid parameters54 */55function rotate (angle, options) {56 if (!is.defined(angle)) {57 return this.autoOrient();58 }59 if (this.options.angle || this.options.rotationAngle) {60 this.options.debuglog('ignoring previous rotate options');61 this.options.angle = 0;62 this.options.rotationAngle = 0;63 }64 if (is.integer(angle) && !(angle % 90)) {65 this.options.angle = angle;66 } else if (is.number(angle)) {67 this.options.rotationAngle = angle;68 if (is.object(options) && options.background) {69 this._setBackgroundColourOption('rotationBackground', options.background);70 }71 } else {72 throw is.invalidParameterError('angle', 'numeric', angle);73 }74 return this;75}76 77/**78 * Auto-orient based on the EXIF `Orientation` tag, then remove the tag.79 * Mirroring is supported and may infer the use of a flip operation.80 *81 * Previous or subsequent use of `rotate(angle)` and either `flip()` or `flop()`82 * will logically occur after auto-orientation, regardless of call order.83 *84 * @example85 * const output = await sharp(input).autoOrient().toBuffer();86 *87 * @example88 * const pipeline = sharp()89 * .autoOrient()90 * .resize(null, 200)91 * .toBuffer(function (err, outputBuffer, info) {92 * // outputBuffer contains 200px high JPEG image data,93 * // auto-oriented using EXIF Orientation tag94 * // info.width and info.height contain the dimensions of the resized image95 * });96 * readableStream.pipe(pipeline);97 *98 * @returns {Sharp}99 */100function autoOrient () {101 this.options.input.autoOrient = true;102 return this;103}104 105/**106 * Mirror the image vertically (up-down) about the x-axis.107 * This always occurs before rotation, if any.108 *109 * This operation does not work correctly with multi-page images.110 *111 * @example112 * const output = await sharp(input).flip().toBuffer();113 *114 * @param {Boolean} [flip=true]115 * @returns {Sharp}116 */117function flip (flip) {118 this.options.flip = is.bool(flip) ? flip : true;119 return this;120}121 122/**123 * Mirror the image horizontally (left-right) about the y-axis.124 * This always occurs before rotation, if any.125 *126 * @example127 * const output = await sharp(input).flop().toBuffer();128 *129 * @param {Boolean} [flop=true]130 * @returns {Sharp}131 */132function flop (flop) {133 this.options.flop = is.bool(flop) ? flop : true;134 return this;135}136 137/**138 * Perform an affine transform on an image. This operation will always occur after resizing, extraction and rotation, if any.139 *140 * You must provide an array of length 4 or a 2x2 affine transformation matrix.141 * By default, new pixels are filled with a black background. You can provide a background colour with the `background` option.142 * A particular interpolator may also be specified. Set the `interpolator` option to an attribute of the `sharp.interpolators` Object e.g. `sharp.interpolators.nohalo`.143 *144 * In the case of a 2x2 matrix, the transform is:145 * - X = `matrix[0, 0]` \* (x + `idx`) + `matrix[0, 1]` \* (y + `idy`) + `odx`146 * - Y = `matrix[1, 0]` \* (x + `idx`) + `matrix[1, 1]` \* (y + `idy`) + `ody`147 *148 * where:149 * - x and y are the coordinates in input image.150 * - X and Y are the coordinates in output image.151 * - (0,0) is the upper left corner.152 *153 * @since 0.27.0154 *155 * @example156 * const pipeline = sharp()157 * .affine([[1, 0.3], [0.1, 0.7]], {158 * background: 'white',159 * interpolator: sharp.interpolators.nohalo160 * })161 * .toBuffer((err, outputBuffer, info) => {162 * // outputBuffer contains the transformed image163 * // info.width and info.height contain the new dimensions164 * });165 *166 * inputStream167 * .pipe(pipeline);168 *169 * @param {Array<Array<number>>|Array<number>} matrix - affine transformation matrix170 * @param {Object} [options] - if present, is an Object with optional attributes.171 * @param {String|Object} [options.background="#000000"] - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.172 * @param {Number} [options.idx=0] - input horizontal offset173 * @param {Number} [options.idy=0] - input vertical offset174 * @param {Number} [options.odx=0] - output horizontal offset175 * @param {Number} [options.ody=0] - output vertical offset176 * @param {String} [options.interpolator=sharp.interpolators.bicubic] - interpolator177 * @returns {Sharp}178 * @throws {Error} Invalid parameters179 */180function affine (matrix, options) {181 const isValidShape = Array.isArray(matrix) && (182 // 1x4 array of numbers183 (matrix.length === 4 && matrix.every(is.number)) ||184 // 2x2 array of arrays of numbers185 (matrix.length === 2 && matrix.every((row) => Array.isArray(row) && row.length === 2))186 );187 const flatMatrix = isValidShape ? matrix.flat() : [];188 if (flatMatrix.length === 4 && flatMatrix.every(is.number)) {189 this.options.affineMatrix = flatMatrix;190 } else {191 throw is.invalidParameterError('matrix', '1x4 or 2x2 array', matrix);192 }193 194 if (is.defined(options)) {195 if (is.object(options)) {196 this._setBackgroundColourOption('affineBackground', options.background);197 if (is.defined(options.idx)) {198 if (is.number(options.idx)) {199 this.options.affineIdx = options.idx;200 } else {201 throw is.invalidParameterError('options.idx', 'number', options.idx);202 }203 }204 if (is.defined(options.idy)) {205 if (is.number(options.idy)) {206 this.options.affineIdy = options.idy;207 } else {208 throw is.invalidParameterError('options.idy', 'number', options.idy);209 }210 }211 if (is.defined(options.odx)) {212 if (is.number(options.odx)) {213 this.options.affineOdx = options.odx;214 } else {215 throw is.invalidParameterError('options.odx', 'number', options.odx);216 }217 }218 if (is.defined(options.ody)) {219 if (is.number(options.ody)) {220 this.options.affineOdy = options.ody;221 } else {222 throw is.invalidParameterError('options.ody', 'number', options.ody);223 }224 }225 if (is.defined(options.interpolator)) {226 if (is.inArray(options.interpolator, Object.values(this.constructor.interpolators))) {227 this.options.affineInterpolator = options.interpolator;228 } else {229 throw is.invalidParameterError('options.interpolator', 'valid interpolator name', options.interpolator);230 }231 }232 } else {233 throw is.invalidParameterError('options', 'object', options);234 }235 }236 237 return this;238}239 240/**241 * Sharpen the image.242 *243 * When used without parameters, performs a fast, mild sharpen of the output image.244 *245 * When a `sigma` is provided, performs a slower, more accurate sharpen of the L channel in the LAB colour space.246 * Fine-grained control over the level of sharpening in "flat" (m1) and "jagged" (m2) areas is available.247 *248 * See {@link https://www.libvips.org/API/current/method.Image.sharpen.html libvips sharpen} operation.249 *250 * @example251 * const data = await sharp(input).sharpen().toBuffer();252 *253 * @example254 * const data = await sharp(input).sharpen({ sigma: 2 }).toBuffer();255 *256 * @example257 * const data = await sharp(input)258 * .sharpen({259 * sigma: 2,260 * m1: 0,261 * m2: 3,262 * x1: 3,263 * y2: 15,264 * y3: 15,265 * })266 * .toBuffer();267 *268 * @param {Object} [options] - if present, is an Object with attributes269 * @param {number} [options.sigma] - the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`, between 0.000001 and 10270 * @param {number} [options.m1=1.0] - the level of sharpening to apply to "flat" areas, between 0 and 1000000271 * @param {number} [options.m2=2.0] - the level of sharpening to apply to "jagged" areas, between 0 and 1000000272 * @param {number} [options.x1=2.0] - threshold between "flat" and "jagged", between 0 and 1000000273 * @param {number} [options.y2=10.0] - maximum amount of brightening, between 0 and 1000000274 * @param {number} [options.y3=20.0] - maximum amount of darkening, between 0 and 1000000275 * @returns {Sharp}276 * @throws {Error} Invalid parameters277 */278function sharpen (options) {279 if (is.plainObject(options)) {280 if (is.number(options.sigma) && is.inRange(options.sigma, 0.000001, 10)) {281 this.options.sharpenSigma = options.sigma;282 } else {283 throw is.invalidParameterError('options.sigma', 'number between 0.000001 and 10', options.sigma);284 }285 if (is.defined(options.m1)) {286 if (is.number(options.m1) && is.inRange(options.m1, 0, 1000000)) {287 this.options.sharpenM1 = options.m1;288 } else {289 throw is.invalidParameterError('options.m1', 'number between 0 and 1000000', options.m1);290 }291 }292 if (is.defined(options.m2)) {293 if (is.number(options.m2) && is.inRange(options.m2, 0, 1000000)) {294 this.options.sharpenM2 = options.m2;295 } else {296 throw is.invalidParameterError('options.m2', 'number between 0 and 1000000', options.m2);297 }298 }299 if (is.defined(options.x1)) {300 if (is.number(options.x1) && is.inRange(options.x1, 0, 1000000)) {301 this.options.sharpenX1 = options.x1;302 } else {303 throw is.invalidParameterError('options.x1', 'number between 0 and 1000000', options.x1);304 }305 }306 if (is.defined(options.y2)) {307 if (is.number(options.y2) && is.inRange(options.y2, 0, 1000000)) {308 this.options.sharpenY2 = options.y2;309 } else {310 throw is.invalidParameterError('options.y2', 'number between 0 and 1000000', options.y2);311 }312 }313 if (is.defined(options.y3)) {314 if (is.number(options.y3) && is.inRange(options.y3, 0, 1000000)) {315 this.options.sharpenY3 = options.y3;316 } else {317 throw is.invalidParameterError('options.y3', 'number between 0 and 1000000', options.y3);318 }319 }320 } else {321 this.options.sharpenSigma = -1;322 }323 return this;324}325 326/**327 * Apply median filter.328 * When used without parameters the default window is 3x3.329 *330 * @example331 * const output = await sharp(input).median().toBuffer();332 *333 * @example334 * const output = await sharp(input).median(5).toBuffer();335 *336 * @param {number} [size=3] square mask size: size x size337 * @returns {Sharp}338 * @throws {Error} Invalid parameters339 */340function median (size) {341 if (!is.defined(size)) {342 // No arguments: default to 3x3343 this.options.medianSize = 3;344 } else if (is.integer(size) && is.inRange(size, 1, 1000)) {345 // Numeric argument: specific sigma346 this.options.medianSize = size;347 } else {348 throw is.invalidParameterError('size', 'integer between 1 and 1000', size);349 }350 return this;351}352 353/**354 * Blur the image.355 *356 * When used without parameters, performs a fast 3x3 box blur (equivalent to a box linear filter).357 *358 * When a `sigma` is provided, performs a slower, more accurate Gaussian blur.359 *360 * @example361 * const boxBlurred = await sharp(input)362 * .blur()363 * .toBuffer();364 *365 * @example366 * const gaussianBlurred = await sharp(input)367 * .blur(5)368 * .toBuffer();369 *370 * @param {Object|number|Boolean} [options]371 * @param {number} [options.sigma] a value between 0.3 and 1000 representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.372 * @param {string} [options.precision='integer'] How accurate the operation should be, one of: integer, float, approximate.373 * @param {number} [options.minAmplitude=0.2] A value between 0.001 and 1. A smaller value will generate a larger, more accurate mask.374 * @returns {Sharp}375 * @throws {Error} Invalid parameters376 */377function blur (options) {378 let sigma;379 if (is.number(options)) {380 sigma = options;381 } else if (is.plainObject(options)) {382 if (!is.number(options.sigma)) {383 throw is.invalidParameterError('options.sigma', 'number between 0.3 and 1000', sigma);384 }385 sigma = options.sigma;386 if ('precision' in options) {387 if (is.string(vipsPrecision[options.precision])) {388 this.options.precision = vipsPrecision[options.precision];389 } else {390 throw is.invalidParameterError('precision', 'one of: integer, float, approximate', options.precision);391 }392 }393 if ('minAmplitude' in options) {394 if (is.number(options.minAmplitude) && is.inRange(options.minAmplitude, 0.001, 1)) {395 this.options.minAmpl = options.minAmplitude;396 } else {397 throw is.invalidParameterError('minAmplitude', 'number between 0.001 and 1', options.minAmplitude);398 }399 }400 }401 402 if (!is.defined(options)) {403 // No arguments: default to mild blur404 this.options.blurSigma = -1;405 } else if (is.bool(options)) {406 // Boolean argument: apply mild blur?407 this.options.blurSigma = options ? -1 : 0;408 } else if (is.number(sigma) && is.inRange(sigma, 0.3, 1000)) {409 // Numeric argument: specific sigma410 this.options.blurSigma = sigma;411 } else {412 throw is.invalidParameterError('sigma', 'number between 0.3 and 1000', sigma);413 }414 415 return this;416}417 418/**419 * Expand foreground objects using the dilate morphological operator.420 *421 * @example422 * const output = await sharp(input)423 * .dilate()424 * .toBuffer();425 *426 * @param {Number} [width=1] dilation width in pixels.427 * @returns {Sharp}428 * @throws {Error} Invalid parameters429 */430function dilate (width) {431 if (!is.defined(width)) {432 this.options.dilateWidth = 1;433 } else if (is.integer(width) && is.inRange(width, 1, 65536)) {434 this.options.dilateWidth = width;435 } else {436 throw is.invalidParameterError('width', 'integer between 1 and 65536', width);437 }438 return this;439}440 441/**442 * Shrink foreground objects using the erode morphological operator.443 *444 * @example445 * const output = await sharp(input)446 * .erode()447 * .toBuffer();448 *449 * @param {Number} [width=1] erosion width in pixels.450 * @returns {Sharp}451 * @throws {Error} Invalid parameters452 */453function erode (width) {454 if (!is.defined(width)) {455 this.options.erodeWidth = 1;456 } else if (is.integer(width) && is.inRange(width, 1, 65536)) {457 this.options.erodeWidth = width;458 } else {459 throw is.invalidParameterError('width', 'integer between 1 and 65536', width);460 }461 return this;462}463 464/**465 * Merge alpha transparency channel, if any, with a background, then remove the alpha channel.466 *467 * See also {@link /api-channel#removealpha removeAlpha}.468 *469 * @example470 * await sharp(rgbaInput)471 * .flatten({ background: '#F0A703' })472 * .toBuffer();473 *474 * @param {Object} [options]475 * @param {string|Object} [options.background={r: 0, g: 0, b: 0}] - background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to black.476 * @returns {Sharp}477 */478function flatten (options) {479 this.options.flatten = is.bool(options) ? options : true;480 if (is.object(options)) {481 this._setBackgroundColourOption('flattenBackground', options.background);482 }483 return this;484}485 486/**487 * Ensure the image has an alpha channel488 * with all white pixel values made fully transparent.489 *490 * Existing alpha channel values for non-white pixels remain unchanged.491 *492 * @since 0.32.1493 *494 * @example495 * await sharp(rgbInput)496 * .unflatten()497 * .toBuffer();498 *499 * @example500 * await sharp(rgbInput)501 * .threshold(128, { grayscale: false }) // converter bright pixels to white502 * .unflatten()503 * .toBuffer();504 */505function unflatten () {506 this.options.unflatten = true;507 return this;508}509 510/**511 * Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma`512 * then increasing the encoding (brighten) post-resize at a factor of `gamma`.513 * This can improve the perceived brightness of a resized image in non-linear colour spaces.514 * JPEG and WebP input images will not take advantage of the shrink-on-load performance optimisation515 * when applying a gamma correction.516 *517 * Supply a second argument to use a different output gamma value, otherwise the first value is used in both cases.518 *519 * @param {number} [gamma=2.2] value between 1.0 and 3.0.520 * @param {number} [gammaOut] value between 1.0 and 3.0. (optional, defaults to same as `gamma`)521 * @returns {Sharp}522 * @throws {Error} Invalid parameters523 */524function gamma (gamma, gammaOut) {525 if (!is.defined(gamma)) {526 // Default gamma correction of 2.2 (sRGB)527 this.options.gamma = 2.2;528 } else if (is.number(gamma) && is.inRange(gamma, 1, 3)) {529 this.options.gamma = gamma;530 } else {531 throw is.invalidParameterError('gamma', 'number between 1.0 and 3.0', gamma);532 }533 if (!is.defined(gammaOut)) {534 // Default gamma correction for output is same as input535 this.options.gammaOut = this.options.gamma;536 } else if (is.number(gammaOut) && is.inRange(gammaOut, 1, 3)) {537 this.options.gammaOut = gammaOut;538 } else {539 throw is.invalidParameterError('gammaOut', 'number between 1.0 and 3.0', gammaOut);540 }541 return this;542}543 544/**545 * Produce the "negative" of the image.546 *547 * @example548 * const output = await sharp(input)549 * .negate()550 * .toBuffer();551 *552 * @example553 * const output = await sharp(input)554 * .negate({ alpha: false })555 * .toBuffer();556 *557 * @param {Object} [options]558 * @param {Boolean} [options.alpha=true] Whether or not to negate any alpha channel559 * @returns {Sharp}560 */561function negate (options) {562 this.options.negate = is.bool(options) ? options : true;563 if (is.plainObject(options) && 'alpha' in options) {564 if (!is.bool(options.alpha)) {565 throw is.invalidParameterError('alpha', 'should be boolean value', options.alpha);566 } else {567 this.options.negateAlpha = options.alpha;568 }569 }570 return this;571}572 573/**574 * Enhance output image contrast by stretching its luminance to cover a full dynamic range.575 *576 * Uses a histogram-based approach, taking a default range of 1% to 99% to reduce sensitivity to noise at the extremes.577 *578 * Luminance values below the `lower` percentile will be underexposed by clipping to zero.579 * Luminance values above the `upper` percentile will be overexposed by clipping to the max pixel value.580 *581 * @example582 * const output = await sharp(input)583 * .normalise()584 * .toBuffer();585 *586 * @example587 * const output = await sharp(input)588 * .normalise({ lower: 0, upper: 100 })589 * .toBuffer();590 *591 * @param {Object} [options]592 * @param {number} [options.lower=1] - Percentile below which luminance values will be underexposed.593 * @param {number} [options.upper=99] - Percentile above which luminance values will be overexposed.594 * @returns {Sharp}595 */596function normalise (options) {597 if (is.plainObject(options)) {598 if (is.defined(options.lower)) {599 if (is.number(options.lower) && is.inRange(options.lower, 0, 99)) {600 this.options.normaliseLower = options.lower;601 } else {602 throw is.invalidParameterError('lower', 'number between 0 and 99', options.lower);603 }604 }605 if (is.defined(options.upper)) {606 if (is.number(options.upper) && is.inRange(options.upper, 1, 100)) {607 this.options.normaliseUpper = options.upper;608 } else {609 throw is.invalidParameterError('upper', 'number between 1 and 100', options.upper);610 }611 }612 }613 if (this.options.normaliseLower >= this.options.normaliseUpper) {614 throw is.invalidParameterError('range', 'lower to be less than upper',615 `${this.options.normaliseLower} >= ${this.options.normaliseUpper}`);616 }617 this.options.normalise = true;618 return this;619}620 621/**622 * Alternative spelling of normalise.623 *624 * @example625 * const output = await sharp(input)626 * .normalize()627 * .toBuffer();628 *629 * @param {Object} [options]630 * @param {number} [options.lower=1] - Percentile below which luminance values will be underexposed.631 * @param {number} [options.upper=99] - Percentile above which luminance values will be overexposed.632 * @returns {Sharp}633 */634function normalize (options) {635 return this.normalise(options);636}637 638/**639 * Perform contrast limiting adaptive histogram equalization640 * {@link https://en.wikipedia.org/wiki/Adaptive_histogram_equalization#Contrast_Limited_AHE CLAHE}.641 *642 * This will, in general, enhance the clarity of the image by bringing out darker details.643 *644 * @since 0.28.3645 *646 * @example647 * const output = await sharp(input)648 * .clahe({649 * width: 3,650 * height: 3,651 * })652 * .toBuffer();653 *654 * @param {Object} options655 * @param {number} options.width - Integral width of the search window, in pixels, between 1 and 65536.656 * @param {number} options.height - Integral height of the search window, in pixels, between 1 and 65536.657 * @param {number} [options.maxSlope=3] - Integral level of brightening, between 0 and 100, where 0 disables contrast limiting.658 * @returns {Sharp}659 * @throws {Error} Invalid parameters660 */661function clahe (options) {662 if (is.plainObject(options)) {663 if (is.integer(options.width) && is.inRange(options.width, 1, 65536)) {664 this.options.claheWidth = options.width;665 } else {666 throw is.invalidParameterError('width', 'integer between 1 and 65536', options.width);667 }668 if (is.integer(options.height) && is.inRange(options.height, 1, 65536)) {669 this.options.claheHeight = options.height;670 } else {671 throw is.invalidParameterError('height', 'integer between 1 and 65536', options.height);672 }673 if (is.defined(options.maxSlope)) {674 if (is.integer(options.maxSlope) && is.inRange(options.maxSlope, 0, 100)) {675 this.options.claheMaxSlope = options.maxSlope;676 } else {677 throw is.invalidParameterError('maxSlope', 'integer between 0 and 100', options.maxSlope);678 }679 }680 } else {681 throw is.invalidParameterError('options', 'plain object', options);682 }683 return this;684}685 686/**687 * Convolve the image with the specified kernel.688 *689 * @example690 * sharp(input)691 * .convolve({692 * width: 3,693 * height: 3,694 * kernel: [-1, 0, 1, -2, 0, 2, -1, 0, 1]695 * })696 * .raw()697 * .toBuffer(function(err, data, info) {698 * // data contains the raw pixel data representing the convolution699 * // of the input image with the horizontal Sobel operator700 * });701 *702 * @param {Object} kernel703 * @param {number} kernel.width - width of the kernel in pixels.704 * @param {number} kernel.height - height of the kernel in pixels.705 * @param {Array<number>} kernel.kernel - Array of length `width*height` containing the kernel values.706 * @param {number} [kernel.scale=sum] - the scale of the kernel in pixels.707 * @param {number} [kernel.offset=0] - the offset of the kernel in pixels.708 * @returns {Sharp}709 * @throws {Error} Invalid parameters710 */711function convolve (kernel) {712 if (!is.object(kernel) || !Array.isArray(kernel.kernel) ||713 !is.integer(kernel.width) || !is.integer(kernel.height) ||714 !is.inRange(kernel.width, 3, 1001) || !is.inRange(kernel.height, 3, 1001) ||715 kernel.height * kernel.width !== kernel.kernel.length ||716 !kernel.kernel.every(is.number)717 ) {718 // must pass in a kernel719 throw new Error('Invalid convolution kernel');720 }721 // Default scale is sum of kernel values722 if (!is.integer(kernel.scale)) {723 kernel.scale = kernel.kernel.reduce((a, b) => a + b, 0);724 }725 // Clip scale to a minimum value of 1726 if (kernel.scale < 1) {727 kernel.scale = 1;728 }729 if (!is.integer(kernel.offset)) {730 kernel.offset = 0;731 }732 this.options.convKernel = kernel;733 return this;734}735 736/**737 * Any pixel value greater than or equal to the threshold value will be set to 255, otherwise it will be set to 0.738 * @param {number} [threshold=128] - a value in the range 0-255 representing the level at which the threshold will be applied.739 * @param {Object} [options]740 * @param {Boolean} [options.greyscale=true] - convert to single channel greyscale.741 * @param {Boolean} [options.grayscale=true] - alternative spelling for greyscale.742 * @returns {Sharp}743 * @throws {Error} Invalid parameters744 */745function threshold (threshold, options) {746 if (!is.defined(threshold)) {747 this.options.threshold = 128;748 } else if (is.bool(threshold)) {749 this.options.threshold = threshold ? 128 : 0;750 } else if (is.integer(threshold) && is.inRange(threshold, 0, 255)) {751 this.options.threshold = threshold;752 } else {753 throw is.invalidParameterError('threshold', 'integer between 0 and 255', threshold);754 }755 if (!is.object(options) || options.greyscale === true || options.grayscale === true) {756 this.options.thresholdGrayscale = true;757 } else {758 this.options.thresholdGrayscale = false;759 }760 return this;761}762 763/**764 * Perform a bitwise boolean operation with operand image.765 *766 * This operation creates an output image where each pixel is the result of767 * the selected bitwise boolean `operation` between the corresponding pixels of the input images.768 *769 * @param {Buffer|string} operand - Buffer containing image data or string containing the path to an image file.770 * @param {string} operator - one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively.771 * @param {Object} [options]772 * @param {Object} [options.raw] - describes operand when using raw pixel data.773 * @param {number} [options.raw.width]774 * @param {number} [options.raw.height]775 * @param {number} [options.raw.channels]776 * @returns {Sharp}777 * @throws {Error} Invalid parameters778 */779function boolean (operand, operator, options) {780 this.options.boolean = this._createInputDescriptor(operand, options);781 if (is.string(operator) && is.inArray(operator, ['and', 'or', 'eor'])) {782 this.options.booleanOp = operator;783 } else {784 throw is.invalidParameterError('operator', 'one of: and, or, eor', operator);785 }786 return this;787}788 789/**790 * Apply the linear formula `a` * input + `b` to the image to adjust image levels.791 *792 * When a single number is provided, it will be used for all image channels.793 * When an array of numbers is provided, the array length must match the number of channels.794 *795 * @example796 * await sharp(input)797 * .linear(0.5, 2)798 * .toBuffer();799 *800 * @example801 * await sharp(rgbInput)802 * .linear(803 * [0.25, 0.5, 0.75],804 * [150, 100, 50]805 * )806 * .toBuffer();807 *808 * @param {(number|number[])} [a=[]] multiplier809 * @param {(number|number[])} [b=[]] offset810 * @returns {Sharp}811 * @throws {Error} Invalid parameters812 */813function linear (a, b) {814 if (!is.defined(a) && is.number(b)) {815 a = 1.0;816 } else if (is.number(a) && !is.defined(b)) {817 b = 0.0;818 }819 if (!is.defined(a)) {820 this.options.linearA = [];821 } else if (is.number(a)) {822 this.options.linearA = [a];823 } else if (Array.isArray(a) && a.length && a.every(is.number)) {824 this.options.linearA = a;825 } else {826 throw is.invalidParameterError('a', 'number or array of numbers', a);827 }828 if (!is.defined(b)) {829 this.options.linearB = [];830 } else if (is.number(b)) {831 this.options.linearB = [b];832 } else if (Array.isArray(b) && b.length && b.every(is.number)) {833 this.options.linearB = b;834 } else {835 throw is.invalidParameterError('b', 'number or array of numbers', b);836 }837 if (this.options.linearA.length !== this.options.linearB.length) {838 throw new Error('Expected a and b to be arrays of the same length');839 }840 return this;841}842 843/**844 * Recombine the image with the specified matrix.845 *846 * @since 0.21.1847 *848 * @example849 * sharp(input)850 * .recomb([851 * [0.3588, 0.7044, 0.1368],852 * [0.2990, 0.5870, 0.1140],853 * [0.2392, 0.4696, 0.0912],854 * ])855 * .raw()856 * .toBuffer(function(err, data, info) {857 * // data contains the raw pixel data after applying the matrix858 * // With this example input, a sepia filter has been applied859 * });860 *861 * @param {Array<Array<number>>} inputMatrix - 3x3 or 4x4 Recombination matrix862 * @returns {Sharp}863 * @throws {Error} Invalid parameters864 */865function recomb (inputMatrix) {866 if (!Array.isArray(inputMatrix)) {867 throw is.invalidParameterError('inputMatrix', 'array', inputMatrix);868 }869 const dimensions = inputMatrix.length;870 if (dimensions !== 3 && dimensions !== 4) {871 throw is.invalidParameterError('inputMatrix', '3x3 or 4x4 array', dimensions);872 }873 if (!inputMatrix.every((row) => Array.isArray(row) && row.length === dimensions)) {874 throw is.invalidParameterError('inputMatrix', `array of ${dimensions} arrays of length ${dimensions}`, inputMatrix);875 }876 const recombMatrix = inputMatrix.flat();877 if (!recombMatrix.every(is.number)) {878 throw is.invalidParameterError('inputMatrix', 'array of numbers', recombMatrix);879 }880 this.options.recombMatrix = recombMatrix;881 return this;882}883 884/**885 * Transforms the image using brightness, saturation, hue rotation, and lightness.886 * Brightness and lightness both operate on luminance, with the difference being that887 * brightness is multiplicative whereas lightness is additive.888 *889 * @since 0.22.1890 *891 * @example892 * // increase brightness by a factor of 2893 * const output = await sharp(input)894 * .modulate({895 * brightness: 2896 * })897 * .toBuffer();898 *899 * @example900 * // hue-rotate by 180 degrees901 * const output = await sharp(input)902 * .modulate({903 * hue: 180904 * })905 * .toBuffer();906 *907 * @example908 * // increase lightness by +50909 * const output = await sharp(input)910 * .modulate({911 * lightness: 50912 * })913 * .toBuffer();914 *915 * @example916 * // decrease brightness and saturation while also hue-rotating by 90 degrees917 * const output = await sharp(input)918 * .modulate({919 * brightness: 0.5,920 * saturation: 0.5,921 * hue: 90,922 * })923 * .toBuffer();924 *925 * @param {Object} [options]926 * @param {number} [options.brightness] Brightness multiplier927 * @param {number} [options.saturation] Saturation multiplier928 * @param {number} [options.hue] Degrees for hue rotation929 * @param {number} [options.lightness] Lightness addend930 * @returns {Sharp}931 */932function modulate (options) {933 if (!is.plainObject(options)) {934 throw is.invalidParameterError('options', 'plain object', options);935 }936 if ('brightness' in options) {937 if (is.number(options.brightness) && options.brightness >= 0) {938 this.options.brightness = options.brightness;939 } else {940 throw is.invalidParameterError('brightness', 'number above zero', options.brightness);941 }942 }943 if ('saturation' in options) {944 if (is.number(options.saturation) && options.saturation >= 0) {945 this.options.saturation = options.saturation;946 } else {947 throw is.invalidParameterError('saturation', 'number above zero', options.saturation);948 }949 }950 if ('hue' in options) {951 if (is.integer(options.hue)) {952 this.options.hue = options.hue % 360;953 } else {954 throw is.invalidParameterError('hue', 'number', options.hue);955 }956 }957 if ('lightness' in options) {958 if (is.number(options.lightness)) {959 this.options.lightness = options.lightness;960 } else {961 throw is.invalidParameterError('lightness', 'number', options.lightness);962 }963 }964 return this;965}966 967/**968 * Decorate the Sharp prototype with operation-related functions.969 * @module Sharp970 * @private971 */972module.exports = (Sharp) => {973 Object.assign(Sharp.prototype, {974 autoOrient,975 rotate,976 flip,977 flop,978 affine,979 sharpen,980 erode,981 dilate,982 median,983 blur,984 flatten,985 unflatten,986 gamma,987 negate,988 normalise,989 normalize,990 clahe,991 convolve,992 threshold,993 boolean,994 linear,995 recomb,996 modulate997 });998};999 