Skip to content

Commit

Permalink
Merge pull request #27 from studio-YOLO/26-add-missing-tests-and-demos
Browse files Browse the repository at this point in the history
update: added tests for brightness, contrast, saturation
  • Loading branch information
DPende authored Mar 19, 2024
2 parents b2ce073 + 901b402 commit 8093bd9
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 19 deletions.
9 changes: 6 additions & 3 deletions src/core/change_brightness.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ import utils from "../utils.js";
* @returns {number[]} adjustedPixelArray: Adjusted image pixel array in the format [R, G, B, alpha,..., R, G, B, alpha]
*/
function changeBrightness(pixelArray, factor) {
const adjustedPixelArray = [];
if (factor == 0)
return pixelArray;
for (let i = 0; i < pixelArray.length; i += 4) {
const hsl = utils.rgbToHsl(pixelArray[i], pixelArray[i + 1], pixelArray[i + 2]);
hsl[2] = Math.max(0, Math.min(100, hsl[2] += factor));
const rgb = utils.hslToRgb(hsl[0], hsl[1], hsl[2]);

adjustedPixelArray.push(rgb[0], rgb[1], rgb[2], pixelArray[i + 3]);
pixelArray[i] = rgb[0];
pixelArray[i + 1] = rgb[1];
pixelArray[i + 2] = rgb[2];
}
return adjustedPixelArray;
return pixelArray;
}

export default changeBrightness;
15 changes: 5 additions & 10 deletions src/core/change_contrast.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,16 @@
* @returns {number[]} contrastArray: an array in the format [R, G, B, alpha,..., R, G, B, alpha]
**/
function changeContrast(pixelArray, factor) {
const clip = (value) => {
return Math.round(Math.min(Math.max(value, 0), 255));
}
if (factor == 0)
return pixelArray;
const sCurve = (x) => {
return clip(255 / (1 + Math.exp(-factor * (x - 128) / 255)));
return 255 / (1 + Math.exp(-factor * (x - 128) / 255));
}
const newArray = [];
for (let i = 0; i < pixelArray.length; i++) {
if ((i+1) % 4 != 0)
newArray.push(sCurve(pixelArray[i]));
else
newArray.push(pixelArray[i]);
pixelArray[i] = sCurve(pixelArray[i]);
}

return newArray;
return pixelArray;
}

export default changeContrast;
2 changes: 2 additions & 0 deletions src/core/change_saturation.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import utils from "../utils.js";
* @returns {number[]} pixel array of the saturated or desaturated image.
*/
function changeSaturation(pixelArray, factor) {
if (factor == 0)
return pixelArray;
for (let i = 0; i < pixelArray.length; i += 4) {
const hsl = utils.rgbToHsl(pixelArray[i], pixelArray[i + 1], pixelArray[i + 2]);
hsl[1] = Math.max(0, Math.min(100, hsl[1] += factor));
Expand Down
4 changes: 2 additions & 2 deletions src/editpix.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,15 @@ EditPix.prototype.changeTemperature = (image, factor) => {

EditPix.prototype.changeSaturation = (image, factor) => {
if (factor < -100 || factor > 100)
throw new Error("Invalid contrast factor: must be a value between -100 and 100");
throw new Error("Invalid saturation factor: must be a value between -100 and 100");
const pixelArray = imageManager.getPixelArray(image);
return imageManager.convertToImage(changeSaturation(pixelArray, factor), image.naturalWidth, image.naturalHeight);

}

EditPix.prototype.changeBrightness = (image, factor) => {
if (factor < -100 || factor > 100)
throw new Error("Invalid contrast factor: must be a value between -100 and 100");
throw new Error("Invalid brightness factor: must be a value between -100 and 100");
const pixelArray = imageManager.getPixelArray(image);
return imageManager.convertToImage(changeBrightness(pixelArray, factor), image.naturalWidth, image.naturalHeight);
}
Expand Down
87 changes: 83 additions & 4 deletions test/core.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import changeTemperature from "../src/core/change_temperature.js";
import changeOpacity from "../src/core/change_opacity.js";
import changeShadows from "../src/core/change_shadows.js"
import higherColorContrast from "../src/core/higher_contrast.js";
import changeSaturation from "../src/core/change_saturation.js"
import changeBrightness from "../src/core/change_brightness.js";
import utils from "../src/utils.js";

describe('convertToBW function', () => {
test('converts pixel array to black and white correctly', () => {
Expand Down Expand Up @@ -67,7 +70,7 @@ describe('convertToGrayScale function', () => {
describe('optimizeContrast function', () => {
test('rescales input vector correctly', () => {
const pixelArray = [204, 33, 11, 33, 132, 4, 108, 13, 167, 50, 72, 141]; // RGBA values
const expectedOptimizedContrastArray = [255, 161, 0, 33, 0, 0, 255, 13, 124, 255, 160, 141]; //hand-computed rescaling
const expectedOptimizedContrastArray = [255, 161, 0, 33, 0, 0, 255, 13, 124, 255, 160, 141]; // hand-computed rescaling
expect(optimizeContrast(pixelArray)).toEqual(expectedOptimizedContrastArray);
});

Expand All @@ -78,11 +81,17 @@ describe('optimizeContrast function', () => {
});
});

describe('setContrast function', () => {
describe('changeContrast function', () => {
test('does not change anything if factor is 0', () => {
const pixelArray = [0, 0, 0, 11, 255, 255, 255, 23, 2, 128, 47, 71]; // RGBA values
const expectedContrastArray = [0, 0, 0, 11, 255, 255, 255, 23, 2, 128, 47, 71]; // untouched vector
expect(changeContrast(pixelArray, 0)).toEqual(expectedContrastArray);
});
test('rescales input vector correctly', () => {
const pixelArray = [0, 0, 0, 11, 255, 255, 255, 23, 2, 128, 47, 71]; // RGBA values
const expectedSetContrastArray = [2, 2, 2, 11, 253, 253, 253, 23, 2, 128, 10, 71]; //hand-computed rescaling
expect(changeContrast(pixelArray, 10)).toEqual(expectedSetContrastArray);
const expectedSetContrastArray = [2, 2, 2, 11, 253, 253, 253, 23, 2, 128, 10, 71]; // hand-computed rescaling
expect(changeContrast(pixelArray, 10).map((value) => Math.round(value))) // round values
.toEqual(expectedSetContrastArray);
});
})

Expand Down Expand Up @@ -160,6 +169,8 @@ describe('changeShadows', () => {
expect(testColor1[0]).toEqual(testColor2[0]);
expect(testColor1[1]).toEqual(testColor2[1]);
expect(testColor1[2]).toEqual(testColor2[2]);
});
});

describe('higherColorContrast', () => {
test('should return color with higher contrast for dark input color', () => {
Expand Down Expand Up @@ -188,4 +199,72 @@ describe('higherColorContrast', () => {

expect(result).toEqual(expectedResult);
});
});

describe('changeSaturation', () => {
test('should not change anything if factor is 0', () => {
const testColor1 = [173, 114, 255];
const testColor2 = [173, 114, 255];
changeSaturation(testColor1, 0);
expect(testColor1[0]).toEqual(testColor2[0]);
expect(testColor1[1]).toEqual(testColor2[1]);
expect(testColor1[2]).toEqual(testColor2[2]);
});
test('should change something if factor is not 0', () => {
const testColor1 = [173, 114, 234];
const testColor2 = [173, 114, 234];
changeSaturation(testColor1, 50);
expect(testColor1[0]).not.toEqual(testColor2[0]);
expect(testColor1[1]).not.toEqual(testColor2[1]);
expect(testColor1[2]).not.toEqual(testColor2[2]);
});
test('should increase saturation for positive factors', () => {
const testColor1 = [173, 114, 234];
const testColor2 = [173, 114, 234];
changeSaturation(testColor1, 50);
expect(utils.rgbToHsl(testColor2[0], testColor2[1], testColor2[2])[1])
.toBeLessThan(utils.rgbToHsl(testColor1[0], testColor1[1], testColor1[2])[1]);
});
test('should decrease saturation for negative factors', () => {
const testColor1 = [173, 114, 234];
const testColor2 = [173, 114, 234];
changeSaturation(testColor1, -50);
expect(utils.rgbToHsl(testColor2[0], testColor2[1], testColor2[2])[1])
.toBeGreaterThan(utils.rgbToHsl(testColor1[0], testColor1[1], testColor1[2])[1]);
});
});

describe('changeBrightness', () => {
test('should not change anything if factor is 0', () => {
const testColor1 = [173, 114, 255];
const testColor2 = [173, 114, 255];
changeBrightness(testColor1, 0);
expect(testColor1[0]).toEqual(testColor2[0]);
expect(testColor1[1]).toEqual(testColor2[1]);
expect(testColor1[2]).toEqual(testColor2[2]);
});
test('should change something if factor is not 0', () => {
const testColor1 = [173, 114, 234];
const testColor2 = [173, 114, 234];
changeBrightness(testColor1, 50);
expect(testColor1[0]).not.toEqual(testColor2[0]);
expect(testColor1[1]).not.toEqual(testColor2[1]);
expect(testColor1[2]).not.toEqual(testColor2[2]);
});
test('should clip to 0 at the bottom', () => {
const testColor1 = [11, 13, 7];
const testColor2 = [0, 0, 0];
changeBrightness(testColor1, -80);
expect(testColor1[0]).toEqual(testColor2[0]);
expect(testColor1[1]).toEqual(testColor2[1]);
expect(testColor1[2]).toEqual(testColor2[2]);
});
test('should clip to 255 at the top', () => {
const testColor1 = [243, 210, 251];
const testColor2 = [255, 255, 255];
changeBrightness(testColor1, 100);
expect(testColor1[0]).toEqual(testColor2[0]);
expect(testColor1[1]).toEqual(testColor2[1]);
expect(testColor1[2]).toEqual(testColor2[2]);
});
});
57 changes: 57 additions & 0 deletions test/editpix.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,61 @@ describe('EditPix changeShadows method', () => {
expect(e).toEqual(new Error("Invalid shadow factor: must be a value between -100 and 100"));
}
});
});

describe('EditPix changeContrast method', () => {
test('should reject lower out-of-range factors', () => {
try {
const editPix = new EditPix();
editPix.changeContrast([0, 234, 87], 150);
} catch (e) {
expect(e).toEqual(new Error("Invalid contrast factor: must be a value between -100 and 100"));
}
});
test('should reject upper out-of-range factors', () => {
try {
const editPix = new EditPix();
editPix.changeContrast([0, 234, 87], -123);
} catch (e) {
expect(e).toEqual(new Error("Invalid contrast factor: must be a value between -100 and 100"));
}
});
});

describe('EditPix changeSaturation method', () => {
test('should reject lower out-of-range factors', () => {
try {
const editPix = new EditPix();
editPix.changeSaturation([0, 234, 87], 150);
} catch (e) {
expect(e).toEqual(new Error("Invalid saturation factor: must be a value between -100 and 100"));
}
});
test('should reject upper out-of-range factors', () => {
try {
const editPix = new EditPix();
editPix.changeSaturation([0, 234, 87], -123);
} catch (e) {
expect(e).toEqual(new Error("Invalid saturation factor: must be a value between -100 and 100"));
}
});
});

describe('EditPix changeBrightness method', () => {
test('should reject lower out-of-range factors', () => {
try {
const editPix = new EditPix();
editPix.changeBrightness([0, 234, 87], 150);
} catch (e) {
expect(e).toEqual(new Error("Invalid brightness factor: must be a value between -100 and 100"));
}
});
test('should reject upper out-of-range factors', () => {
try {
const editPix = new EditPix();
editPix.changeBrightness([0, 234, 87], -123);
} catch (e) {
expect(e).toEqual(new Error("Invalid brightness factor: must be a value between -100 and 100"));
}
});
});

0 comments on commit 8093bd9

Please sign in to comment.