(mode, img1, img2, dx, dy, alpha)
| 3228 | var HUE = "hue"; // Hue from the blend image, brightness and saturation from the base image. |
| 3229 | |
| 3230 | function blend(mode, img1, img2, dx, dy, alpha) { |
| 3231 | /* Applies the second image as a blend layer with the first image. |
| 3232 | * - dx: horizontal offset (in pixels) of the blend layer. |
| 3233 | * - dy: vertical offset (in pixels) of the blend layer. |
| 3234 | */ |
| 3235 | alpha = (alpha || alpha == 0)? alpha : 1; |
| 3236 | switch(mode) { |
| 3237 | case ADD : op = function(x, y) { return x + y; }; break; |
| 3238 | case SUBTRACT : op = function(x, y) { return x + y - 255; }; break; |
| 3239 | case LIGHTEN : op = function(x, y) { return Math.max(x, y); }; break; |
| 3240 | case DARKEN : op = function(x, y) { return Math.min(x, y); }; break; |
| 3241 | case MULTIPLY : op = function(x, y) { return x * y / 255; }; break; |
| 3242 | case SCREEN : op = function(x, y) { return 255 - (255-x) * (255-y) / 255; }; break; |
| 3243 | case OVERLAY : op = function(x, y, luminance) { }; |
| 3244 | case HARDLIGHT: op = function(x, y, luminance) { |
| 3245 | var a = 2 * x * y / 255; |
| 3246 | var b = 255 - 2 * (255-x) * (255-y) / 255; |
| 3247 | return (luminance < 0.45)? a : |
| 3248 | (luminance > 0.55)? b : |
| 3249 | geometry.lerp(a, b, (luminance - 0.45) * 255); }; break; |
| 3250 | default: |
| 3251 | op = function(x, y) { return 0; }; |
| 3252 | } |
| 3253 | function mix(p1, p2, op, luminance) { |
| 3254 | var p = [0,0,0,0]; |
| 3255 | var a = p2[3] / 255 * alpha; |
| 3256 | p[0] = geometry.lerp(p1[0], op(p1[0], p2[0], luminance), a); |
| 3257 | p[1] = geometry.lerp(p1[1], op(p1[1], p2[1], luminance), a); |
| 3258 | p[2] = geometry.lerp(p1[2], op(p1[2], p2[2], luminance), a); |
| 3259 | p[3] = geometry.lerp(p1[3], 255, a); |
| 3260 | return p; |
| 3261 | } |
| 3262 | // Some blend modes swap opaque blend (alpha=255) with base layer to mimic Photoshop. |
| 3263 | // Some blend modes use luminace (overlay & hard light). |
| 3264 | if (mode == ADD|| mode == SUBTRACT) { |
| 3265 | return composite(img1, img2, dx, dy, function(p1, p2) { |
| 3266 | return mix(p1, p2, op); |
| 3267 | }); |
| 3268 | } |
| 3269 | if (mode == LIGHTEN || mode == DARKEN || mode == MULTIPLY || mode == SCREEN) { |
| 3270 | return composite(img1, img2, dx, dy, function(p1, p2) { |
| 3271 | return (p2[3] == 255)? mix(p2, p1, op) : mix(p1, p2, op); |
| 3272 | }); |
| 3273 | } |
| 3274 | if (mode == OVERLAY) { |
| 3275 | return composite(img1, img2, dx, dy, function(p1, p2) { |
| 3276 | return mix(p1, p2, op, Math.dot(p1.slice(0, 3), LUMINANCE)); |
| 3277 | }); |
| 3278 | } |
| 3279 | if (mode == HARDLIGHT) { |
| 3280 | return composite(img1, img2, dx, dy, function(p1, p2) { |
| 3281 | return mix(p1, p2, op, Math.dot(p2.slice(0, 3), LUMINANCE)); |
| 3282 | }); |
| 3283 | } |
| 3284 | if (mode == HUE) { |
| 3285 | return composite(img1, img2, dx, dy, function(p1, p2) { |
| 3286 | var p, a=p1[3]; |
| 3287 | p1 = _rgb2hsb(p1[0], p1[1], p1[2]); |
no test coverage detected
searching dependent graphs…