Skip to content

Instantly share code, notes, and snippets.

@reklis
Created October 8, 2010 01:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reklis/616240 to your computer and use it in GitHub Desktop.
Save reklis/616240 to your computer and use it in GitHub Desktop.
working bmp decoding
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>fetch</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<script src="jquery.base64.min.js" type="text/javascript"></script>
<!--[if IE]><script src="excanvas.compiled.js" type="text/javascript"></script><![endif]-->
<script src="texture2d.js" type="text/javascript"></script>
<script type="text/javascript">
function makeNoise() {
var w = $("#txtWidth").val();
var h = $("#txtHeight").val();
var t = Texture2d.noise(w, h);
t.draw($("#renderingTarget")[0]);
}
function draw(data) {
// convert vb hex csv hackery to actual byte array
if (data.substring(0, 19) == "BinaryArrayToAscCSV") {
data = data.substring("BinaryArrayToAscCSV".length, data.length - 1).split(',');
}
var bmp = new BitmapDecoder();
var texture = bmp.decode(data, true);
texture.draw($("#renderingTarget")[0]);
}
function makeXMLHttpRequest() {
if (window.XMLHttpRequest) {
return new window.XMLHttpRequest;
}
else {
try {
return new ActiveXObject("MSXML2.XMLHTTP.3.0");
}
catch (ex) {
return null;
}
}
}
function fetchBmp() {
// $.get('http://localhost:3168/experimental/imgrender/beta.bmp', function (data) {
// draw(data);
// });
var oReq = makeXMLHttpRequest();
if (oReq != null) {
oReq.open("GET", "http://localhost:3168/experimental/imgrender/beta.bmp", true);
oReq.onreadystatechange = function () {
if (oReq.readyState == 4) {
if (oReq.status == 200) {
draw(oReq.responseBody);
} else {
alert("Error Code: " + oReq.status);
}
} else {
//alert("State Change: " + oReq.readyState);
}
}
oReq.send();
} else {
window.alert("AJAX (XMLHTTP) not supported.");
}
}
function fetchBase64() {
$.get('http://localhost:3168/experimental/imgrender/beta.bmp', function (data) {
var base64Data = $.base64.encode(data);
$('#my-image').attr('src', 'data:image/bmp;base64,' + base64Data);
});
}
</script>
<script type="text/vbscript">
Function BinaryArrayToAscCSV( aBytes )
Dim j, sOutput
sOutput = "BinaryArrayToAscCSV"
For j = 1 to LenB(aBytes)
sOutput= sOutput & AscB( MidB(aBytes,j,1) )
sOutput= sOutput & ","
Next
BinaryArrayToAscCSV = sOutput
End Function
Dim objXML
Function objXML_onreadystatechange()
If (objXML.readyState = 4) Then
If (objXML.status = 200) Then
Dim hexString
hexString = BinaryArrayToAscCSV(objXML.responseBody)
draw(hexString)
End If
End If
End Function
Function btnFetchVb_OnClick()
Set objXML = CreateObject("MSXML2.XMLHTTP.3.0")
objXML.Open "GET", "http://localhost:3168/experimental/imgrender/beta.bmp", True
objXML.OnReadyStateChange = GetRef("objXML_onreadystatechange")
objXML.Send
End Function
</script>
</head>
<body>
<form id="frm1">
<div>
<input id="txtWidth" type="text" value="100" />
<input id="txtHeight" type="text" value="100" />
</div>
<div>
<input id="btnNoise" type="button" value="Generate Noise" onclick="makeNoise()" />
</div>
<div>
<input id="btnBase64" type="button" value="Fetch Base64" onclick="fetchBase64()" />
<input id="btnFetch" type="button" value="Fetch BMP" onclick="fetchBmp()" />
<input id="btnFetchVb" type="button" value="Fetch with VB" />
</div>
</form>
<canvas id="renderingTarget"></canvas>
<img id="my-image" />
</body>
</html>
Math.randInRange = function (lbounds, ubounds) {
return (Math.random() * ubounds) + lbounds;
}
function Texture2d(d,w,h) {
this._data = d;
this._width = w;
this._height = h;
}
Texture2d.noise = function (width, height) {
var d = [];
for (var x = 0; x != width; ++x) {
for (var y = 0; y != height; ++y) {
var i = (x + y * width) * 4;
d[i + 0] = parseInt(Math.randInRange(0, 255)); // Red channel
d[i + 1] = parseInt(Math.randInRange(0, 255)); // Green channel
d[i + 2] = parseInt(Math.randInRange(0, 255)); // Blue channel
d[i + 3] = parseInt(Math.randInRange(0, 255)); // Alpha channel
}
}
return new Texture2d(d, width, height);
}
// the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
Texture2d.prototype.data = function (d) {
if (undefined != d) {
this._data = d;
}
return this._data;
}
Texture2d.prototype.width = function (w) {
if (undefined != w) {
this._width = w;
}
return this._width;
}
Texture2d.prototype.height = function (h) {
if (undefined != h) {
this._height = h;
}
return this._height;
}
Texture2d.prototype.draw = function (canvas) {
ctx = canvas.getContext("2d");
canvas.setAttribute('width', this.width());
canvas.setAttribute('height', this.height());
var w = this.width();
var h = this.height();
for (var x = 0; x < w; x++) {
for (var y = 0; y < h; y++) {
var i = (x + y * w) * 4;
var r = this._data[i + 0];
var g = this._data[i + 1];
var b = this._data[i + 2];
var a = this._data[i + 3];
ctx.fillStyle = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
ctx.fillRect(x, y, 1, 1);
}
}
}
function ByteStream(byteArray) {
if (byteArray == undefined) {
this._stream = [];
} else {
this._stream = byteArray;
}
this._position = 0;
}
ByteStream.prototype.position = function(p) {
if (undefined != p) {
this._position = p;
}
return this._position;
}
ByteStream.prototype.length = function() {
return this._stream.length;
}
ByteStream.prototype.eof = function() {
var l = this.length();
var p = this.position();
return (p >= l);
}
ByteStream.prototype.seek = function(origin, count) {
this.position(origin + count);
}
ByteStream.prototype.readByte = function () {
if (this.eof()) {
return undefined;
}
var p = this.position();
var b = this._stream[p];
this.position(p + 1);
// strings would be this way
// var c = b.charCodeAt(0);
// if (undefined == c) {
// debugger; // yikes!
// }
// return c;
// for byte arrays just return it
//return b;
// with hex CSV make sure we call parseInt
return parseInt(b);
}
ByteStream.prototype.readBytes = function (numBytes) {
var b = [];
for (var i = 0; i < numBytes; ++i) {
b[i] = this.readByte();
}
return b;
}
ByteStream.prototype.readInt16 = function () {
var b = this.readBytes(2);
var i = (b[1] << 8) + b[0];
return i;
}
ByteStream.prototype.readInt32 = function () {
var b = this.readBytes(4);
var i = (b[3] << 24) + (b[2] << 16) + (b[1] << 8) + b[0];
return i;
}
ByteStream.prototype.readString = function (length) {
var b = this.readBytes(length);
var s = "";
for (var i = 0; i < length; ++i) {
s += String.fromCharCode(b[i]);
}
return s;
}
function BitmapDecoder() {
}
BitmapDecoder.prototype.decode = function (byteArray) {
var memStream = new ByteStream(byteArray);
// based on http://www.dragonwins.com/bmp/bmpfileformat.htm
this.magic = memStream.readString(2);
this.fileSize = memStream.readInt32();
memStream.readInt16(); // unused
memStream.readInt16(); // unused
this.dataStart = memStream.readInt32();
this.headerLength = memStream.readInt32();
this.width = memStream.readInt32();
this.height = memStream.readInt32();
this.colorPlaneCount = memStream.readInt16();
this.bitsPerPixel = memStream.readInt16();
this.compressionMethod = memStream.readInt32();
this.rawSize = memStream.readInt32();
this.horizontalResolution = memStream.readInt32();
this.verticalResolution = memStream.readInt32();
this.numberOfPaletteColors = memStream.readInt32();
this.numberOfImportantColors = memStream.readInt32();
if (memStream.position() != this.dataStart) {
debugger;
return; // corrupt header
}
var textureData = [];
var padding = 4 - ((this.width * 3) % 4); // scanlines are padded to ensure DWORD size
for (var y = this.height; y > 0; --y) { // bmp scanlines go bottom up
for (var x = 0; x < this.width; ++x) {
var pixel = memStream.readBytes(3);
var i = (x + y * this.width) * 4;
textureData[i++] = pixel[0]; // r
textureData[i++] = pixel[1]; // g
textureData[i++] = pixel[2]; // b
textureData[i++] = 1; // a
if (x == this.width-1) {
memStream.readBytes(padding);
}
}
}
this.texture = new Texture2d(textureData, this.width, this.height);
return this.texture;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment