image-js
Version:
Image processing and manipulation in JavaScript
104 lines (93 loc) • 2.52 kB
text/typescript
import type { BitDepth } from '../Image.js';
import { Image } from '../Image.js';
import type { BorderType } from '../utils/interpolateBorder.js';
import checkProcessable from '../utils/validators/checkProcessable.js';
export interface GradientFilterBaseOptions {
/**
* Specify how the borders should be handled.
* @default `'replicate'`
*/
borderType?: BorderType;
/**
* Value of the border if BorderType is 'constant'.
* @default `0`
*/
borderValue?: number;
/**
* Specify the bit depth of the resulting image.
* @default `image.bitDepth`
*/
bitDepth?: BitDepth;
}
export interface GradientFilterXOptions extends GradientFilterBaseOptions {
/**
* Kernel along x axis.
*/
kernelX: number[][];
}
export interface GradientFilterYOptions extends GradientFilterBaseOptions {
/**
* Kernel along y axis.
*/
kernelY: number[][];
}
export interface GradientFilterXYOptions extends GradientFilterBaseOptions {
/**
* Kernel along x axis.
*/
kernelX: number[][];
/**
* Kernel along y axis.
*/
kernelY: number[][];
}
export type GradientFilterOptions =
| GradientFilterXOptions
| GradientFilterYOptions
| GradientFilterXYOptions;
/**
* Apply a gradient filter to an image.
* @param image - The image to process.
* @param options - Gradient filter options.
* @returns The gradient image.
*/
export function gradientFilter(
image: Image,
options: GradientFilterOptions,
): Image {
const { borderType = 'replicate', borderValue = 0 } = options;
checkProcessable(image, {
bitDepth: [8, 16],
colorModel: 'GREY',
});
if ('kernelX' in options && 'kernelY' in options) {
const { kernelX, kernelY } = options;
const gradientX = image.rawDirectConvolution(kernelX, {
borderType,
borderValue,
});
const gradientY = image.rawDirectConvolution(kernelY, {
borderType,
borderValue,
});
const gradient = new Image(image.width, image.height, {
colorModel: 'GREY',
});
for (let i = 0; i < image.size; i++) {
gradient.setValueByIndex(i, 0, Math.hypot(gradientX[i], gradientY[i]));
}
return gradient;
} else if ('kernelX' in options) {
return image.directConvolution(options.kernelX, {
borderType,
borderValue,
});
} else if ('kernelY' in options) {
return image.directConvolution(options.kernelY, {
borderType,
borderValue,
});
} else {
throw new TypeError(`kernelX and KernelY are not defined`);
}
}