var CanvasLoader = (function(){ var loader = new Loader (function(){}) function CanvasLoader (opt){ this.opt = defaults(opt, { rotate: true, }) this.canvas = document.createElement("canvas") this.ctx = this.canvas.getContext('2d') } CanvasLoader.prototype.load_image = function(url, cb){ loader.preloadImage(url, function(img){ var w = this.w = img.naturalWidth var h = this.h = img.naturalHeight this.img = img cb(img, w, h) }.bind(this)) } CanvasLoader.prototype.scale_image_data = function(opt){ var w, h if (opt.scale) { w = this.w * opt.scale h = this.h * opt.scale } if (opt.w) { w = opt.w h = opt.w * this.h / this.w } else if (opt.h) { w = opt.h * this.w / this.h h = opt.h } this.canvas.width = w this.canvas.height = h this.ctx.save() if (this.opt.rotate) { this.ctx.translate(w/2, h/2) this.ctx.rotate( Math.PI ) this.ctx.translate(-w/2, -h/2) } this.ctx.drawImage(this.img, 0, 0, w, h) this.ctx.restore() return this.ctx.getImageData(0, 0, w, h) } CanvasLoader.prototype.gray_image_data = function(opt){ var data = this.scale_image_data(opt) var pixels = data.data var len = data.width * data.height var gray_data = new Uint8Array( len ) var invert = this.opt.invert var gray, ii for (var i = 0; i < len; i++) { ii = i * 4 gray = (255 - (pixels[ii] + pixels[ii+1] + pixels[ii+2]) / 3 ) * (pixels[ii+3]/255) gray_data[i] = (invert) ? 255 - gray : gray } return { width: data.width, height: data.height, data: gray_data, } } // in: imagedata [r,g,b,a] and a palette // out: an array strided as [ palette offset, alpha ] CanvasLoader.prototype.palette_image_data = function(opt){ var data = this.scale_image_data(opt) var pixels = data.data var len = data.width * data.height var palette_data = new Uint8Array( len*2 ) var invert = this.opt.invert var palette = this.paletteToNumbers(opt.palette) var color, index, ii for (var i = 0; i < len; i++) { ii = i * 2 jj = i * 4 index = closest_to( palette, pixels.slice(jj, jj+3) ) palette_data[ii] = index palette_data[ii+1] = pixels[jj+3] } return { width: data.width, height: data.height, data: palette_data, } } CanvasLoader.prototype.paletteToStrings = function (palette){ if (typeof palette[0] === "string") return palette return palette.map(function(rgb){ return "rgb(" + rgb.join(",") + ")" }) } CanvasLoader.prototype.paletteToNumbers = function (palette){ if (typeof palette[0] !== "string") return palette var colors = palette.map(function(color){ if (color[0] == "#") return hexToRgb(color) return rgbStringToRgb(color) }).filter(function(color){ return !! color }).map(function(rgb){ return [rgb.r, rgb.g, rgb.b] }) return colors } function hexToRgb(hex) { // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; hex = hex.replace(shorthandRegex, function(m, r, g, b) { return r + r + g + g + b + b; }); var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; } function rgbStringToRgb(rgb) { var nums = rgb.replace(/rgba?\(/,"").replace(/\)/,"").split(",") return { r: nums[0], g: nums[1], b: nums[2] } } function closest_to(palette, pixel){ return palette.reduce(function(prev, curr, index) { var d = distance(pixel, curr) if (prev[0] > d) { prev[0] = d prev[1] = index } return prev }, [Infinity, -1])[1] } function distance(u, v){ if (! v) return Math.Infinity var r = u[0] - v[0] var g = u[1] - v[1] var b = u[2] - v[2] return Math.sqrt(r*r+g*g+b*b) } return CanvasLoader })()