Image transformations
by IceCreamYou
HTML
<div>
<div><strong>Input</strong></div>
<canvas id="input" width="300" height="70"></canvas>
</div>
<div>
<div><strong>Outputs</strong></div>
<div>
<span class="label">Averaging:</span>
<canvas id="output-avg" width="300" height="70"></canvas>
</div>
<div>
<span class="label">Luminance:</span>
<canvas id="output-lum" width="300" height="70"></canvas>
</div>
<div>
<span class="label">Gamma-corrected luminance:</span>
<canvas id="output-gamma-lum" width="300" height="70"></canvas>
</div>
<div>
<span class="label">Desaturation:</span>
<canvas id="output-des" width="300" height="70"></canvas>
</div>
<div>
<span class="label">Max decomposition:</span>
<canvas id="output-max" width="300" height="70"></canvas>
</div>
<div>
<span class="label">Min decomposition:</span>
<canvas id="output-min" width="300" height="70"></canvas>
</div>
<div>
<span class="label">Red channel:</span>
<canvas id="output-r" width="300" height="70"></canvas>
</div>
<div>
<span class="label">Green channel:</span>
<canvas id="output-g" width="300" height="70"></canvas>
</div>
<div>
<span class="label">Blue channel:</span>
<canvas id="output-b" width="300" height="70"></canvas>
</div>
<div>
<span class="label">Contrast:</span>
<canvas id="output-contrast" width="300" height="70"></canvas>
</div>
<div>
<span class="label">Contrast v2:</span>
<canvas id="output-contrast2" width="300" height="70"></canvas>
</div>
<div>
<span class="label">Brightness:</span>
<canvas id="output-brightness" width="300" height="70"></canvas>
</div>
<div>
<span class="label">Invert:</span>
<canvas id="output-invert" width="300" height="70"></canvas>
</div>
</div>
CSS
canvas {
border: 1px solid black;
}
.label {
display: inline-block;
width: 100px;
}
JavaScript
/**
* Gets a random integer between `lo` and `hi`.
*/
function getRandIntBetween(lo, hi) {
return Math.floor(Math.random() * (hi - lo + 1) + lo);
}
/**
* Logs a string to the DOM for debugging.
*/
function log(s) {
var d = document.createElement('div');
d.textContent = s;
document.body.appendChild(d);
}
/* Prepare an interesting input */
var canvas = document.getElementById('input'),
context = canvas.getContext('2d'),
w = canvas.width,
h = canvas.height,
i,
l,
avg;
// Only previously touched pixels are modifiable when writing imageData
context.fillRect(0, 0, w, h);
var imageData = context.getImageData(0, 0, w, h),
pixels = imageData.data;
// Set random colors. Picking random colors in RGB isn't very pretty,
// but it suffices for the purposes of this example.
for (i = 0, l = pixels.length; i < l; i += 4) {
do {
pixels[i] = getRandIntBetween(0, 255);
pixels[i + 1] = getRandIntBetween(0, 255);
pixels[i + 2] = getRandIntBetween(0, 255);
}
while (Math.abs(pixels[i] - pixels[i+1]) + Math.abs(pixels[i+1] - pixels[i+2]) + Math.abs(pixels[i+2] - pixels[i]) < 0);
}
var p = pixels.slice();
context.putImageData(imageData, 0, 0);
/* Averaging method */
for (i = 0, l = pixels.length; i < l; i += 4) {
avg = (p[i] + p[i+1] + p[i+2]) / 3;
pixels[i] = pixels[i+1] = pixels[i+2] = avg;
}
document.getElementById('output-avg').getContext('2d').putImageData(imageData, 0, 0);
/* Luminance method per the ITU-R BT.709 standard */
for (i = 0, l = pixels.length; i < l; i += 4) {
avg = p[i] * 0.2126 + p[i+1] * 0.7152 + p[i+2] * 0.0722;
pixels[i] = pixels[i+1] = pixels[i+2] = avg;
}
document.getElementById('output-lum').getContext('2d').putImageData(imageData, 0, 0);
/* Gamma-corrected luminance method for the sRGB color space */
function rgbToLinear(x) {
return x <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
}
for (i = 0, l = pixels.length; i < l; i += 4) {
avg =...