Path: blob/master/node_modules/bmp-js/lib/decoder.js
2591 views
/**1* @author shaozilee2*3* Bmp format decoder,support 1bit 4bit 8bit 24bit bmp4*5*/67function BmpDecoder(buffer,is_with_alpha) {8this.pos = 0;9this.buffer = buffer;10this.is_with_alpha = !!is_with_alpha;11this.bottom_up = true;12this.flag = this.buffer.toString("utf-8", 0, this.pos += 2);13if (this.flag != "BM") throw new Error("Invalid BMP File");14this.parseHeader();15this.parseRGBA();16}1718BmpDecoder.prototype.parseHeader = function() {19this.fileSize = this.buffer.readUInt32LE(this.pos);20this.pos += 4;21this.reserved = this.buffer.readUInt32LE(this.pos);22this.pos += 4;23this.offset = this.buffer.readUInt32LE(this.pos);24this.pos += 4;25this.headerSize = this.buffer.readUInt32LE(this.pos);26this.pos += 4;27this.width = this.buffer.readUInt32LE(this.pos);28this.pos += 4;29this.height = this.buffer.readInt32LE(this.pos);30this.pos += 4;31this.planes = this.buffer.readUInt16LE(this.pos);32this.pos += 2;33this.bitPP = this.buffer.readUInt16LE(this.pos);34this.pos += 2;35this.compress = this.buffer.readUInt32LE(this.pos);36this.pos += 4;37this.rawSize = this.buffer.readUInt32LE(this.pos);38this.pos += 4;39this.hr = this.buffer.readUInt32LE(this.pos);40this.pos += 4;41this.vr = this.buffer.readUInt32LE(this.pos);42this.pos += 4;43this.colors = this.buffer.readUInt32LE(this.pos);44this.pos += 4;45this.importantColors = this.buffer.readUInt32LE(this.pos);46this.pos += 4;4748if(this.bitPP === 16 && this.is_with_alpha){49this.bitPP = 1550}51if (this.bitPP < 15) {52var len = this.colors === 0 ? 1 << this.bitPP : this.colors;53this.palette = new Array(len);54for (var i = 0; i < len; i++) {55var blue = this.buffer.readUInt8(this.pos++);56var green = this.buffer.readUInt8(this.pos++);57var red = this.buffer.readUInt8(this.pos++);58var quad = this.buffer.readUInt8(this.pos++);59this.palette[i] = {60red: red,61green: green,62blue: blue,63quad: quad64};65}66}67if(this.height < 0) {68this.height *= -1;69this.bottom_up = false;70}7172}7374BmpDecoder.prototype.parseRGBA = function() {75var bitn = "bit" + this.bitPP;76var len = this.width * this.height * 4;77this.data = new Buffer(len);78this[bitn]();79};8081BmpDecoder.prototype.bit1 = function() {82var xlen = Math.ceil(this.width / 8);83var mode = xlen%4;84var y = this.height >= 0 ? this.height - 1 : -this.height85for (var y = this.height - 1; y >= 0; y--) {86var line = this.bottom_up ? y : this.height - 1 - y87for (var x = 0; x < xlen; x++) {88var b = this.buffer.readUInt8(this.pos++);89var location = line * this.width * 4 + x*8*4;90for (var i = 0; i < 8; i++) {91if(x*8+i<this.width){92var rgb = this.palette[((b>>(7-i))&0x1)];9394this.data[location+i*4] = 0;95this.data[location+i*4 + 1] = rgb.blue;96this.data[location+i*4 + 2] = rgb.green;97this.data[location+i*4 + 3] = rgb.red;9899}else{100break;101}102}103}104105if (mode != 0){106this.pos+=(4 - mode);107}108}109};110111BmpDecoder.prototype.bit4 = function() {112//RLE-4113if(this.compress == 2){114this.data.fill(0xff);115116var location = 0;117var lines = this.bottom_up?this.height-1:0;118var low_nibble = false;//for all count of pixel119120while(location<this.data.length){121var a = this.buffer.readUInt8(this.pos++);122var b = this.buffer.readUInt8(this.pos++);123//absolute mode124if(a == 0){125if(b == 0){//line end126if(this.bottom_up){127lines--;128}else{129lines++;130}131location = lines*this.width*4;132low_nibble = false;133continue;134}else if(b == 1){//image end135break;136}else if(b ==2){137//offset x,y138var x = this.buffer.readUInt8(this.pos++);139var y = this.buffer.readUInt8(this.pos++);140if(this.bottom_up){141lines-=y;142}else{143lines+=y;144}145146location +=(y*this.width*4+x*4);147}else{148var c = this.buffer.readUInt8(this.pos++);149for(var i=0;i<b;i++){150if (low_nibble) {151setPixelData.call(this, (c & 0x0f));152} else {153setPixelData.call(this, (c & 0xf0)>>4);154}155156if ((i & 1) && (i+1 < b)){157c = this.buffer.readUInt8(this.pos++);158}159160low_nibble = !low_nibble;161}162163if ((((b+1) >> 1) & 1 ) == 1){164this.pos++165}166}167168}else{//encoded mode169for (var i = 0; i < a; i++) {170if (low_nibble) {171setPixelData.call(this, (b & 0x0f));172} else {173setPixelData.call(this, (b & 0xf0)>>4);174}175low_nibble = !low_nibble;176}177}178179}180181182183184function setPixelData(rgbIndex){185var rgb = this.palette[rgbIndex];186this.data[location] = 0;187this.data[location + 1] = rgb.blue;188this.data[location + 2] = rgb.green;189this.data[location + 3] = rgb.red;190location+=4;191}192}else{193194var xlen = Math.ceil(this.width/2);195var mode = xlen%4;196for (var y = this.height - 1; y >= 0; y--) {197var line = this.bottom_up ? y : this.height - 1 - y198for (var x = 0; x < xlen; x++) {199var b = this.buffer.readUInt8(this.pos++);200var location = line * this.width * 4 + x*2*4;201202var before = b>>4;203var after = b&0x0F;204205var rgb = this.palette[before];206this.data[location] = 0;207this.data[location + 1] = rgb.blue;208this.data[location + 2] = rgb.green;209this.data[location + 3] = rgb.red;210211212if(x*2+1>=this.width)break;213214rgb = this.palette[after];215216this.data[location+4] = 0;217this.data[location+4 + 1] = rgb.blue;218this.data[location+4 + 2] = rgb.green;219this.data[location+4 + 3] = rgb.red;220221}222223if (mode != 0){224this.pos+=(4 - mode);225}226}227228}229230};231232BmpDecoder.prototype.bit8 = function() {233//RLE-8234if(this.compress == 1){235this.data.fill(0xff);236237var location = 0;238var lines = this.bottom_up?this.height-1:0;239240while(location<this.data.length){241var a = this.buffer.readUInt8(this.pos++);242var b = this.buffer.readUInt8(this.pos++);243//absolute mode244if(a == 0){245if(b == 0){//line end246if(this.bottom_up){247lines--;248}else{249lines++;250}251location = lines*this.width*4;252continue;253}else if(b == 1){//image end254break;255}else if(b ==2){256//offset x,y257var x = this.buffer.readUInt8(this.pos++);258var y = this.buffer.readUInt8(this.pos++);259if(this.bottom_up){260lines-=y;261}else{262lines+=y;263}264265location +=(y*this.width*4+x*4);266}else{267for(var i=0;i<b;i++){268var c = this.buffer.readUInt8(this.pos++);269setPixelData.call(this, c);270}271if(b&1 == 1){272this.pos++;273}274275}276277}else{//encoded mode278for (var i = 0; i < a; i++) {279setPixelData.call(this, b);280}281}282283}284285286287288function setPixelData(rgbIndex){289var rgb = this.palette[rgbIndex];290this.data[location] = 0;291this.data[location + 1] = rgb.blue;292this.data[location + 2] = rgb.green;293this.data[location + 3] = rgb.red;294location+=4;295}296}else {297var mode = this.width % 4;298for (var y = this.height - 1; y >= 0; y--) {299var line = this.bottom_up ? y : this.height - 1 - y300for (var x = 0; x < this.width; x++) {301var b = this.buffer.readUInt8(this.pos++);302var location = line * this.width * 4 + x * 4;303if (b < this.palette.length) {304var rgb = this.palette[b];305306this.data[location] = 0;307this.data[location + 1] = rgb.blue;308this.data[location + 2] = rgb.green;309this.data[location + 3] = rgb.red;310311} else {312this.data[location] = 0;313this.data[location + 1] = 0xFF;314this.data[location + 2] = 0xFF;315this.data[location + 3] = 0xFF;316}317}318if (mode != 0) {319this.pos += (4 - mode);320}321}322}323};324325BmpDecoder.prototype.bit15 = function() {326var dif_w =this.width % 3;327var _11111 = parseInt("11111", 2),_1_5 = _11111;328for (var y = this.height - 1; y >= 0; y--) {329var line = this.bottom_up ? y : this.height - 1 - y330for (var x = 0; x < this.width; x++) {331332var B = this.buffer.readUInt16LE(this.pos);333this.pos+=2;334var blue = (B & _1_5) / _1_5 * 255 | 0;335var green = (B >> 5 & _1_5 ) / _1_5 * 255 | 0;336var red = (B >> 10 & _1_5) / _1_5 * 255 | 0;337var alpha = (B>>15)?0xFF:0x00;338339var location = line * this.width * 4 + x * 4;340341this.data[location] = alpha;342this.data[location + 1] = blue;343this.data[location + 2] = green;344this.data[location + 3] = red;345}346//skip extra bytes347this.pos += dif_w;348}349};350351BmpDecoder.prototype.bit16 = function() {352var dif_w =(this.width % 2)*2;353//default xrgb555354this.maskRed = 0x7C00;355this.maskGreen = 0x3E0;356this.maskBlue =0x1F;357this.mask0 = 0;358359if(this.compress == 3){360this.maskRed = this.buffer.readUInt32LE(this.pos);361this.pos+=4;362this.maskGreen = this.buffer.readUInt32LE(this.pos);363this.pos+=4;364this.maskBlue = this.buffer.readUInt32LE(this.pos);365this.pos+=4;366this.mask0 = this.buffer.readUInt32LE(this.pos);367this.pos+=4;368}369370371var ns=[0,0,0];372for (var i=0;i<16;i++){373if ((this.maskRed>>i)&0x01) ns[0]++;374if ((this.maskGreen>>i)&0x01) ns[1]++;375if ((this.maskBlue>>i)&0x01) ns[2]++;376}377ns[1]+=ns[0]; ns[2]+=ns[1]; ns[0]=8-ns[0]; ns[1]-=8; ns[2]-=8;378379for (var y = this.height - 1; y >= 0; y--) {380var line = this.bottom_up ? y : this.height - 1 - y;381for (var x = 0; x < this.width; x++) {382383var B = this.buffer.readUInt16LE(this.pos);384this.pos+=2;385386var blue = (B&this.maskBlue)<<ns[0];387var green = (B&this.maskGreen)>>ns[1];388var red = (B&this.maskRed)>>ns[2];389390var location = line * this.width * 4 + x * 4;391392this.data[location] = 0;393this.data[location + 1] = blue;394this.data[location + 2] = green;395this.data[location + 3] = red;396}397//skip extra bytes398this.pos += dif_w;399}400};401402BmpDecoder.prototype.bit24 = function() {403for (var y = this.height - 1; y >= 0; y--) {404var line = this.bottom_up ? y : this.height - 1 - y405for (var x = 0; x < this.width; x++) {406//Little Endian rgb407var blue = this.buffer.readUInt8(this.pos++);408var green = this.buffer.readUInt8(this.pos++);409var red = this.buffer.readUInt8(this.pos++);410var location = line * this.width * 4 + x * 4;411this.data[location] = 0;412this.data[location + 1] = blue;413this.data[location + 2] = green;414this.data[location + 3] = red;415}416//skip extra bytes417this.pos += (this.width % 4);418}419420};421422/**423* add 32bit decode func424* @author soubok425*/426BmpDecoder.prototype.bit32 = function() {427//BI_BITFIELDS428if(this.compress == 3){429this.maskRed = this.buffer.readUInt32LE(this.pos);430this.pos+=4;431this.maskGreen = this.buffer.readUInt32LE(this.pos);432this.pos+=4;433this.maskBlue = this.buffer.readUInt32LE(this.pos);434this.pos+=4;435this.mask0 = this.buffer.readUInt32LE(this.pos);436this.pos+=4;437for (var y = this.height - 1; y >= 0; y--) {438var line = this.bottom_up ? y : this.height - 1 - y;439for (var x = 0; x < this.width; x++) {440//Little Endian rgba441var alpha = this.buffer.readUInt8(this.pos++);442var blue = this.buffer.readUInt8(this.pos++);443var green = this.buffer.readUInt8(this.pos++);444var red = this.buffer.readUInt8(this.pos++);445var location = line * this.width * 4 + x * 4;446this.data[location] = alpha;447this.data[location + 1] = blue;448this.data[location + 2] = green;449this.data[location + 3] = red;450}451}452453}else{454for (var y = this.height - 1; y >= 0; y--) {455var line = this.bottom_up ? y : this.height - 1 - y;456for (var x = 0; x < this.width; x++) {457//Little Endian argb458var blue = this.buffer.readUInt8(this.pos++);459var green = this.buffer.readUInt8(this.pos++);460var red = this.buffer.readUInt8(this.pos++);461var alpha = this.buffer.readUInt8(this.pos++);462var location = line * this.width * 4 + x * 4;463this.data[location] = alpha;464this.data[location + 1] = blue;465this.data[location + 2] = green;466this.data[location + 3] = red;467}468}469470}471472473474475};476477BmpDecoder.prototype.getData = function() {478return this.data;479};480481module.exports = function(bmpData) {482var decoder = new BmpDecoder(bmpData);483return decoder;484};485486487