mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-20 22:39:50 -05:00
Revert to longer version of blend mode code as it is faster.
This commit is contained in:
parent
62f5204810
commit
9142c974c3
1 changed files with 64 additions and 50 deletions
|
@ -47,113 +47,127 @@ var BlendMode = {
|
|||
src = sourceContext.getImageData(0, 0,
|
||||
sourceCanvas.width, sourceCanvas.height).data,
|
||||
min = Math.min,
|
||||
sA, dA, rA, sM, dM, rM;
|
||||
sA, dA, rA, sM, dM, rM, sRA, sGA, sBA, dRA, dGA, dBA;
|
||||
|
||||
// TODO: Some blend modes seem broken at the moment, e.g.
|
||||
// dodge, burn
|
||||
// TODO: Some blend modes seem broken at the moment, e.g. dodge, burn
|
||||
var modes = {
|
||||
unsupported: function(i) {
|
||||
// Render checker pattern
|
||||
rA = 1;
|
||||
dst[i] = 255;
|
||||
dst[i + 1] = i % 8 == 0 ? 255 : 0;
|
||||
dst[i + 2] = i % 8 == 0 ? 0 : 255;
|
||||
},
|
||||
|
||||
normal: function(i) {
|
||||
var s = src[i] * sM, d = dst[i] * dM;
|
||||
dst[i] = (s + d * (1 - sA)) * rM;
|
||||
dst[i] = (sRA + dRA - dRA * sA) * rM;
|
||||
dst[i + 1] = (sGA + dGA - dGA * sA) * rM;
|
||||
dst[i + 2] = (sBA + dBA - dBA * sA) * rM;
|
||||
},
|
||||
|
||||
multiply: function(i) {
|
||||
var s = src[i] * sM, d = dst[i] * dM;
|
||||
dst[i] = (s * d + s * (1 - dA) + d * (1 - sA)) * rM;
|
||||
dst[i] = (sRA * dRA + sRA * (1 - dA) + dRA * (1 - sA)) * rM;
|
||||
dst[i + 1] = (sGA * dGA + sGA * (1 - dA) + dGA * (1 - sA)) * rM;
|
||||
dst[i + 2] = (sBA * dBA + sBA * (1 - dA) + dBA * (1 - sA)) * rM;
|
||||
},
|
||||
|
||||
screen: function(i) {
|
||||
var s = src[i] * sM, d = dst[i] * dM;
|
||||
dst[i] = (s * (1 - d) + d) * rM;
|
||||
dst[i] = (sRA + dRA - sRA * dRA) * rM;
|
||||
dst[i + 1] = (sGA + dGA - sGA * dGA) * rM;
|
||||
dst[i + 2] = (sBA + dBA - sBA * dBA) * rM;
|
||||
},
|
||||
|
||||
overlay: function(i) {
|
||||
// Correct for 100% opacity case; colors get clipped as opacity falls
|
||||
var s = src[i], d = dst[i] * dM; // src is unmultiplied
|
||||
dst[i] = d <= 0.5 ? (2 * s * d / dA) : 255 - (2 - 2 * d / dA) * (255 - s);
|
||||
dst[i] = dRA <= 0.5 ? (2 * src[i] * dRA / dA) : 255 - (2 - 2 * dRA / dA) * (255 - src[i]);
|
||||
dst[i + 1] = dGA <= 0.5 ? (2 * src[i + 1] * dGA / dA) : 255 - (2 - 2 * dGA / dA) * (255 - src[i + 1]);
|
||||
dst[i + 2] = dBA <= 0.5 ? (2 * src[i + 2] * dBA / dA) : 255 - (2 - 2 * dBA / dA) * (255 - src[i + 2]);
|
||||
},
|
||||
|
||||
// TODO: Missing: soft-light
|
||||
|
||||
'hard-light': function(i) {
|
||||
var s = src[i] * sM, d = dst[i]; // dst is unmultiplied
|
||||
dst[i] = s <= 0.5 ? (2 * d * s / dA) : 255 - (2 - 2 * s / sA) * (255 - d);
|
||||
dst[i] = sRA <= 0.5 ? (2 * dst[i] * sRA / dA) : 255 - (2 - 2 * sRA / sA) * (255 - dst[i]);
|
||||
dst[i + 1] = sGA <= 0.5 ? (2 * dst[i + 1] * sGA / dA) : 255 - (2 - 2 * sGA / sA) * (255 - dst[i + 1]);
|
||||
dst[i + 2] = sBA <= 0.5 ? (2 * dst[i + 2] * sBA / dA) : 255 - (2 - 2 * sBA / sA) * (255 - dst[i + 2]);
|
||||
},
|
||||
|
||||
'color-dodge': function(i) {
|
||||
var s = src[i], d = dst[i]; // both unmultiplied
|
||||
dst[i] = s == 255 && d * dM == 0 ? 255 : min(255, d / (255 - s)) * rM;
|
||||
dst[i] = src[i] == 255 && dRA == 0 ? 255 : min(255, dst[i] / (255 - src[i] )) * rM;
|
||||
dst[i + 1] = src[i + 1] == 255 && dGA == 0 ? 255 : min(255, dst[i + 1] / (255 - src[i + 1])) * rM;
|
||||
dst[i + 2] = src[i + 2] == 255 && dBA == 0 ? 255 : min(255, dst[i + 2] / (255 - src[i + 2])) * rM;
|
||||
},
|
||||
|
||||
'color-burn': function(i) {
|
||||
var s = src[i] * sM, d = dst[i] * dM;
|
||||
dst[i] = src[i] == 0 && d == 0 ? 0 : (1 - min(1, (1 - d) / s)) * rM;
|
||||
dst[i] = src[i] == 0 && dRA == 0 ? 0 : (1 - min(1, (1 - dRA) / sRA)) * rM;
|
||||
dst[i + 1] = src[i + 1] == 0 && dGA == 0 ? 0 : (1 - min(1, (1 - dGA) / sGA)) * rM;
|
||||
dst[i + 2] = src[i + 2] == 0 && dBA == 0 ? 0 : (1 - min(1, (1 - dBA) / sBA)) * rM;
|
||||
},
|
||||
|
||||
darken: function(i) {
|
||||
var s = src[i] * sM, d = dst[i] * dM;
|
||||
dst[i] = (s > d ? d : s) * rM;
|
||||
dst[i] = (sRA > dRA ? dRA : sRA) * rM;
|
||||
dst[i + 1] = (sGA > dGA ? dGA : sGA) * rM;
|
||||
dst[i + 2] = (sBA > dBA ? dBA : sBA) * rM;
|
||||
},
|
||||
|
||||
lighten: function(i) {
|
||||
var s = src[i] * sM, d = dst[i] * dM;
|
||||
dst[i] = (s < d ? d : s) * rM;
|
||||
dst[i] = (sRA < dRA ? dRA : sRA) * rM;
|
||||
dst[i + 1] = (sGA < dGA ? dGA : sGA) * rM;
|
||||
dst[i + 2] = (sBA < dBA ? dBA : sBA) * rM;
|
||||
},
|
||||
|
||||
difference: function(i) {
|
||||
var s = src[i] * sM, d = dst[i] * dM;
|
||||
dst[i] = (s + d - 2 * min(s * dA, d * sA)) * rM;
|
||||
dst[i] = (sRA + dRA - 2 * min(sRA * dA, dRA * sA)) * rM;
|
||||
dst[i + 1] = (sGA + dGA - 2 * min(sGA * dA, dGA * sA)) * rM;
|
||||
dst[i + 2] = (sBA + dBA - 2 * min(sBA * dA, dBA * sA)) * rM;
|
||||
},
|
||||
|
||||
exclusion: function(i) {
|
||||
var s = src[i] * sM, d = dst[i] * dM;
|
||||
dst[i] = (d + s - 2 * d * s) * rM;
|
||||
dst[i] = (dRA + sRA - 2 * dRA * sRA) * rM;
|
||||
dst[i + 1] = (dGA + sGA - 2 * dGA * sGA) * rM;
|
||||
dst[i + 2] = (dBA + sBA - 2 * dBA * sBA) * rM;
|
||||
},
|
||||
|
||||
// TODO: Missing: hue, saturation, color, luminosity
|
||||
|
||||
// TODO: Not in Illustrator. Remove these?
|
||||
// Not in Illustrator:
|
||||
|
||||
'src-in': function(i) {
|
||||
// Only differs from Photoshop in low - opacity areas
|
||||
dst[i] = sRA * dA * rM;
|
||||
rA = sA * dA;
|
||||
rM = 255 / rA;
|
||||
dst[i] = sRA * dA * rM;
|
||||
dst[i + 1] = sGA * dA * rM;
|
||||
dst[i + 2] = sBA * dA * rM;
|
||||
},
|
||||
|
||||
add: function(i) {
|
||||
// Photoshop doesn't simply add the alpha channels,
|
||||
// this might be correct wrt SVG 1.2
|
||||
dst[i] = min(sRA + dRA, 1) * rM;
|
||||
rA = min(1, sA + dA);
|
||||
rM = 255 / rA;
|
||||
dst[i] = min(sRA + dRA, 1) * rM;
|
||||
dst[i + 1] = min(sGA + dGA, 1) * rM;
|
||||
dst[i + 2] = min(sBA + dBA, 1) * rM;
|
||||
}
|
||||
};
|
||||
|
||||
var alphas = {
|
||||
'src-in': function(sA, dA) {
|
||||
return sA * dA;
|
||||
},
|
||||
|
||||
add: function(sA, dA) {
|
||||
return min(1, sA + dA);
|
||||
}
|
||||
};
|
||||
|
||||
var process = modes[blendMode];
|
||||
var alpha = alphas[blendMode];
|
||||
if (!process)
|
||||
return;
|
||||
// Divide opacity by 255 so it can be multiplied straight into pixel
|
||||
// values to get 0 .. 1 range.
|
||||
var process = modes[blendMode] || modes.unsupported;
|
||||
opacity /= 255;
|
||||
for (var i = 0, l = dst.length; i < l; i += 4) {
|
||||
sA = src[i + 3] * opacity;
|
||||
dA = dst[i + 3] / 255;
|
||||
// Result alpha:
|
||||
rA = alpha ? alpha(sA, dA) : sA + dA - sA * dA;
|
||||
rM = 255 / rA;
|
||||
// Multipliers:
|
||||
rA = sA + dA - sA * dA;
|
||||
sM = sA / 255;
|
||||
dM = dA / 255;
|
||||
sRA = src[i] * sM;
|
||||
dRA = dst[i] * dM;
|
||||
sGA = src[i + 1] * sM;
|
||||
dGA = dst[i + 1] * dM;
|
||||
sBA = src[i + 2] * sM;
|
||||
dBA = dst[i + 2] * dM;
|
||||
rM = 255 / rA;
|
||||
process(i);
|
||||
process(i + 1);
|
||||
process(i + 2);
|
||||
dst[i + 3] = rA * 255;
|
||||
}
|
||||
destContext.putImageData(dstData, offset.x, offset.y);
|
||||
|
|
Loading…
Reference in a new issue