Skip to content

Commit

Permalink
fix: gamma algorithm to handle negative value
Browse files Browse the repository at this point in the history
  • Loading branch information
tychota committed Dec 14, 2023
1 parent 8e87258 commit e68e4c2
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 14 deletions.
11 changes: 11 additions & 0 deletions src/gamut/rgb/cssInterpolation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ describe("gamut algorithm", () => {
expect(gammutMappedColor.g).toBeCloseTo(0.5);
expect(gammutMappedColor.b).toBeCloseTo(0.5);
});

it("should return the correct color when JND - E < epsilon (testing Sept Step 14.4.3.1)", () => {
// Given
const origin = new Color.RGB(0.7493801387258747, -0.37619585533746525, 0.45807639518528487);
// When
const gammutMappedColor = gammutAlgorithm.visitRGBColor(origin);
// Then
expect(gammutMappedColor.r).toBeCloseTo(0.5342294534717992);
expect(gammutMappedColor.g).toBeCloseTo(0);
expect(gammutMappedColor.b).toBeCloseTo(0.369135470389997672);
});
});

describe("clip", () => {
Expand Down
14 changes: 10 additions & 4 deletions src/utils/gamma.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
export function srgb_to_linear(srgb: number) {
if (srgb <= 0.04045) {
let srgb_sign = srgb < 0 ? -1 : 1;
let srgb_abs = srgb * srgb_sign;

if (srgb_abs <= 0.04045) {
return srgb / 12.92;
} else {
return Math.pow((srgb + 0.055) / 1.055, 2.4);
return srgb_sign * Math.pow((srgb_abs + 0.055) / 1.055, 2.4);
}
}

export function linear_to_srgb(linear: number) {
if (linear <= 0.0031308) {
let linear_sign = linear < 0 ? -1 : 1;
let linear_abs = linear * linear_sign;

if (linear_abs <= 0.0031308) {
return linear * 12.92;
} else {
return 1.055 * Math.pow(linear, 1 / 2.4) - 0.055;
return linear_sign * (1.055 * Math.pow(linear_abs, 1 / 2.4) - 0.055);
}
}
59 changes: 49 additions & 10 deletions tests/colors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, it, expect } from "bun:test";
import { Color } from "../src/colors";
import { ToRGBColorspaceVisitor } from "../src/colorspace/rgb";
import { ToOkLabColorspaceVisitor } from "../src/colorspace/oklab";
import { _LinearRGB, _LinearRgbColorspace } from "../src/colorspace/rgb/_linearRgb";

describe("colors", () => {
it("should be able to convert from OkLab to RGB", () => {
Expand All @@ -11,11 +12,7 @@ describe("colors", () => {
const rgbColorspace = new ToRGBColorspaceVisitor();
// Then
const rgb = rgbColorspace.visitOkLabColor(lab);
const expectedRgb = new Color.RGB(
0.5658744623277556,
0.28546849365275634,
0.37966673439558823
);
const expectedRgb = new Color.RGB(0.5658744654539968, 0.2854684929162757, 0.3796666882061938);
expect(rgb).toEqual(expectedRgb);
});
it("should be able to convert from RGB to OkLab", () => {
Expand All @@ -25,13 +22,55 @@ describe("colors", () => {
const okLabColorspace = new ToOkLabColorspaceVisitor();
const lab = okLabColorspace.visitRGBColor(rgb);
// Then
const expectedLab = new Color.OkLab(
0.5244890538202618,
0.09009675437758097,
-0.1307119570889005
);
const expectedLab = new Color.OkLab(0.5244890538202618, 0.09009675437758097, -0.1307119570889005);
expect(lab.l).toBeCloseTo(expectedLab.l);
expect(lab.a).toBeCloseTo(expectedLab.a);
expect(lab.b).toBeCloseTo(expectedLab.b);
});
});

describe("sRGB", () => {
it("Should handle negative value with symetrie - A1", () => {
// Given
const rgb = new Color.RGB(0.1, 0, 0);
// When
const lrgbColorspace = new _LinearRgbColorspace();
const lrgb = lrgbColorspace.visitRGBColor(rgb);
// Then
const expectedLrgb = new _LinearRGB(0.010022825574869039, 0, 0);
expect(lrgb).toEqual(expectedLrgb);
});

it("Should handle negative value with symetrie - A2", () => {
// Given
const rgb = new Color.RGB(-0.1, 0, 0);
// When
const lrgbColorspace = new _LinearRgbColorspace();
const lrgb = lrgbColorspace.visitRGBColor(rgb);
// Then
const expectedLrgb = new _LinearRGB(-0.010022825574869039, 0, 0);
expect(lrgb).toEqual(expectedLrgb);
});

it("Should handle negative value with symetrie - B1", () => {
// Given
const rgb = new Color.RGB(0.01, 0, 0);
// When
const lrgbColorspace = new _LinearRgbColorspace();
const lrgb = lrgbColorspace.visitRGBColor(rgb);
// Then
const expectedLrgb = new _LinearRGB(0.0007739938080495357, 0, 0);
expect(lrgb).toEqual(expectedLrgb);
});

it("Should handle negative value with symetrie -B2", () => {
// Given
const rgb = new Color.RGB(-0.01, 0, 0);
// When
const lrgbColorspace = new _LinearRgbColorspace();
const lrgb = lrgbColorspace.visitRGBColor(rgb);
// Then
const expectedLrgb = new _LinearRGB(-0.0007739938080495357, 0, 0);
expect(lrgb).toEqual(expectedLrgb);
});
});

0 comments on commit e68e4c2

Please sign in to comment.