Created
November 12, 2013 16:56
-
-
Save senocular/7434502 to your computer and use it in GitHub Desktop.
Subset of AS BitmapData API in JS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function BitmapData(canvas){ | |
this.canvas = canvas; | |
this.width = this.canvas.width; | |
this.height = this.canvas.height; | |
this.context = this.canvas.getContext("2d"); | |
this.imageData = null; | |
// true if the canvas has been drawn into | |
// and the image data has not been updated | |
this.dataInvalid = false; | |
// true if the image data has changed | |
// and the image data has not been updated | |
this.canvasInvalid = false; | |
this.updateImageData(); | |
} | |
BitmapData.fromCanvas = function(canvas){ | |
return new BitmapData(canvas); | |
}; | |
BitmapData.fromImage = function(image){ | |
var canvas = document.createElement("canvas"); | |
canvas.width = image.width; | |
canvas.height = image.height; | |
var context = canvas.getContext("2d"); | |
context.drawImage(image, 0, 0); | |
return new BitmapData(canvas); | |
}; | |
BitmapData.fromSize = function(width, height){ | |
var canvas = document.createElement("canvas"); | |
canvas.width = width; | |
canvas.height = height; | |
return new BitmapData(canvas); | |
}; | |
Object.defineProperty(BitmapData.prototype, "rect", { | |
get: function(){ | |
return {x:0, y:0, width:this.width, height:this.height}; | |
} | |
}); | |
BitmapData.prototype.draw = function(source, matrix){ | |
if (source instanceof BitmapData){ | |
// make sure source canvas has all | |
// data changes drawn into it | |
if (source.canvasInvalid){ | |
source.updateCanvas(); | |
} | |
source = source.canvas; | |
} | |
// make sure this canvas has all | |
// data changes drawn into it | |
if (this.canvasInvalid){ | |
this.updateCanvas(); | |
} | |
if (matrix !== undefined){ | |
this.context.save(); | |
this.context.setTransform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty); | |
this.context.drawImage(source, 0, 0); | |
this.context.restore(); | |
}else{ | |
this.context.drawImage(source, 0, 0); | |
} | |
if (!this.dataInvalid){ | |
this.dataInvalid = true; | |
} | |
}; | |
BitmapData.prototype.updateImageData = function(){ | |
if (this.context){ | |
this.imageData = this.context.getImageData(0, 0, this.width, this.height); | |
this.dataInvalid = false; | |
} | |
}; | |
BitmapData.prototype.updateCanvas = function(){ | |
if (this.context){ | |
this.context.putImageData(this.imageData, 0, 0); | |
this.canvasInvalid = false; | |
} | |
}; | |
BitmapData.prototype.lock = function(){ | |
// noop | |
// locking inherent in the api | |
// with update methods needed | |
// to apply changes | |
}; | |
BitmapData.prototype.unlock = function(){ | |
// noop | |
}; | |
BitmapData.prototype.getPixel = function(x, y){ | |
// make sure data has all updates | |
// from canvas | |
if (this.dataInvalid){ | |
this.updateImageData(); | |
} | |
var i = 4 * (x + y * this.imageData.width); | |
var data = this.imageData.data; | |
var r = data[i]; | |
var g = data[i + 1]; | |
var b = data[i + 2]; | |
var a = data[i + 3]; | |
return (a << 24) | (r << 16) | (g << 8) | b; | |
}; | |
BitmapData.prototype.getPixels = function(rect){ | |
if (!rect){ | |
throw new ReferenceError("Parameter rect in getPixels must be non-null."); | |
} | |
// make sure data has all updates | |
// from canvas | |
if (this.dataInvalid){ | |
this.updateImageData(); | |
} | |
var bytes = new ByteArray(); | |
var data = this.imageData.data; | |
var xMax = this.imageData.width - 1; | |
var yMax = this.imageData.height - 1; | |
var rectRight = rect.x + rect.width; | |
var rectBottom = rect.y + rect.height; | |
for (var y=rect.y; y<rectBottom; y++){ | |
for (var x=rect.x; x<rectRight; x++){ | |
if (x < 0 || x > xMax || y < 0 || y > yMax){ | |
// is outside of image bounds, fill black | |
bytes.writeUnsignedInt(0); | |
}else{ | |
var i = 4 * (x + y * this.imageData.width); | |
// convert rgba to argb | |
var r = data[i ]; | |
var g = data[i + 1]; | |
var b = data[i + 2]; | |
var a = data[i + 3]; | |
var pixel = (a << 24) | (r << 16) | (g << 8) | b; | |
bytes.writeUnsignedInt(pixel); | |
} | |
} | |
} | |
bytes.position = 0; | |
return bytes; | |
}; | |
BitmapData.prototype.setPixels = function(rect, bytes){ | |
if (!rect){ | |
throw new ReferenceError("Parameter rect in getPixels must be non-null."); | |
} | |
if (!bytes){ | |
throw new ReferenceError("Parameter bytes in getPixels must be non-null."); | |
} | |
// make sure data has all updates | |
// from canvas | |
if (this.dataInvalid){ | |
this.updateImageData(); | |
} | |
var data = this.imageData.data; | |
var bytesPos = bytes.position; | |
bytes.position = 0; | |
var xMax = this.imageData.width - 1; | |
var yMax = this.imageData.height - 1; | |
var rectRight = rect.x + rect.width; | |
var rectBottom = rect.y + rect.height; | |
for (var y=rect.y; y<rectBottom; y++){ | |
if (y < 0){ | |
// skipping rows until visible | |
var skipRows = -y; | |
bytes.position += skipRows * 4 * rect.width; // 4 bytes per pixel uint | |
y = 0; | |
} | |
if (y > yMax){ | |
// no more setting to be done | |
break; | |
} | |
for (var x=rect.x; x<rectRight; x++){ | |
var skipCols; | |
if (x < 0){ | |
// skip cols up until when visible (0) | |
skipCols = -x; | |
bytes.position += 4 * skipCols; | |
x = 0; | |
} | |
if (x > xMax){ | |
// skipping rest of row, moving onto next | |
skipCols = rectRight - xMax; | |
bytes.position += 4 * skipCols; | |
break; | |
} | |
var i = 4 * (x + y * this.imageData.width); | |
var pixel = bytes.readUnsignedInt(); | |
// convert argb to rgba | |
var a = pixel >>> 24; | |
var r = (pixel >>> 16) & 0xFF; | |
var g = (pixel >>> 8) & 0xFF; | |
var b = pixel & 0xFF; | |
data[i ] = r; | |
data[i + 1] = g; | |
data[i + 2] = b; | |
data[i + 3] = a; | |
} | |
} | |
bytes.position = bytesPos; | |
if (!this.canvasInvalid){ | |
this.canvasInvalid = true; | |
} | |
}; | |
BitmapData.prototype.setPixel = function(x, y, pixel){ | |
// make sure data has all updates | |
// from canvas | |
if (this.dataInvalid){ | |
this.updateImageData(); | |
} | |
var i = 4 * (x + y * this.imageData.width); | |
var a = (pixel >>> 24) & 0xFF; | |
var r = (pixel >>> 16) & 0xFF; | |
var g = (pixel >>> 8) & 0xFF; | |
var b = pixel & 0xFF; | |
var data = this.imageData.data; | |
data[i ] = r; | |
data[i + 1] = g; | |
data[i + 2] = b; | |
data[i + 3] = a; | |
if (!this.canvasInvalid){ | |
this.canvasInvalid = true; | |
} | |
}; | |
function Matrix(a,b,c,d,tx,ty){ | |
this.a = a; | |
this.b = b; | |
this.c = c; | |
this.d = d; | |
this.tx = tx; | |
this.ty = ty; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment