├── canvas-image-worker.js ├── canvas-image.js ├── index.html ├── readme.md ├── style.css └── target.jpg /canvas-image-worker.js: -------------------------------------------------------------------------------- 1 | function draw (data) { 2 | 3 | if (data.processing.greyscaleMethod == "luminance") { 4 | 5 | greyscale_luminance(data.image.data); 6 | 7 | } else if (data.processing.greyscaleMethod == "average") { 8 | 9 | greyscale_average(data.image.data); 10 | 11 | } 12 | 13 | if (data.processing.ditherMethod == "atkinson") { 14 | 15 | dither_atkinson(data.image.data, data.image.width, (data.processing.greyscaleMethod == "")); 16 | 17 | } else if (data.processing.ditherMethod == "threshold") { 18 | 19 | dither_threshold(data.image.data, data.processing.ditherThreshold); 20 | } 21 | 22 | if (data.processing.replaceColours == true) { 23 | 24 | replace_colours(data.image.data, data.processing.replaceColourMap.black, data.processing.replaceColourMap.white); 25 | 26 | } 27 | 28 | return data; 29 | } 30 | 31 | // Convert image data to greyscale based on luminance. 32 | function greyscale_luminance (image) { 33 | 34 | for (var i = 0; i <= image.data.length; i += 4) { 35 | 36 | image.data[i] = image.data[i + 1] = image.data[i + 2] = parseInt(image.data[i] * 0.21 + image.data[i + 1] * 0.71 + image.data[i + 2] * 0.07, 10); 37 | 38 | } 39 | 40 | return image; 41 | } 42 | 43 | // Convert image data to greyscale based on average of R, G and B values. 44 | function greyscale_average (image) { 45 | 46 | for (var i = 0; i <= image.data.length; i += 4) { 47 | 48 | image.data[i] = image.data[i + 1] = image.data[i + 2] = parseInt((image.data[i] + image.data[i + 1] + image.data[i + 2]) / 3, 10); 49 | 50 | } 51 | 52 | return image; 53 | } 54 | 55 | // Apply Atkinson Dither to Image Data 56 | function dither_atkinson (image, imageWidth, drawColour) { 57 | skipPixels = 4; 58 | 59 | if (!drawColour) 60 | drawColour = false; 61 | 62 | if(drawColour == true) 63 | skipPixels = 1; 64 | 65 | imageLength = image.data.length; 66 | 67 | for (currentPixel = 0; currentPixel <= imageLength; currentPixel += skipPixels) { 68 | 69 | if (image.data[currentPixel] <= 128) { 70 | 71 | newPixelColour = 0; 72 | 73 | } else { 74 | 75 | newPixelColour = 255; 76 | 77 | } 78 | 79 | err = parseInt((image.data[currentPixel] - newPixelColour) / 8, 10); 80 | image.data[currentPixel] = newPixelColour; 81 | 82 | image.data[currentPixel + 4] += err; 83 | image.data[currentPixel + 8] += err; 84 | image.data[currentPixel + (4 * imageWidth) - 4] += err; 85 | image.data[currentPixel + (4 * imageWidth)] += err; 86 | image.data[currentPixel + (4 * imageWidth) + 4] += err; 87 | image.data[currentPixel + (8 * imageWidth)] += err; 88 | 89 | if (drawColour == false) 90 | image.data[currentPixel + 1] = image.data[currentPixel + 2] = image.data[currentPixel]; 91 | 92 | } 93 | 94 | return image.data; 95 | } 96 | 97 | function dither_threshold (image, threshold_value) { 98 | 99 | for (var i = 0; i <= image.data.length; i += 4) { 100 | 101 | image.data[i] = (image.data[i] > threshold_value) ? 255 : 0; 102 | image.data[i + 1] = (image.data[i + 1] > threshold_value) ? 255 : 0; 103 | image.data[i + 2] = (image.data[i + 2] > threshold_value) ? 255 : 0; 104 | 105 | } 106 | } 107 | 108 | function replace_colours (image, black, white) { 109 | 110 | for (var i = 0; i <= image.data.length; i += 4) { 111 | 112 | image.data[i] = (image.data[i] < 127) ? black.r : white.r; 113 | image.data[i + 1] = (image.data[i + 1] < 127) ? black.g : white.g; 114 | image.data[i + 2] = (image.data[i + 2] < 127) ? black.b : white.b; 115 | image.data[i + 3] = (((image.data[i]+image.data[i+1]+image.data[i+2])/3) < 127) ? black.a : white.a; 116 | 117 | } 118 | 119 | } 120 | 121 | self.addEventListener('message', function (e) { 122 | self.postMessage(draw(e.data)); 123 | }, false); -------------------------------------------------------------------------------- /canvas-image.js: -------------------------------------------------------------------------------- 1 | var imageDisplay, displayCanvas, displayContext, displayImage, displayImageData, originalImage; 2 | var worker = new Worker('canvas-image-worker.js'); 3 | var fileReader = new FileReader(); 4 | 5 | function draw () { 6 | 7 | displayImage = new Image(); 8 | displayImage.src = originalImage; 9 | 10 | displayCanvas.width = displayImage.width; 11 | displayCanvas.height = displayImage.height; 12 | 13 | displayContext = displayCanvas.getContext('2d'); 14 | 15 | displayContext.drawImage(displayImage, 0, 0); 16 | 17 | displayImageData = displayContext.getImageData(0,0,displayCanvas.width,displayCanvas.height); 18 | 19 | var tmpGreyscaleMethod = (document.getElementById('rdo_greyscale_luminance').checked) ? "luminance" : (document.getElementById('rdo_greyscale_average').checked) ? "average" : (document.getElementById('rdo_greyscale_disable').checked) ? "" : "luminance" ; 20 | var tmpDitherMethod = (document.getElementById('rdo_dither_atkinson').checked) ? "atkinson" : (document.getElementById('rdo_dither_threshold').checked) ? "threshold" : "atkinson" ; 21 | var tmpDitherThreshold = document.getElementById('threshold').value; 22 | var tmpReplaceColours = document.getElementById('chk_replace_colours').checked; 23 | var tmpReplaceBlack = { 24 | r: document.getElementById('rep_black_r').value, 25 | g: document.getElementById('rep_black_g').value, 26 | b: document.getElementById('rep_black_b').value, 27 | a: document.getElementById('rep_black_a').value 28 | } 29 | var tmpReplaceWhite = { 30 | r: document.getElementById('rep_white_r').value, 31 | g: document.getElementById('rep_white_g').value, 32 | b: document.getElementById('rep_white_b').value, 33 | a: document.getElementById('rep_white_a').value 34 | } 35 | 36 | if (window.console && window.console.time) { 37 | console.log("Starting Web Worker for image (" + displayCanvas.width + "x" + displayCanvas.height + ", Greyscale Method: " + tmpGreyscaleMethod + ", Dither Method: " + tmpDitherMethod + ")"); 38 | console.time("Web worker took"); 39 | } 40 | 41 | worker.postMessage( { 42 | image: { 43 | data: displayImageData, 44 | width: displayCanvas.width, 45 | height: displayCanvas.height 46 | }, 47 | processing: { 48 | greyscaleMethod: tmpGreyscaleMethod, 49 | ditherMethod: tmpDitherMethod, 50 | ditherThreshold: tmpDitherThreshold, 51 | replaceColours: tmpReplaceColours, 52 | replaceColourMap: { 53 | black: tmpReplaceBlack, 54 | white: tmpReplaceWhite 55 | } 56 | } 57 | }); 58 | 59 | } 60 | 61 | worker.addEventListener('message', function (e) { 62 | 63 | displayContext = displayCanvas.getContext('2d'); 64 | 65 | if (window.console && window.console.time) 66 | console.timeEnd("Web worker took"); 67 | 68 | displayContext.putImageData(e.data.image.data, 0, 0); 69 | 70 | if (document.getElementById('rdo_format_png').checked == true) { 71 | 72 | imageDisplay.src = displayCanvas.toDataURL("image/png"); 73 | 74 | } else if (document.getElementById('rdo_format_gif').checked == true) { 75 | 76 | imageDisplay.src = displayCanvas.toDataURL("image/gif"); 77 | 78 | } 79 | 80 | }, false); 81 | 82 | fileReader.onload = function (e) { 83 | originalImage = e.target.result; 84 | document.getElementById('displayImage').src = e.target.result; 85 | } 86 | 87 | function handleFileSelect (e) { 88 | var files = e.target.files; 89 | 90 | fileReader.readAsDataURL(e.target.files[0]); 91 | } 92 | 93 | function setup () { 94 | 95 | // Detect Canvas Support 96 | displayCanvas = document.createElement('canvas'); 97 | imageDisplay = document.getElementById('displayImage'); 98 | 99 | if (displayCanvas.getContext) { 100 | 101 | document.getElementById('renderbtn').onclick = function() { draw(); }; 102 | document.getElementById('fileSelect').addEventListener('change', handleFileSelect, false); 103 | originalImage = document.getElementById('displayImage').src; 104 | 105 | } else { 106 | 107 | alert("Hi there, you're using an older browser which doesn't support Canvas, so unfortunately I can't show you this demo. Sorry!"); 108 | 109 | } 110 | 111 | } 112 | 113 | window.onload = setup; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |