image-js
Version:
Image processing and manipulation in JavaScript
249 lines (243 loc) • 7.64 kB
text/typescript
import type { Image } from '../Image.js';
import { assert } from '../utils/validators/assert.js';
/**
* Converts R, G and B values to a single value using Luma 709 standard({@link https://en.wikipedia.org/wiki/Luma_(video)}).
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @returns - Corresponding gray value.
*/
export function luma709(red: number, green: number, blue: number): number {
// sRGB
// return red * 0.2126 + green * 0.7152 + blue * 0.0722;
// Let's do a little trick ... in order not convert the integer to a double we do
// the multiplication with integer to reach a total of 32768 and then shift the bits
// of 15 to the right
// This does a Math.floor and may lead to small (max 1) difference
// Same result, > 10% faster on the full grey conversion
return (red * 6966 + green * 23436 + blue * 2366) >> 15;
}
/**
* Converts R, G and B values to a single value using Luma 601 standard({@link https://en.wikipedia.org/wiki/Luma_(video)}).
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @returns - Corresponding gray value.
*/
export function luma601(red: number, green: number, blue: number): number {
// NTSC
// return this.red * 0.299 + green * 0.587 + blue * 0.114;
return (red * 9798 + green * 19235 + blue * 3735) >> 15;
}
/**
* Return the maximal value between red, green and blue.
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @returns - Corresponding gray value.
*/
export function max(red: number, green: number, blue: number): number {
return Math.max(red, green, blue);
}
/**
* Return the minimal value between red, green and blue.
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @returns - Corresponding gray value.
*/
export function min(red: number, green: number, blue: number): number {
return Math.min(red, green, blue);
}
/**
* Return the average of red, green and blue.
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @returns - Corresponding gray value.
*/
export function average(red: number, green: number, blue: number): number {
return ((red + green + blue) / 3) >> 0;
}
/**
* Return the average between the max and min values of red, green and blue.
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @returns - Corresponding gray value.
*/
export function minmax(red: number, green: number, blue: number): number {
return (Math.max(red, green, blue) + Math.min(red, green, blue)) / 2;
}
/**
* Return the red value.
* @param red - Red value of current pixel.
* @returns - Corresponding gray value.
*/
export function red(red: number): number {
return red;
}
/**
* Return the green value.
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @returns - Corresponding gray value.
*/
export function green(red: number, green: number): number {
return green;
}
/**
* Return the blue value.
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @returns - Corresponding gray value.
*/
export function blue(red: number, green: number, blue: number): number {
return blue;
}
/**
* Return the minimum of the inverses of red, green and blue.
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @param image - Image to convert to grey.
* @returns - Corresponding gray value.
*/
export function black(
red: number,
green: number,
blue: number,
image: Image,
): number {
return Math.min(
image.maxValue - red,
image.maxValue - green,
image.maxValue - blue,
);
}
/**
* Returns the cyan component of a pixel.
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @param image - Image to convert to grey.
* @returns - Corresponding gray value.
*/
export function cyan(
red: number,
green: number,
blue: number,
image: Image,
): number {
const blackColor = black(red, green, blue, image);
return (
((image.maxValue - red - blackColor) / (1 - blackColor / image.maxValue)) >>
0
);
}
/**
* Returns the magenta component of a pixel.
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @param image - Image to convert to grey.
* @returns - Corresponding gray value.
*/
export function magenta(
red: number,
green: number,
blue: number,
image: Image,
): number {
const blackColor = black(red, green, blue, image);
return (
((image.maxValue - green - blackColor) /
(1 - blackColor / image.maxValue)) >>
0
);
}
/**
* Returns the yellow component of a pixel.
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @param image - Image to convert to grey.
* @returns - Corresponding gray value.
*/
export function yellow(
red: number,
green: number,
blue: number,
image: Image,
): number {
const blackColor = black(red, green, blue, image);
return (
((image.maxValue - blue - blackColor) /
(1 - blackColor / image.maxValue)) >>
0
);
}
/**
* Returns the hue of a pixel as a value between 0 and 255.
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @param image - Source image for the RGB values.
* @returns - Hue of the pixel.
*/
export function hue(
red: number,
green: number,
blue: number,
image: Image,
): number {
const minValue = min(red, green, blue);
const maxValue = max(red, green, blue);
if (maxValue === minValue) {
return 0;
}
let hue = 0;
const delta = maxValue - minValue;
if (maxValue === red) {
hue = (green - blue) / delta + (green < blue ? 6 : 0);
} else if (maxValue === green) {
hue = (blue - red) / delta + 2;
} else {
assert(maxValue === blue);
hue = (red - green) / delta + 4;
}
return ((hue / 6) * image.maxValue) >> 0;
}
/**
* Returns the saturation component of a pixel.
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @param image - Source image for the RGB values.
* @returns - Saturation of the pixel.
*/
export function saturation(
red: number,
green: number,
blue: number,
image: Image,
): number {
// from HSV model
const minValue = min(red, green, blue);
const maxValue = max(red, green, blue);
const delta = maxValue - minValue;
return maxValue === 0 ? 0 : (delta / maxValue) * image.maxValue;
}
/**
* Returns the lightness of a pixel.
* @param red - Red value of current pixel.
* @param green - Green value of current pixel.
* @param blue - Blue value of current pixel.
* @returns - Lightness of the pixel.
*/
export function lightness(red: number, green: number, blue: number): number {
const minValue = min(red, green, blue);
const maxValue = max(red, green, blue);
return (maxValue + minValue) / 2;
}