Skip to content
34 changes: 32 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ const invert = require('invert-color');

- **`color`** : `String|Array|Object`
Color in HEX string, RGB array or RGB object to be inverted.
- **`bw`** : `Boolean`
Optional. A boolean value indicating whether the output should be amplified to black (`#000000`) or white (`#ffffff`), according to the luminance of the original color.
- **`bw`** : `Boolean|Object`
Optional. A boolean value indicating whether the output should be amplified to black (`#000000`) or white (`#ffffff`), according to the luminance of the original color.
When it's an object, it should be shaped like `{ black: String?, white: String? }`,
where `black` and `white` are expressed as HEX strings and will be used as target
amplified values. When any of them is missing, the default black/white will be assumed.


```js
Expand All @@ -36,6 +39,9 @@ invert('#282b35') // —> #d7d4ca
// amplify to black or white
invert('#282b35', true) // —> #ffffff

// amplify to custom black or white color
invert('#282b35', { black: '#3a3a3a', white: '#fafafa' }) // —> #fafafa

// input color as RGB array or object
invert([69, 191, 189]) // —> #ba4042
invert({ r: 249, g: 119, b: 121 }) // —> #068886
Expand All @@ -59,6 +65,30 @@ invert.asRgbObject('#fff') // —> { r: 0, g: 0, b: 0 }

This is useful in case, you need to create contrast (i.e. background vs foreground, for better readability). The animation at the top is a demonstration.

## Contributing

Clone original project (or fork and clone that):

```sh
git clone https://github.com/onury/invert-color.git
```

Install dependencies:

```sh
npm install
```

There's nothing to build. Run tests:

```sh
npm test
```

Add (failing) tests into [test/unit.spec.js](test/unit.spec.js) file.
Add implementation.
Pass tests.
Refactor and repeat.

## License

Expand Down
19 changes: 13 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,33 @@ function getLuminance(c) {
return 0.2126 * a[0] + 0.7152 * a[1] + 0.0722 * a[2];
}

function invertToBW(color, asArr) {
function invertToBW(color, bw, asArr) {
const defaultColors = {
black: '#000000',
white: '#ffffff',
};
const bwColors = (bw === true)
? defaultColors
: Object.assign({}, defaultColors, bw);
return getLuminance(color) > BW_TRESHOLD
? (asArr ? [0, 0, 0] : '#000000')
: (asArr ? [255, 255, 255] : '#ffffff');
? (asArr ? hexToRGB(bwColors.black) : bwColors.black)
: (asArr ? hexToRGB(bwColors.white) : bwColors.white);
}

function invert(color, bw) {
color = toRGB(color);
if (bw) return invertToBW(color);
if (bw) return invertToBW(color, bw);
return '#' + color.map(c => padz((255 - c).toString(16))).join('');
}

invert.asRgbArray = (color, bw) => {
color = toRGB(color);
return bw ? invertToBW(color, true) : color.map(c => 255 - c);
return bw ? invertToBW(color, bw, true) : color.map(c => 255 - c);
};

invert.asRgbObject = (color, bw) => {
color = toRGB(color);
return toObj(bw ? invertToBW(color, true) : color.map(c => 255 - c));
return toObj(bw ? invertToBW(color, bw, true) : color.map(c => 255 - c));
};


Expand Down
57 changes: 57 additions & 0 deletions test/unit.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ describe('test: invert-color', () => {
const A_WHITE = [255, 255, 255];
const O_BLACK = { r: 0, g: 0, b: 0 };
const O_WHITE = { r: 255, g: 255, b: 255 };
const CUSTOM_BLACK = '#303030';
const CUSTOM_WHITE = '#fafafa';
const A_CUSTOM_BLACK = [48, 48, 48];
const O_CUSTOM_BLACK = { r: 48, g: 48, b: 48 };
const A_CUSTOM_WHITE = [250, 250, 250];
const O_CUSTOM_WHITE = { r: 250, g: 250, b: 250 };
const CUSTOM_BW_COLORS = {
black: CUSTOM_BLACK,
white: CUSTOM_WHITE,
};

it('should invert & match photoshop inverted colors', () => {
// ORIGINAL PHOTOSHOP
Expand Down Expand Up @@ -102,6 +112,27 @@ describe('test: invert-color', () => {
expect(invert('#fff', true)).toEqual('#000000');
});

it('should invert to custom black and white colors', () => {
expect(invert('#631746', CUSTOM_BW_COLORS)).toEqual(CUSTOM_WHITE);
expect(invert('#655c42', CUSTOM_BW_COLORS)).toEqual(CUSTOM_WHITE);
expect(invert('#166528', CUSTOM_BW_COLORS)).toEqual(CUSTOM_WHITE);
expect(invert('#4c2946', CUSTOM_BW_COLORS)).toEqual(CUSTOM_WHITE);
expect(invert('#002d26', CUSTOM_BW_COLORS)).toEqual(CUSTOM_WHITE);
expect(invert('#e71398', CUSTOM_BW_COLORS)).toEqual(CUSTOM_BLACK);
expect(invert('#3ab3af', CUSTOM_BW_COLORS)).toEqual(CUSTOM_BLACK);
expect(invert('#76ff98', CUSTOM_BW_COLORS)).toEqual(CUSTOM_BLACK);
expect(invert('#bbb962', CUSTOM_BW_COLORS)).toEqual(CUSTOM_BLACK);
expect(invert('#52838b', CUSTOM_BW_COLORS)).toEqual(CUSTOM_BLACK);
expect(invert('#000', CUSTOM_BW_COLORS)).toEqual(CUSTOM_WHITE);
expect(invert('#fff', CUSTOM_BW_COLORS)).toEqual(CUSTOM_BLACK);
});

it('should support true/false/object for black and white parameter', () => {
expect(invert('#201395', true)).toEqual('#ffffff');
expect(invert('#201395', false)).toEqual('#dfec6a');
expect(invert('#201395', CUSTOM_BW_COLORS)).toEqual(CUSTOM_WHITE);
});

it('should invert to/from array/object to B/W', () => {
// this test also checks for object mutation

Expand All @@ -128,6 +159,32 @@ describe('test: invert-color', () => {
expect(invert.asRgbObject(O_WHITE, true)).toEqual(O_BLACK);
});

it('should invert to/from array/object to custom B/W', () => {
// this test also checks for object mutation

// hex as array
expect(invert.asRgbArray('#631746', CUSTOM_BW_COLORS)).toEqual(A_CUSTOM_WHITE);
expect(invert.asRgbArray('#655c42', CUSTOM_BW_COLORS)).toEqual(A_CUSTOM_WHITE);
expect(invert.asRgbArray('#e71398', CUSTOM_BW_COLORS)).toEqual(A_CUSTOM_BLACK);

// hex as object
expect(invert.asRgbObject('#4c2946', CUSTOM_BW_COLORS)).toEqual(O_CUSTOM_WHITE);
expect(invert.asRgbObject('#002d26', CUSTOM_BW_COLORS)).toEqual(O_CUSTOM_WHITE);
expect(invert.asRgbObject('#76ff98', CUSTOM_BW_COLORS)).toEqual(O_CUSTOM_BLACK);

// array as array
expect(invert.asRgbArray(A_WHITE, CUSTOM_BW_COLORS)).toEqual(A_CUSTOM_BLACK);
expect(invert.asRgbArray(A_BLACK, CUSTOM_BW_COLORS)).toEqual(A_CUSTOM_WHITE);

// object as array
expect(invert.asRgbArray(O_BLACK, CUSTOM_BW_COLORS)).toEqual(A_CUSTOM_WHITE);
expect(invert.asRgbArray(O_WHITE, CUSTOM_BW_COLORS)).toEqual(A_CUSTOM_BLACK);

// object as object
expect(invert.asRgbObject(O_BLACK, CUSTOM_BW_COLORS)).toEqual(O_CUSTOM_WHITE);
expect(invert.asRgbObject(O_WHITE, CUSTOM_BW_COLORS)).toEqual(O_CUSTOM_BLACK);
});

it('should modulo exceeding RGB comps', () => {
expect(invert([300, 300, 300])).toEqual('#2d2d2d');
expect(invert({ r: -46, g: -46, b: -46 })).toEqual('#2d2d2d');
Expand Down