import { Image } from '../Image.js'; import { getDefaultColor } from '../utils/getDefaultColor.ts'; import type { BorderType } from '../utils/interpolateBorder.js'; import { getBorderInterpolation } from '../utils/interpolateBorder.js'; import { validateColor } from '../utils/validators/validators.ts'; export interface ExtendBordersOptions { /** * Left and right border thickness. */ horizontal: number; /** *Top and bottom border thickness. */ vertical: number; /** * Specify how the borders should be handled. * @default `'reflect101'` */ borderType?: BorderType; /** * Value of the border if BorderType is 'constant'. * @default `0` */ borderValue?: number | number[]; } /** * Extend the borders of an image according to the given border type. * @param image - Image to extend. * @param options - Options. * @returns A copy of the image with extended borders. */ export function extendBorders( image: Image, options: ExtendBordersOptions, ): Image { const { horizontal, vertical, borderType = 'reflect101', borderValue = getDefaultColor(image), } = options; if (Array.isArray(borderValue)) { validateColor(borderValue, image); } const interpolateBorder = getBorderInterpolation(borderType, borderValue); const newImage = Image.createFrom(image, { width: image.width + 2 * horizontal, height: image.height + 2 * vertical, }); image.copyTo(newImage, { origin: { column: horizontal, row: vertical, }, out: newImage, }); // Top strip for (let row = 0; row < vertical; row++) { for (let col = 0; col < newImage.width; col++) { for (let channel = 0; channel < image.channels; channel++) { const newValue = interpolateBorder( col - horizontal, row - vertical, channel, image, ); newImage.setValue(col, row, channel, newValue); } } } // Bottom strip for (let row = newImage.height - vertical; row < newImage.height; row++) { for (let col = 0; col < newImage.width; col++) { for (let channel = 0; channel < image.channels; channel++) { const newValue = interpolateBorder( col - horizontal, row - vertical, channel, image, ); newImage.setValue(col, row, channel, newValue); } } } // Left strip for (let row = vertical; row < newImage.height - vertical; row++) { for (let col = 0; col < horizontal; col++) { for (let channel = 0; channel < image.channels; channel++) { const newValue = interpolateBorder( col - horizontal, row - vertical, channel, image, ); newImage.setValue(col, row, channel, newValue); } } } // Right strip for (let row = vertical; row < newImage.height - vertical; row++) { for (let col = newImage.width - horizontal; col < newImage.width; col++) { for (let channel = 0; channel < image.channels; channel++) { const newValue = interpolateBorder( col - horizontal, row - vertical, channel, image, ); newImage.setValue(col, row, channel, newValue); } } } return newImage; }