Skip to content
This repository was archived by the owner on Jul 26, 2025. It is now read-only.

feat: add setBlendedPixel for draw* functions #478

Merged
merged 10 commits into from
Oct 3, 2024
18 changes: 18 additions & 0 deletions src/draw/__tests__/drawLineOnImage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@ test('RGB image', () => {
expect(result).not.toBe(image);
});

test('RGBA image with different alphas', () => {
const image = testUtils.createRgbaImage([
[100, 150, 200, 150, 100, 150, 0, 150],
[100, 200, 5, 150, 3, 200, 0, 150],
[150, 200, 255, 150, 6, 150, 0, 150],
]);

const from = { row: 0, column: 0 };
const to = { row: 1, column: 1 };
const result = image.drawLine(from, to, { strokeColor: [255, 0, 0, 50] });
expect(result).toMatchImageData([
[145, 106, 141, 170, 100, 150, 0, 150],
[100, 200, 5, 150, 76, 141, 0, 170],
[150, 200, 255, 150, 6, 150, 0, 150],
]);
expect(result).not.toBe(image);
});

test('out parameter set to self', () => {
const image = testUtils.createRgbImage([
[100, 150, 200, 100, 150, 0],
Expand Down
11 changes: 7 additions & 4 deletions src/draw/drawCircleOnImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { Point } from '../utils/geometry/points';
import { getDefaultColor } from '../utils/getDefaultColor';
import { getOutputImage } from '../utils/getOutputImage';
import { setBlendedVisiblePixel } from '../utils/setBlendedVisiblePixel';
import checkProcessable from '../utils/validators/checkProcessable';
import { validateColor } from '../utils/validators/validators';

Expand Down Expand Up @@ -60,22 +61,24 @@
radius = Math.round(radius);

if (radius === 0) {
newImage.setVisiblePixel(center.column, center.row, color);
setBlendedVisiblePixel(newImage, center.column, center.row, { color });
return newImage;
}

if (!fill) {
circle(center.column, center.row, radius, (column: number, row: number) => {
newImage.setVisiblePixel(column, row, color);
setBlendedVisiblePixel(newImage, column, row, { color });
});
} else {
if (radius === 1) {
newImage.setVisiblePixel(center.column, center.row, fill);
setBlendedVisiblePixel(newImage, center.column, center.row, {
color: fill,
});
}
circle(center.column, center.row, radius, (column: number, row: number) => {
newImage.setVisiblePixel(column, row, color);
setBlendedVisiblePixel(newImage, column, row, { color });

//todo: fill is not optimal we can fill symmetrically

Check warning on line 81 in src/draw/drawCircleOnImage.ts

View workflow job for this annotation

GitHub Actions / nodejs / lint-eslint

Unexpected 'todo' comment: 'todo: fill is not optimal we can fill...'
if (column - 1 > center.column) {
newImage.drawLine(
{ row, column: column - 1 },
Expand Down
6 changes: 4 additions & 2 deletions src/draw/drawPoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Mask } from '../Mask';
import { Point } from '../utils/geometry/points';
import { getDefaultColor } from '../utils/getDefaultColor';
import { getOutputImage, maskToOutputMask } from '../utils/getOutputImage';
import { setBlendedVisiblePixel } from '../utils/setBlendedVisiblePixel';
import checkProcessable from '../utils/validators/checkProcessable';
import { validateColor } from '../utils/validators/validators';

Expand Down Expand Up @@ -61,10 +62,11 @@ export function drawPoints(
});

for (const point of points) {
newImage.setVisiblePixel(
setBlendedVisiblePixel(
newImage,
Math.round(origin.column + point.column),
Math.round(origin.row + point.row),
color,
{ color },
);
}

Expand Down
6 changes: 4 additions & 2 deletions src/draw/drawPolygonOnImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Image } from '../Image';
import { arrayPointsToObjects } from '../utils/arrayPointsToObjects';
import { Point } from '../utils/geometry/points';
import { getOutputImage } from '../utils/getOutputImage';
import { setBlendedVisiblePixel } from '../utils/setBlendedVisiblePixel';
import checkProcessable from '../utils/validators/checkProcessable';
import { validateColor } from '../utils/validators/validators';

Expand Down Expand Up @@ -61,10 +62,11 @@ export function drawPolygonOnImage(
for (let row = 0; row < newImage.height; row++) {
for (let column = 0; column < newImage.width; column++) {
if (robustPointInPolygon(arrayPoints, [column, row]) === -1) {
newImage.setPixel(
setBlendedVisiblePixel(
newImage,
Math.round(origin.column) + column,
Math.round(origin.row) + row,
fillColor,
{ color: fillColor },
);
}
}
Expand Down
25 changes: 19 additions & 6 deletions src/draw/drawRectangle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Mask } from '../Mask';
import { Point } from '../utils/geometry/points';
import { getDefaultColor } from '../utils/getDefaultColor';
import { getOutputImage, maskToOutputMask } from '../utils/getOutputImage';
import { setBlendedVisiblePixel } from '../utils/setBlendedVisiblePixel';
import checkProcessable from '../utils/validators/checkProcessable';

export interface DrawRectangleOptions<OutType> {
Expand Down Expand Up @@ -82,16 +83,24 @@ export function drawRectangle(
currentColumn < column + width;
currentColumn++
) {
newImage.setVisiblePixel(currentColumn, row, strokeColor);
newImage.setVisiblePixel(currentColumn, row + height - 1, strokeColor);
setBlendedVisiblePixel(newImage, currentColumn, row, {
color: strokeColor,
});
setBlendedVisiblePixel(newImage, currentColumn, row + height - 1, {
color: strokeColor,
});
}
for (
let currentRow = row + 1;
currentRow < row + height - 1;
currentRow++
) {
newImage.setVisiblePixel(column, currentRow, strokeColor);
newImage.setVisiblePixel(column + width - 1, currentRow, strokeColor);
setBlendedVisiblePixel(newImage, column, currentRow, {
color: strokeColor,
});
setBlendedVisiblePixel(newImage, column + width - 1, currentRow, {
color: strokeColor,
});
}
}
if (fillColor !== 'none') {
Expand All @@ -105,8 +114,12 @@ export function drawRectangle(
currentColumn < column + width - 1;
currentColumn++
) {
newImage.setVisiblePixel(currentColumn, currentRow, fillColor);
newImage.setVisiblePixel(currentColumn, currentRow, fillColor);
/* setBlendedVisiblePixel(newImage, currentColumn, currentRow, {
color: fillColor,
});*/
setBlendedVisiblePixel(newImage, currentColumn, currentRow, {
color: fillColor,
});
}
}
}
Expand Down
63 changes: 63 additions & 0 deletions src/utils/__tests__/setBlendedVisiblePixel.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { setBlendedVisiblePixel } from '../setBlendedVisiblePixel';

test('GREYA image, default options', () => {
const image = testUtils.createGreyaImage([
[50, 255],
[20, 30],
]);
setBlendedVisiblePixel(image, 0, 1);
expect(image).toMatchImageData([
[50, 255],
[0, 255],
]);
});

test('GREYA image: set pixel out of bounds', () => {
const image = testUtils.createGreyaImage([
[50, 255, 1, 2, 3, 4],
[20, 30, 5, 6, 7, 8],
[1, 2, 3, 4, 5, 6],
]);
setBlendedVisiblePixel(image, 0, 5, { color: [40, 40] });
expect(image).toMatchImageData([
[50, 255, 1, 2, 3, 4],
[20, 30, 5, 6, 7, 8],
[1, 2, 3, 4, 5, 6],
]);
});

test('RGBA image: set pixel out of bounds', () => {
const image = testUtils.createGreyaImage([
[50, 255, 1, 200, 2, 3, 4, 200],
[20, 30, 5, 200, 6, 7, 8, 200],
[1, 2, 3, 200, 4, 5, 6, 200],
]);
setBlendedVisiblePixel(image, 0, 5, { color: [40, 40, 40, 40] });
expect(image).toMatchImageData([
[50, 255, 1, 200, 2, 3, 4, 200],
[20, 30, 5, 200, 6, 7, 8, 200],
[1, 2, 3, 200, 4, 5, 6, 200],
]);
});

test('GREYA image: alpha different from 255', () => {
const image = testUtils.createGreyaImage([[50, 64]]);
setBlendedVisiblePixel(image, 0, 0, { color: [100, 128] });
const alpha = 128 + 64 * (1 - 128 / 255);
const component = (100 * 128 + 50 * 64 * (1 - 128 / 255)) / alpha;
expect(image).toMatchImageData([[component, alpha]]);
});

test('asymetrical test', () => {
const image = testUtils.createGreyaImage([
[50, 255, 1, 2, 3, 4],
[20, 30, 5, 6, 7, 8],
[1, 2, 3, 4, 5, 6],
]);
setBlendedVisiblePixel(image, 2, 0, { color: [0, 125] });
expect(image).toMatchImageData([
[50, 255, 1, 2, 0, 127],
[20, 30, 5, 6, 7, 8],
[1, 2, 3, 4, 5, 6],
]);
});
Loading