Skip to content

Instantly share code, notes, and snippets.

@reklis
Created October 7, 2010 00:07
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/614328 to your computer and use it in GitHub Desktop.
Save reklis/614328 to your computer and use it in GitHub Desktop.
broken 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>
<!-- http://code.google.com/p/explorercanvas/ -->
<!--[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 fetchBmp() {
$.get('http://localhost:3168/experimental/imgrender/beta.bmp', function (data) {
var bmp = new BitmapDecoder();
var texture = bmp.decode(data);
texture.draw($("#renderingTarget")[0]);
});
}
</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="btnFetch" type="button" value="Fetch BMP" onclick="fetchBmp()" /></div>
</form>
<canvas id="renderingTarget"></canvas>
</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);
var c = b.charCodeAt(0);
if (undefined == c) {
debugger; // yikes!
}
return c;
}
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);
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
}
// convert to RGBA from BGR
var textureData = [];
var x = 0;
var y = this.height;
while (!memStream.eof()) {
// first pixel
var b1 = memStream.readByte();
var g1 = memStream.readByte();
var r1 = memStream.readByte();
var a1 = 1; // bmp does not support alpha channel
var i = (x + y * this.width) * 4;
textureData[i++] = r1;
textureData[i++] = g1;
textureData[i++] = b1;
textureData[i++] = a1;
// bmp starts at bottom left pixel
if (x == this.width) {
x = 0;
--y;
} else {
++x;
}
// second pixel
var b2 = memStream.readByte();
var g2 = memStream.readByte();
var r2 = memStream.readByte();
var a2 = 1; // bmp does not support alpha channel
var i = (x + y * this.width) * 4;
textureData[i++] = r2;
textureData[i++] = g2;
textureData[i++] = b2;
textureData[i++] = a2;
// bmp starts at bottom left pixel
if (x == this.width) {
x = 0;
--y;
} else {
++x;
}
// padding
memStream.readByte();
memStream.readByte();
}
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