134 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| var fs = require('fs');
 | |
| 
 | |
| 
 | |
| function PixmapFromFile (path,options){
 | |
|   if(!options && typeof path == "object"){
 | |
|     this.options = path;
 | |
|     path = null;
 | |
|   }else{
 | |
|     this.options = options||{};
 | |
|   }
 | |
|   if(path){
 | |
|     return this.parse(fs.readFileSync(path, {encoding:"utf-8"}));
 | |
|   }
 | |
| }
 | |
| /**
 | |
|  *
 | |
|  * @param  {[type]}   data     utf-8 file data
 | |
|  * @param  {Function} callback optionnal callback.
 | |
|  */
 | |
| PixmapFromFile.prototype.parse = function (data) {
 | |
|   if(!/^\/\*\s*XPM\s*\*\/$/m.test(data)){
 | |
|     throw new Error("Not an XPM file");
 | |
|   }
 | |
|   data=data.replace(/\/\*[^\*]*\*\/\n/g,'');
 | |
|   var size = this.getSize(data);
 | |
|   var content = this.getArray(data,size);
 | |
|   var colors = this.mapColors(data,size);
 | |
|   size.data = this.toBuffer(colors,content,size);
 | |
|   return size;
 | |
| };
 | |
| PixmapFromFile.prototype.getSize = function(data){
 | |
|   var match = /{\n?"([0-9\s]*)\s?"/.exec(data);
 | |
|   if(!match){
 | |
|     console.log(data);
 | |
|     throw new Error("can't parse size infos");
 | |
|   }
 | |
|   var values = match[1].split(" ").map(function(i){return parseInt(i)});
 | |
|   return {width:values[0],height:values[1],count:values[2],length:values[3]}
 | |
| }
 | |
| 
 | |
| PixmapFromFile.prototype.getArray = function(data,size){
 | |
|   //var reg = new RegExp('"((?!(?:[0-9]+\\s?){4}).{'+size.length+'}(?!\\sc\\s).*)"',"g"); //Works also but much less simple
 | |
|   var reg = new RegExp('"(.{'+size.width*size.length+'})"',"g");
 | |
|   var res;
 | |
|   var rows = [];
 | |
|   while((res = reg.exec(data)) !== null){
 | |
|     rows.push(res[1]);
 | |
|   }
 | |
|   if(rows.length != size.height){
 | |
|     throw new Error("found : "+rows.length+" rows. Should have found :"+size.height+" rows.");
 | |
|   }
 | |
|   return rows;
 | |
| }
 | |
| // return RGBA color
 | |
| PixmapFromFile.prototype.mapColors = function(content,size){
 | |
|   var reg = new RegExp('"(.' + ((size.length > 1)? "{"+(size.length)+"}" : "") + ")\\s+c\\s+#?(None|black|white|gray100|[0-9a-fA-F]{6})\"","gm");
 | |
|   var res;
 | |
|   var colors = {};
 | |
|   while((res = reg.exec(content)) !== null){
 | |
|     if(res[2] === "None" || res[2] === "black"){
 | |
|       colors[res[1]] = "00000000"
 | |
|     } else if(res[2] === "white" || res[2] === "gray100"){
 | |
|       colors[res[1]] = "FFFFFFFF"
 | |
|     } else{
 | |
|         colors[res[1]] = res[2]+"FF";//RGBA
 | |
|     }
 | |
| 
 | |
|   }
 | |
|   if(Object.keys(colors).length != size.count){
 | |
|     throw new Error("found : "+Object.keys(colors).length+" colors. Should have found :"+size.count+" colors.");
 | |
|   }
 | |
|   return colors;
 | |
| }
 | |
| 
 | |
| PixmapFromFile.prototype.toBuffer = function (colors,content,size) {
 | |
|   var buf = new Buffer(size.width*size.height*4);
 | |
|   var offset = 0, byte,color;
 | |
|   var copy;
 | |
|   if( !this.options.format || this.options.format.toUpperCase() === "BGRA"){
 | |
|     copy = this.copyBGRABuffer;
 | |
|   }else if(this.options.format && this.options.format.toUpperCase() === "RGBA"){
 | |
|     copy = this.copyRGBABuffer;
 | |
|   }else{
 | |
|     throw new Error("invalid format option : ",this.options.format," valid values are BGRA (default) or RGBA")
 | |
|   }
 | |
|   content.forEach(function(row){
 | |
|     //console.log("parsing : ",row)
 | |
|     while(row && row.length >0){
 | |
|       var code = row.slice(0,size.length);
 | |
|       row = row.slice(size.length);
 | |
|       if(!colors[code]){
 | |
|         throw new Error("unknown color : ",code);
 | |
|       }
 | |
|       offset = copy(buf,offset,colors[code]);;
 | |
|     }
 | |
|   });
 | |
|   return buf;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Takes an array of rows. Each char/sequence represents a colored pixel
 | |
|  * @param  {[type]} content [description]
 | |
|  * @return {Buffer}         A 1d array of pixels in RGBA
 | |
|  */
 | |
| PixmapFromFile.prototype.copyBGRABuffer = function(buf, offset, color){
 | |
|   [4,2,0,6].forEach(function(i){
 | |
|     buf.writeUInt8(parseInt(color[i]+color[i+1],16),offset);
 | |
|     offset ++;
 | |
|   });
 | |
|   return offset;
 | |
| }
 | |
| PixmapFromFile.prototype.copyRGBABuffer = function(buf, offset, color){
 | |
|   buf.writeUInt32BE(parseInt(color,16),offset);
 | |
|   return offset+4;
 | |
| }
 | |
| PixmapFromFile.prototype.open = function(path,callback){
 | |
|   var self = this;
 | |
|    
 | |
|   if (callback) fs.readFile(path, {encoding:"utf-8"}, function(err,data){
 | |
|     if(err){
 | |
|       return callback(err);
 | |
|     }else{
 | |
|       callback(null,self.parse(data));
 | |
|     }
 | |
|   }); else {
 | |
|     var data = fs.readFileSync(path, {encoding:"utf-8"});
 | |
|     return self.parse(data);
 | |
|   }
 | |
| 
 | |
| 
 | |
| }
 | |
| 
 | |
| module.exports = PixmapFromFile;
 |