Pixel Perfect Scaling

by confile

HTML

<canvas id='cv' width=560 height=240></canvas>
<img id='testImage'...

JavaScript

polyFillPerfNow();

// Example
var cv = document.getElementById('cv');
var context = cv.getContext('2d');

context.ImageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.mozImageSmoothingEnabled = false;

context.fillStyle = '#080';
context.fillRect(0, 0, 600, 240);
var img = document.getElementById('testImage');

var st =0, ed = 0;
st = performance.now();

var scaledImage = downScaleImage(img, 0.3333);

ed = performance.now();

var pixelCount = img.width * img.height;
console.log('time taken for ' +( pixelCount) + ' pixels ' + (ed-st) + '.  ' 
                   + (1e3*(ed-st)/pixelCount) + ' ns per pixel '  );


context.fillStyle = '#000';
context.fillText('pixel perfect scale.', 320, 220);
context.drawImage(scaledImage, 287, 10);
context.drawImage(img, 20, 10, 247, 186);

context.fillText('canvas scale, less blurry / more noisy', 50, 220);

// --------------------------------

// scales the image by (float) scale < 1
// returns a canvas containing the scaled image.
function downScaleImage(img, scale) {
    var imgCV = document.createElement('canvas');
    imgCV.width = img.width;
    imgCV.height = img.height;
    var imgCtx = imgCV.getContext('2d');
    imgCtx.drawImage(img, 0, 0);
    return downScaleCanvas(imgCV, scale);
}

// scales the canvas by (float) scale < 1
// returns a new canvas containing the scaled image.
function downScaleCanvas(cv, scale) {
    if (!(scale < 1) || !(scale > 0)) {
//    	throw ('scale must be a positive number <1 ');
    	return cv;
    }
    var sqScale = scale * scale; // square scale =  area of a source pixel within target
    var sw = cv.width; // source image width
    var sh = cv.height; // source image height
    var tw = Math.ceil(sw * scale); // target image width
    var th = Math.ceil(sh * scale); // target image height
    var sx = 0, sy = 0, sIndex = 0; // source x,y, index within source array
    var tx = 0, ty = 0, yIndex = 0, tIndex = 0; // target x,y, x,y index within target array
 ...