114 lines
3.6 KiB
TypeScript
114 lines
3.6 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
||
import { colorMask, flattenOntoColor, parseHex, removeColorToAlpha } from './alpha';
|
||
import { makeImage } from './test-helpers';
|
||
|
||
describe('removeColorToAlpha', () => {
|
||
const fixture = () =>
|
||
makeImage(2, 1, [
|
||
[255, 255, 255, 255],
|
||
[255, 0, 0, 255]
|
||
]);
|
||
|
||
it('обнуляет альфу только у точного совпадения при tolerance=0', () => {
|
||
const out = removeColorToAlpha(fixture(), '#ff0000', 0);
|
||
expect(out.data[3]).toBe(255);
|
||
expect(out.data[7]).toBe(0);
|
||
expect(out.data[4]).toBe(255);
|
||
expect(out.data[5]).toBe(0);
|
||
});
|
||
|
||
it('поддерживает короткую форму и регистр hex', () => {
|
||
expect([...removeColorToAlpha(fixture(), '#f00', 0).data.slice(4)]).toEqual([
|
||
255, 0, 0, 0
|
||
]);
|
||
expect([...removeColorToAlpha(fixture(), '#FF0000', 0).data.slice(4)]).toEqual([
|
||
255, 0, 0, 0
|
||
]);
|
||
});
|
||
|
||
it('tolerance 100% удаляет весь диапазон расстояний', () => {
|
||
const out = removeColorToAlpha(fixture(), '#000000', 100);
|
||
expect(out.data[3]).toBe(0);
|
||
expect(out.data[7]).toBe(0);
|
||
});
|
||
|
||
it('промежуточный tolerance различает близкие и далёкие цвета', () => {
|
||
const img = makeImage(2, 1, [
|
||
[0, 0, 0, 255],
|
||
[128, 128, 128, 255]
|
||
]);
|
||
const kept = removeColorToAlpha(img, '#000000', 40);
|
||
const removed = removeColorToAlpha(img, '#000000', 60);
|
||
expect(kept.data[3]).toBe(0);
|
||
expect(kept.data[7]).toBe(255);
|
||
expect(removed.data[3]).toBe(0);
|
||
expect(removed.data[7]).toBe(0);
|
||
});
|
||
|
||
it('не мутирует вход', () => {
|
||
const img = fixture();
|
||
removeColorToAlpha(img, '#ffffff', 100);
|
||
expect([...img.data]).toEqual([
|
||
255, 255, 255, 255,
|
||
255, 0, 0, 255
|
||
]);
|
||
});
|
||
});
|
||
|
||
describe('colorMask', () => {
|
||
it('удаляемые пиксели белые, остальные чёрные, маска непрозрачная', () => {
|
||
const out = colorMask(
|
||
makeImage(2, 1, [
|
||
[255, 0, 0, 255],
|
||
[0, 255, 0, 255]
|
||
]),
|
||
'#ff0000',
|
||
0
|
||
);
|
||
expect([...out.data]).toEqual([
|
||
255, 255, 255, 255,
|
||
0, 0, 0, 255
|
||
]);
|
||
});
|
||
|
||
it('порог совпадает с removeColorToAlpha', () => {
|
||
const img = makeImage(2, 1, [
|
||
[0, 0, 0, 255],
|
||
[128, 128, 128, 255]
|
||
]);
|
||
const kept = colorMask(img, '#000000', 40);
|
||
const removed = colorMask(img, '#000000', 60);
|
||
expect(kept.data[4]).toBe(0);
|
||
expect(removed.data[4]).toBe(255);
|
||
});
|
||
});
|
||
|
||
describe('flattenOntoColor', () => {
|
||
it('непрозрачный пиксель не меняется, альфа становится 255', () => {
|
||
const out = flattenOntoColor(makeImage(1, 1, [[10, 20, 30, 255]]), '#ffffff');
|
||
expect([...out.data]).toEqual([10, 20, 30, 255]);
|
||
});
|
||
|
||
it('полностью прозрачный пиксель становится цветом подложки', () => {
|
||
const out = flattenOntoColor(makeImage(1, 1, [[99, 99, 99, 0]]), '#ff8040');
|
||
expect([...out.data]).toEqual([255, 128, 64, 255]);
|
||
});
|
||
|
||
it('полупрозрачный пиксель смешивается с подложкой', () => {
|
||
const out = flattenOntoColor(makeImage(1, 1, [[10, 20, 30, 128]]), '#ffffff');
|
||
expect([...out.data]).toEqual([132, 137, 142, 255]);
|
||
});
|
||
});
|
||
|
||
describe('parseHex', () => {
|
||
it('разбирает #rrggbb, rrggbb, #rgb', () => {
|
||
expect(parseHex('#ff8040')).toEqual([255, 128, 64]);
|
||
expect(parseHex('ff8040')).toEqual([255, 128, 64]);
|
||
expect(parseHex('#F80')).toEqual([255, 136, 0]);
|
||
});
|
||
|
||
it.each(['zzz', '12345', '##ff', ''])('бросает ошибку на "%s"', (bad) => {
|
||
expect(() => parseHex(bad)).toThrow(/Некорректный HEX/);
|
||
});
|
||
});
|