Skip to content

Commit

Permalink
Adding easier to use interface for blend module and different blend m…
Browse files Browse the repository at this point in the history
…odes (#1453)

* Bump data-uri-to-buffer from 2.0.1 to 3.0.0

Bumps [data-uri-to-buffer](https://github.com/TooTallNate/node-data-uri-to-buffer) from 2.0.1 to 3.0.0.
- [Release notes](https://github.com/TooTallNate/node-data-uri-to-buffer/releases)
- [Commits](TooTallNate/node-data-uri-to-buffer@2.0.1...3.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

* add blend modes

* fix toCliString test

* add docs link for blend modes

* fix crop module

* undo last commit

* minor change

* change default to custom

* add docs link

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Harsh Khandeparkar <34770591+HarshKhandeparkar@users.noreply.github.com>
Co-authored-by: Jeffrey Warren <jeff@unterbahn.com>
  • Loading branch information
4 people committed Jan 17, 2020
1 parent 1fa8c6b commit c22c6c7
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 15 deletions.
11 changes: 8 additions & 3 deletions docs/MODULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ This module is used for averaging all the pixels of the image.

## blend-module

This module is used for blending two images .
This module is used for blending two images. For More info read: _[wiki](https://en.wikipedia.org/wiki/Blend_modes)_

#### Usage

```js
Expand All @@ -88,8 +89,12 @@ This module is used for blending two images .
```

where `options` is an object with the following properties:
* offset: step of image with which current image is to be blended(Two steps back is -2, three steps back is -3 etc; default -2)
* func: function used to blend two images (default : function(r1, g1, b1, a1, r2, g2, b2, a2) { return [ r1, g2, b2, a2 ] })
* offset: step of image with which current image is to be blended(Two steps back is -2, three steps back is -3 etc; default -2)
* blendMode: Blending mode to use for blending two images by default it uses the given function
* func: function used to blend two images (default : function(r1, g1, b1, a1, r2, g2, b2, a2) { return [ r1, g2, b2, a2 ] })

[More info for different blend modes can be found here](http://docs.gimp.org/en/gimp-concepts-layer-modes.html)


## Blob Analysis

Expand Down
76 changes: 67 additions & 9 deletions src/modules/Blend/Module.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module.exports = function Blend(options, UI, util) {

options.func = options.blend || defaults.blend;
options.offset = options.offset || defaults.offset;
options.blendMode = options.blendMode || defaults.blendMode;

var output;

Expand All @@ -29,22 +30,79 @@ module.exports = function Blend(options, UI, util) {
callback();
}

// see http://docs.gimp.org/en/gimp-concepts-layer-modes.html for other blend modes

const multiply_mode = function (i, m) {
return ~~( (i * m) / 255 );
};
const divide_mode = function (i, m) {
return ~~( (256 * i) / (m + 1) );
};

const overlay_mode = function (i, m) {
return ~~( (i / 255) * (i + ((2 * m) / 255) * (255 - i)) );
};

const screen_mode = function (i, m) {
return ~~( 255 - ((255 - m) * (255 - i)) / 255 );
};

const sof_light_mode = function (i, m) {
var Rs = screen_mode(i, m);
return ~~( ((((255 - i) * m) + Rs) * i) / 255 );
};

const color_dodge = function (i, m) {
return ~~( (256 * i) / (255 - m + 1) );
};

const burn_mode = function (i, m) {
return ~~( 255 - (256 * (255 - i)) / (m + 1));
};

const grain_extract_mode = function (i, m) {
return ~~( i - m + 128 );
};

const grain_merge_mode = function (i, m) {
return ~~( i + m - 128 );
};


getPixels(priorStep.output.src, function(err, pixels) {
options.firstImagePixels = pixels;

// Convert to runnable code.
if (typeof options.func === 'string') eval('options.func = ' + options.func);

function changePixel(r2, g2, b2, a2, x, y) {
// blend!
let p = options.firstImagePixels;
return options.func(
r2, g2, b2, a2,
p.get(x, y, 0),
p.get(x, y, 1),
p.get(x, y, 2),
p.get(x, y, 3),
x,
y
);
let r1 = p.get(x, y, 0),
g1 = p.get(x, y, 1),
b1 = p.get(x, y, 2),
a1 = p.get(x, y, 3);

const blends = {
'Color Dodge': () => [color_dodge(r2, r1), color_dodge(g2, g1), color_dodge(b2, b1), 255],
'Multiply': () => [multiply_mode(r2, r1), multiply_mode(g2, g1), multiply_mode(b2, b1), multiply_mode(a2, a1)],
'Divide': () => [divide_mode(r2, r1), divide_mode(g2, g1), divide_mode(b2, b1), 255],
'Overlay': () => [overlay_mode(r2, r1), overlay_mode(g2, g1), overlay_mode(b2, b1), 255],
'Screen': () => [screen_mode(r2, r1), screen_mode(g2, g1), screen_mode(b2, b1), 255],
'Soft Light': () => [sof_light_mode(r2, r1), sof_light_mode(g2, g1), sof_light_mode(b2, b1), 255],
'Color Burn': () => [burn_mode(r2, r1), burn_mode(g2, g1), burn_mode(b2, b1), 255],
'Grain Extract': () => [grain_extract_mode(r2, r1), grain_extract_mode(g2, g1), grain_extract_mode(b2, b1), 255],
'Grain Merge': () => [grain_merge_mode(r2, r1), grain_merge_mode(g2, g1), grain_merge_mode(b2, b1), 255]
};

if(options.blendMode == 'custom')
return options.func(
r2, g2, b2, a2, r1, g1, b1, a1
);
else {
return blends[options.blendMode]();
}

}

function output(image, datauri, mimetype, wasmSuccess) {
Expand Down
21 changes: 19 additions & 2 deletions src/modules/Blend/info.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
{
"name": "blend",
"description": "Blend two chosen image steps with the given function. Defaults to using the red channel from image 1 and the green and blue and alpha channels of image 2. Easier to use interfaces coming soon!",
"description": "Blend two chosen image steps with the given function. Defaults to using the red channel from image 1 and the green and blue and alpha channels of image 2.",
"inputs": {
"offset": {
"type": "integer",
"desc": "Choose which image to blend the current image with. Two steps back is -2, three steps back is -3 etc.",
"default": -2
},
"blendMode": {
"type": "select",
"desc": "Name of the Blend Mode to use",
"default": "custom",
"values": [
"custom",
"Multiply",
"Divide",
"Overlay",
"Screen",
"Soft Light",
"Color Burn",
"Color Dodge",
"Grain Extract",
"Grain Merge"
]
},
"blend": {
"type": "string",
"desc": "Function to use to blend the two images.",
"default": "function(r1, g1, b1, a1, r2, g2, b2, a2, x, y) { return [ r2, g2, b2, a2 ] }"
}
},
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#blend-module"
"docs-link": "https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#blend-module"
}
2 changes: 1 addition & 1 deletion test/core/sequencer/image-sequencer.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ test('getStep(offset) returns the step at offset distance relative to current st
});

test('toCliString() returns the CLI command for the sequence', function(t) {
t.deepEqual(sequencer.toCliString(), 'sequencer -i [PATH] -s "channel channel channel channel invert brightness average brightness invert blend" -d \'{"channel":"green","brightness":"1","offset":-2}\'', 'works correctly');
t.deepEqual(sequencer.toCliString(), 'sequencer -i [PATH] -s "channel channel channel channel invert brightness average brightness invert blend" -d \'{"channel":"green","brightness":"1","offset":-2,"blendMode":"custom"}\'', 'works correctly');
t.end();
});

Expand Down

0 comments on commit c22c6c7

Please sign in to comment.