| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- /**
- * @author shaozilee
- *
- * Bmp format decoder,support 1bit 4bit 8bit 24bit bmp
- *
- */
- function BmpDecoder(buffer,is_with_alpha) {
- this.pos = 0;
- this.buffer = buffer;
- this.is_with_alpha = !!is_with_alpha;
- //Header should be BM
- if (this.buffer[0] != 66 && this.buffer[1] != 77) throw new Error("Invalid BMP File");
- this.pos += 2;
- this.parseHeader();
- this.parseBGR();
- }
- BmpDecoder.prototype.parseHeader = function() {
- var b = this.buffer;
- this.fileSize = (b[this.pos+3] << 24) | (b[this.pos+2] << 16) | (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 4;
- this.reserved = (b[this.pos+3] << 24) | (b[this.pos+2] << 16) | (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 4;
- this.offset = (b[this.pos+3] << 24) | (b[this.pos+2] << 16) | (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 4;
- this.headerSize = (b[this.pos+3] << 24) | (b[this.pos+2] << 16) | (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 4;
- this.width = (b[this.pos+3] << 24) | (b[this.pos+2] << 16) | (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 4;
- this.height = (b[this.pos+3] << 24) | (b[this.pos+2] << 16) | (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 4;
- this.planes = (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 2;
- this.bitPP = (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 2;
- this.compress = (b[this.pos+3] << 24) | (b[this.pos+2] << 16) | (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 4;
- this.rawSize = (b[this.pos+3] << 24) | (b[this.pos+2] << 16) | (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 4;
- this.hr = (b[this.pos+3] << 24) | (b[this.pos+2] << 16) | (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 4;
- this.vr = (b[this.pos+3] << 24) | (b[this.pos+2] << 16) | (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 4;
- this.colors = (b[this.pos+3] << 24) | (b[this.pos+2] << 16) | (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 4;
- this.importantColors = (b[this.pos+3] << 24) | (b[this.pos+2] << 16) | (b[this.pos+1] << 8) | b[this.pos];
- this.pos += 4;
- if(this.bitPP === 16 && this.is_with_alpha){
- this.bitPP = 15
- };
- if (this.bitPP < 15) {
- var len = this.colors === 0 ? 1 << this.bitPP : this.colors;
- this.palette = new Array(len);
- for (var i = 0; i < len; i++) {
- var blue = this.buffer[this.pos++];
- var green = this.buffer[this.pos++];
- var red = this.buffer[this.pos++];
- var quad = this.buffer[this.pos++];
- this.palette[i] = {
- red: red,
- green: green,
- blue: blue,
- quad: quad
- };
- }
- }
- }
- BmpDecoder.prototype.parseBGR = function() {
- this.pos = this.offset;
- try {
- var bitn = "bit" + this.bitPP;
-
- var canvas = document.createElement("canvas");
- var ctx = canvas.getContext("2d");
- var imageData = ctx.createImageData(this.width, this.height);
- this.imageData = imageData;
- this.data = imageData.data;
- this[bitn]();
- } catch (e) {
- console.log("bit decode error:" + e);
- }
- };
- BmpDecoder.prototype.bit1 = function() {
- var xlen = Math.ceil(this.width / 8);
- var mode = xlen%4;
- for (var y = this.height - 1; y >= 0; y--) {
- for (var x = 0; x < xlen; x++) {
- var b = this.buffer[this.pos++];
- var location = y * this.width * 4 + x*8*4;
- for (var i = 0; i < 8; i++) {
- if(x*8+i<this.width){
- var rgb = this.palette[((b>>(7-i))&0x1)];
- this.data[location+i*4] = rgb.red;
- this.data[location+i*4 + 1] = rgb.green;
- this.data[location+i*4 + 2] = rgb.blue;
- this.data[location+i*4 + 3] = 0xFF;
- }else{
- break;
- }
- }
- }
- if (mode != 0){
- this.pos+=(4 - mode);
- }
- }
- };
- BmpDecoder.prototype.bit4 = function() {
- var xlen = Math.ceil(this.width/2);
- var mode = xlen%4;
- for (var y = this.height - 1; y >= 0; y--) {
- for (var x = 0; x < xlen; x++) {
- var b = this.buffer[this.pos++];//this.buffer.readUInt8(this.pos++);
- var location = y * this.width * 4 + x*2*4;
- var before = b>>4;
- var after = b&0x0F;
- var rgb = this.palette[before];
- this.data[location] = rgb.red;
- this.data[location + 1] = rgb.green;
- this.data[location + 2] = rgb.blue;
- this.data[location + 3] = 0xFF;
- if(x*2+1>=this.width)break;
- rgb = this.palette[after];
- this.data[location+4] = rgb.red;
- this.data[location+4 + 1] = rgb.green;
- this.data[location+4 + 2] = rgb.blue;
- this.data[location+4 + 3] = 0xFF;
- }
- if (mode != 0){
- this.pos+=(4 - mode);
- }
- }
- };
- BmpDecoder.prototype.bit8 = function() {
- var mode = this.width%4;
- for (var y = this.height - 1; y >= 0; y--) {
- for (var x = 0; x < this.width; x++) {
- var b = this.buffer[this.pos++];
- var location = y * this.width * 4 + x*4;
- if(b < this.palette.length) {
- var rgb = this.palette[b];
- this.data[location] = rgb.red;
- this.data[location + 1] = rgb.green;
- this.data[location + 2] = rgb.blue;
- this.data[location + 3] = 0xFF;
- } else {
- this.data[location] = 0xFF;
- this.data[location + 1] = 0xFF;
- this.data[location + 2] = 0xFF;
- this.data[location + 3] = 0xFF;
- }
- }
- if (mode != 0){
- this.pos+=(4 - mode);
- }
- }
- };
- //Currently not used!
- BmpDecoder.prototype.bit15 = function() {
- //FIXED BUG, padding is based on number of bytes not the width
- var dif_w = (this.width * 2) % 4;
- if (dif_w != 0) {
- dif_w = 4 - dif_w;
- }
- var _11111 = parseInt("11111", 2),_1_5 = _11111;
- for (var y = this.height - 1; y >= 0; y--) {
- for (var x = 0; x < this.width; x++) {
- var B = (this.buffer[this.pos+1] << 8) | this.buffer[this.pos];
- this.pos+=2;
- var blue = (B & _1_5) / _1_5 * 255 | 0;
- var green = (B >> 5 & _1_5 ) / _1_5 * 255 | 0;
- var red = (B >> 10 & _1_5) / _1_5 * 255 | 0;
- var alpha = (B>>15)?0xFF:0x00;
- var location = y * this.width * 4 + x * 4;
- this.data[location] = red;
- this.data[location + 1] = green;
- this.data[location + 2] = blue;
- this.data[location + 3] = alpha;
- }
- //skip extra bytes
- this.pos += dif_w;
- }
- };
- //TODO support other RGB masks, e.g., RGB565
- BmpDecoder.prototype.bit16 = function() {
- //FIXED BUG, padding is based on number of bytes not the width
- var dif_w = (this.width * 2) % 4;
- if (dif_w != 0) {
- dif_w = 4 - dif_w;
- }
- var _11111 = parseInt("11111", 2),_1_5 = _11111;
- var _111111 = parseInt("111111", 2),_1_6 = _111111;
- for (var y = this.height - 1; y >= 0; y--) {
- for (var x = 0; x < this.width; x++) {
- var B = (this.buffer[this.pos+1] << 8) | this.buffer[this.pos];
- this.pos+=2;
- var alpha = 0xFF;
- var blue = (B & _1_5) / _1_5 * 255 | 0;
- var green = (B >> 5 & _1_5) / _1_5 * 255 | 0;
- var red = (B >> 10 & _1_5) / _1_5 * 255 | 0;
- var location = y * this.width * 4 + x * 4;
- this.data[location] = red;
- this.data[location + 1] = green;
- this.data[location + 2] = blue;
- this.data[location + 3] = alpha;
- }
- //skip extra bytes
- this.pos += dif_w;
- }
- };
- BmpDecoder.prototype.bit24 = function() {
- //when height > 0
- //FIXED BUG, padding is based on number of bytes not the width
- var dif_w = ((this.width * 3) % 4);
- if (dif_w != 0) {
- dif_w = 4 - dif_w;
- }
- for (var y = this.height - 1; y >= 0; y--) {
- for (var x = 0; x < this.width; x++) {
- var blue = this.buffer[this.pos++];
- var green = this.buffer[this.pos++];
- var red = this.buffer[this.pos++];
- var location = y * this.width * 4 + x * 4;
- this.data[location] = red;
- this.data[location + 1] = green;
- this.data[location + 2] = blue;
- this.data[location + 3] = 0xFF;
- }
- //skip extra bytes
- this.pos += dif_w;
- }
- };
- /**
- * add 32bit decode func
- * @author soubok
- */
- BmpDecoder.prototype.bit32 = function() {
- //when height > 0
- for (var y = this.height - 1; y >= 0; y--) {
- for (var x = 0; x < this.width; x++) {
- var blue = this.buffer[this.pos++];
- var green = this.buffer[this.pos++];
- var red = this.buffer[this.pos++];
- var alpha = this.buffer[this.pos++];
- var location = y * this.width * 4 + x * 4;
- //FIXED BUG alpha is the last byte in image data
- this.data[location] = red;
- this.data[location + 1] = green;
- this.data[location + 2] = blue;
- this.data[location + 3] = alpha;
- }
- //FIXED BUG no padding is needed for 32 bit images "the length of the rows IS a multiple of four bytes"
- }
- };
- BmpDecoder.prototype.getData = function() {
- return this.data;
- };
|