├── examples ├── dog.jpg ├── image.js ├── halloween.js ├── tables.js └── formatting.js ├── lib ├── orientation.js ├── align.js ├── language.js ├── rgb.js ├── fonts.js ├── elements │ ├── text.js │ ├── element.js │ ├── group.js │ ├── image.js │ └── table.js ├── colors.js ├── rtf-utils.js ├── format.js └── rtf.js ├── .gitignore ├── README.md └── package.json /examples/dog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrowny/node-rtf/HEAD/examples/dog.jpg -------------------------------------------------------------------------------- /lib/orientation.js: -------------------------------------------------------------------------------- 1 | module.exports = Orientation = { 2 | PORTRAIT : false, 3 | LANDSCAPE : true 4 | }; -------------------------------------------------------------------------------- /lib/align.js: -------------------------------------------------------------------------------- 1 | module.exports = Align = { 2 | LEFT : "\\ql", 3 | RIGHT : "\\qr", 4 | CENTER : "\\qc", 5 | FULL : "\\qj" 6 | }; 7 | -------------------------------------------------------------------------------- /lib/language.js: -------------------------------------------------------------------------------- 1 | module.exports = Language = { 2 | ENG_US : "1033", 3 | SP_MX : "2058", 4 | FR : "1036", 5 | NONE : "1024" 6 | }; 7 | -------------------------------------------------------------------------------- /lib/rgb.js: -------------------------------------------------------------------------------- 1 | module.exports = RGB = function(red, green, blue){ 2 | this.red = red; 3 | this.green = green; 4 | this.blue = blue; 5 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | node_modules 15 | npm-debug.log -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | node-rtf 2 | ======== 3 | 4 | An RTF document creation library for node. Based on my old ActionScript3 implementation which has more documentation at http://code.google.com/p/rtflex/. -------------------------------------------------------------------------------- /lib/fonts.js: -------------------------------------------------------------------------------- 1 | module.exports = Fonts = { 2 | ARIAL : "Arial", 3 | COMIC_SANS : "Comic Sans MS", 4 | GEORGIA : "Georgia", 5 | IMPACT : "Impact", 6 | TAHOMA : "Tahoma", 7 | HELVETICA : "Helvetica", 8 | VERDANA : "Verdana", 9 | COURIER_NEW : "Courier New", 10 | PALATINO : "Palatino Linotype", 11 | TIMES_NEW_ROMAN : "Times New Roman" 12 | }; -------------------------------------------------------------------------------- /lib/elements/text.js: -------------------------------------------------------------------------------- 1 | var Element = require('./element'); 2 | 3 | module.exports = TextElement = function(text, format){ 4 | Element.apply(this, [format]); 5 | this.text=text; 6 | }; 7 | 8 | TextElement.subclass(Element); 9 | 10 | TextElement.prototype.getRTFCode = function(colorTable, fontTable, callback){ 11 | return callback(null, this.format.formatText(this.text, colorTable, fontTable)); 12 | }; -------------------------------------------------------------------------------- /lib/colors.js: -------------------------------------------------------------------------------- 1 | RGB = require("./rgb"); 2 | 3 | module.exports = Colors = 4 | { 5 | BLACK : new RGB(0,0,0), 6 | WHITE : new RGB(255,255,255), 7 | RED : new RGB(255,0,0), 8 | BLUE : new RGB(0,0,255), 9 | LIME : new RGB(191,255,0), 10 | YELLOW : new RGB(255,255,0), 11 | MAROON : new RGB(128,0,0), 12 | GREEN : new RGB(0,255,0), 13 | GRAY : new RGB(80,80,80), 14 | ORANGE : new RGB(255,127,0) 15 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "rtf", 3 | "version" : "0.0.4", 4 | "description" : "Assists with creating rich text documents.", 5 | "main" : "./lib/rtf.js", 6 | "author" : "Jonathan Rowny", 7 | "repository" : { 8 | "type" : "git", 9 | "url" : "https://github.com/jrowny/node-rtf.git" 10 | }, 11 | "keywords": [ 12 | "rtf", 13 | "rich text", 14 | "documents" 15 | ], 16 | "license" : "MIT", 17 | "dependencies": { 18 | "async" : "~0", 19 | "imageinfo" : "~1" 20 | } 21 | } -------------------------------------------------------------------------------- /examples/image.js: -------------------------------------------------------------------------------- 1 | var rtf = require('../lib/rtf'), 2 | fs = require('fs'), 3 | ImageElement = require('../lib/elements/image'); 4 | 5 | var myDoc = new rtf(); 6 | 7 | myDoc.elements.push(new ImageElement('examples/dog.jpg')); 8 | 9 | myDoc.createDocument( 10 | function(err, output){ 11 | //console.log(output); //that's a little much to output to the console 12 | fs.writeFile('image.rtf', output, function (err) { 13 | if (err) return console.log(err); 14 | }); 15 | } 16 | ); -------------------------------------------------------------------------------- /lib/elements/element.js: -------------------------------------------------------------------------------- 1 | //inspired by bobnice: http://stackoverflow.com/questions/1595611/how-to-properly-create-a-custom-object-in-javascript 2 | var Format = require('../format'); 3 | Function.prototype.subclass= function(base) { 4 | var c= Function.prototype.subclass.nonconstructor; 5 | c.prototype= base.prototype; 6 | this.prototype= new c(); 7 | }; 8 | Function.prototype.subclass.nonconstructor= function() {}; 9 | 10 | module.exports = Element = function(format){ 11 | if(format === undefined) format = new Format(); 12 | this.format = format; 13 | }; -------------------------------------------------------------------------------- /examples/halloween.js: -------------------------------------------------------------------------------- 1 | var rtf = require('../lib/rtf'), 2 | Format = require('../lib/format'), 3 | Colors = require('../lib/colors'), 4 | fs = require('fs'); 5 | var myDoc = new rtf(), 6 | format = new Format(); 7 | 8 | format.color = Colors.ORANGE; 9 | myDoc.writeText("Happy Halloween", format); 10 | myDoc.addPage(); 11 | myDoc.addLine(); 12 | myDoc.addTab(); 13 | myDoc.writeText("Trick or treat!"); 14 | myDoc.createDocument( 15 | function(err, output){ 16 | console.log(output); 17 | fs.writeFile('halloween.rtf', output, function (err) { 18 | if (err) return console.log(err); 19 | }); 20 | } 21 | ); -------------------------------------------------------------------------------- /examples/tables.js: -------------------------------------------------------------------------------- 1 | var rtf = require('../lib/rtf'), 2 | TableElement = require('../lib/elements/table'), 3 | fs = require('fs'); 4 | var myDoc = new rtf(), 5 | table = new TableElement(), 6 | table2 = new TableElement(); 7 | 8 | //add rows 9 | table.addRow(["I'm a table row", "with two columns"]); 10 | table.addRow(["This is the second row", "and the second column"]); 11 | 12 | myDoc.addTable(table); 13 | 14 | //You can manually set the data *overwrites any data in the table 15 | table2.setData([ 16 | ["Name", "Price", "Sold"], 17 | ["Rubber Ducky", "$10.00", "22"], 18 | ["Widget", "$99.99", "42"], 19 | ["Sproket", "$5.24", "11"] 20 | ]); 21 | //adding a row to an existing data set 22 | table2.addRow(["Banana", "$0.12", "1"]); 23 | 24 | myDoc.createDocument( 25 | function(err, output){ 26 | console.log(output); 27 | fs.writeFile('table-sample.rtf', output, function (err) { 28 | if (err) return console.log(err); 29 | }); 30 | } 31 | ); -------------------------------------------------------------------------------- /lib/elements/group.js: -------------------------------------------------------------------------------- 1 | //thanks DTrejo for help using async 2 | var Utils = require("../rtf-utils"), 3 | Element = require('./element'), 4 | async = require('async'); 5 | 6 | module.exports = GroupElement = function(name, format) { 7 | Element.apply(this, [format]); 8 | this.elements = []; 9 | this.name = name; 10 | }; 11 | 12 | GroupElement.subclass(Element); 13 | 14 | GroupElement.prototype.addElement = function(element){ 15 | this.elements.push(element); 16 | }; 17 | 18 | GroupElement.prototype.getRTFCode = function(colorTable, fontTable, callback){ 19 | var tasks = []; 20 | var rtf = ""; 21 | this.elements.forEach(function(el, i) { 22 | if (el instanceof Element){ 23 | tasks.push(function(cb) { el.getRTFCode(colorTable, fontTable, cb); }); 24 | } else { 25 | tasks.push(function(cb) { cb(null, Utils.getRTFSafeText(el)); }); 26 | } 27 | }); 28 | 29 | return async.parallel(tasks, function(err, results) { 30 | results.forEach(function(result) { 31 | rtf += result; 32 | }); 33 | //formats the whole group 34 | rtf = format.formatText(rtf, colorTable, fontTable, false); 35 | return callback(null, rtf); 36 | }); 37 | }; -------------------------------------------------------------------------------- /lib/elements/image.js: -------------------------------------------------------------------------------- 1 | var Element = require('./element'), 2 | fs = require('fs'), 3 | imageinfo = require('imageinfo'); 4 | 5 | module.exports = ImageElement = function(path){ 6 | Element.apply(this, arguments); 7 | this.path=path; 8 | this.dpi=300; 9 | }; 10 | 11 | ImageElement.subclass(Element); 12 | 13 | ImageElement.prototype.getRTFCode = function(colorTable, fontTable, callback){ 14 | var self = this; 15 | 16 | //read image file 17 | return fs.readFile(this.path, function(err, buffer){ 18 | 19 | if(err) throw err; 20 | 21 | //get image information and calculate twips based on DPI 22 | var info = imageinfo(buffer); 23 | var twipRatio = ((72/self.dpi) * 20); 24 | var twipWidth = Math.round(info.width * twipRatio), 25 | twipHeight = Math.round(info.height * twipRatio); 26 | 27 | //output image information 28 | var output = "{\\pict\\pngblip\\picw" + info.width + "\\pich" + info.height + 29 | "\\picwgoal" + twipWidth + "\\pichgoal" + twipHeight + " "; 30 | 31 | //output buffer to base16 (hex) and ensure prefixed 0 if single digit 32 | var bufSize = buffer.length; 33 | for(var i = 0; i < bufSize; i++){ 34 | var hex = buffer[i].toString(16); 35 | output += (hex.length === 2) ? hex : "0" + hex; 36 | } 37 | 38 | output += "}"; 39 | return callback(null, output); 40 | }); 41 | }; -------------------------------------------------------------------------------- /examples/formatting.js: -------------------------------------------------------------------------------- 1 | var rtf = require('../lib/rtf'), 2 | Format = require('../lib/format'), 3 | Colors = require('../lib/colors'), 4 | RGB = require('../lib/rgb'), 5 | fs = require('fs'); 6 | var myDoc = new rtf(), 7 | red_underline = new Format(), 8 | blue_strike = new Format(), 9 | green_bold = new Format(), 10 | maroon_super = new Format(), 11 | gray_sub = new Format(), 12 | lime_indent = new Format(), 13 | custom_blue = new Format(); 14 | 15 | red_underline.color = Colors.RED; 16 | red_underline.underline = true; 17 | red_underline.fontSize = 20; 18 | myDoc.writeText("Red underlined", red_underline); 19 | myDoc.addLine(); 20 | blue_strike.color = Colors.RED; 21 | blue_strike.strike = true; 22 | myDoc.writeText("Strikeout Blue", blue_strike); 23 | myDoc.addLine(); 24 | green_bold.color = Colors.GREEN; 25 | green_bold.bold = true; 26 | myDoc.writeText("Bold Green", green_bold); 27 | myDoc.addLine(); 28 | maroon_super.color = Colors.MAROON; 29 | maroon_super.superScript = true; 30 | myDoc.writeText("Superscripted Maroon", maroon_super); 31 | myDoc.addLine(); 32 | gray_sub.color = Colors.GRAY; 33 | gray_sub.subScript = true; 34 | myDoc.writeText("Subscripted Gray", gray_sub); 35 | myDoc.addLine(); 36 | lime_indent.color = Colors.LIME; 37 | lime_indent.backgroundColor = Colors.Gray; 38 | lime_indent.leftIndent = 50; 39 | myDoc.writeText("Left indented Lime", lime_indent); 40 | myDoc.addLine(); 41 | custom_blue.color = new RGB(3, 80, 150); 42 | myDoc.writeText("Custom blue color", custom_blue); 43 | 44 | myDoc.createDocument( 45 | function(err, output){ 46 | console.log(output); 47 | fs.writeFile('formatting.rtf', output, function (err) { 48 | if (err) return console.log(err); 49 | }); 50 | } 51 | ); 52 | -------------------------------------------------------------------------------- /lib/rtf-utils.js: -------------------------------------------------------------------------------- 1 | var Fonts = require('./fonts'); 2 | /** 3 | * ReplaceAll by Fagner Brack (MIT Licensed) 4 | * Replaces all occurrences of a substring in a string 5 | */ 6 | String.prototype.replaceAll = function(token, newToken, ignoreCase) { 7 | var str = this.toString(), i = -1, _token; 8 | if(typeof token === "string") { 9 | if(ignoreCase === true) { 10 | _token = token.toLowerCase(); 11 | while((i = str.toLowerCase().indexOf( token, i >= 0? i + newToken.length : 0 )) !== -1 ) { 12 | str = str.substring(0, i) 13 | .concat(newToken) 14 | .concat(str.substring(i + token.length)); 15 | } 16 | } else { 17 | return this.split(token).join(newToken); 18 | } 19 | } 20 | return str; 21 | }; 22 | 23 | /** 24 | * makes text safe for RTF by escaping characters and it also converts linebreaks 25 | * also checks to see if safetext should be overridden by non-elements like "\line" 26 | */ 27 | function getRTFSafeText(text){ 28 | //if text is overridden not to be safe 29 | if(typeof text === "object" && text.hasOwnProperty("safe") && !text.safe){ 30 | return text.text; 31 | } 32 | //this could probably all be replaced by a bit of regex 33 | return text.replaceAll('\\','\\\\') 34 | .replaceAll('{','\\{') 35 | .replaceAll('}','\\}') 36 | .replaceAll('~','\\~') 37 | .replaceAll('-','\\-') 38 | .replaceAll('_','\\_') 39 | //turns line breaks into \line commands 40 | .replaceAll('\n\r',' \\line ') 41 | .replaceAll('\n',' \\line ') 42 | .replaceAll('\r',' \\line '); 43 | } 44 | 45 | //gneerates a color table 46 | function createColorTable(colorTable) { 47 | var table = "", 48 | c; 49 | table+="{\\colortbl;"; 50 | for(c=0; c < colorTable.length; c++) { 51 | rgb = colorTable[c]; 52 | table+="\\red" + rgb.red + "\\green" + rgb.green + "\\blue" + rgb.blue + ";"; 53 | } 54 | table+="}"; 55 | return table; 56 | } 57 | 58 | //gneerates a font table 59 | function createFontTable(fontTable) { 60 | var table = "", 61 | f; 62 | table+="{\\fonttbl;"; 63 | if(fontTable.length === 0) { 64 | table+="{\\f0 " + Fonts.ARIAL + "}"; //if no fonts are defined, use arial 65 | } else { 66 | for(f=0;f max) max = target[i].length; 10 | } 11 | return max; 12 | } 13 | 14 | module.exports = TableElement = function(){ 15 | Element.apply(this, arguments); 16 | this._data = []; 17 | this._rows = 0; 18 | this._cols = 0; 19 | }; 20 | 21 | TableElement.subclass(Element); 22 | 23 | TableElement.prototype.addRow = function(row){ 24 | this._data.push(row); 25 | }; 26 | 27 | TableElement.prototype.setData = function(data){ 28 | this._data = data; 29 | }; 30 | 31 | function rowTask(row, numCols, colorTable, fontTable){ 32 | return function(rowcb){ 33 | var rowTasks = []; 34 | //generate tasks for each column 35 | row.forEach(function(el, i) { 36 | if (el instanceof Element){ 37 | rowTasks.push(function(cb) { el.getRTFCode(colorTable, fontTable, cb); }); 38 | } else { 39 | rowTasks.push(function(cb) { cb(null, Utils.getRTFSafeText(el)); }); 40 | } 41 | }); 42 | 43 | //process the row 44 | return async.parallel(rowTasks, function(err, results) { 45 | var out = ""; 46 | results.forEach(function(result) { 47 | out += (result + "\\cell "); 48 | }); 49 | return rowcb(null, out); 50 | }); 51 | }; 52 | } 53 | 54 | TableElement.prototype.getRTFCode = function(colorTable, fontTable, callback){ 55 | var rtf = "", 56 | i, j, 57 | tasks = []; 58 | 59 | this._rows = this._data.length; 60 | this._cols = columnCount(this._data); 61 | 62 | //eaech row requires all this data about columns 63 | var pre = "\\trowd\\trautofit1\\intbl"; 64 | var post = "{\\trowd\\trautofit1\\intbl"; 65 | //now do the first \cellx things 66 | for(j = 0; j 0) { 57 | fontTable.push(this.font); 58 | this.fontPos = fontTable.length-1; 59 | } 60 | //if a color was defined, and it's not in the table, add it as well 61 | if(this.colorPos < 0 && this.color !== undefined) { 62 | colorTable.push(this.color); 63 | this.colorPos = colorTable.length; 64 | } 65 | //background colors use the same table as color 66 | if(this.backgroundColorPos < 0 && this.backgroundColor !== undefined) { 67 | colorTable.push(this.backgroundColor); 68 | this.backgroundColorPos = colorTable.length; 69 | } 70 | }; 71 | 72 | //some RTF elements require that they are wrapped, closed by a trailing 0 and must have a spacebefore the text. 73 | function wrap(text, rtfwrapper){ 74 | return rtfwrapper + " " + text + rtfwrapper + "0"; 75 | } 76 | 77 | /** 78 | * Applies a format to some text 79 | */ 80 | Format.prototype.formatText = function(text, colorTable, fontTable, safeText){ 81 | this.updateTables(colorTable, fontTable); 82 | var rtf = "{"; 83 | if(this.makeParagraph) rtf+="\\pard"; 84 | 85 | if(this.fontPos !== undefined && this.fontPos>=0) rtf+="\\f" + this.fontPos.toString(); 86 | //Add one because color 0 is null 87 | if(this.backgroundColorPos !== undefined && this.backgroundColorPos >= 0) rtf+="\\cb" + (this.backgroundColorPos+1).toString(); 88 | //Add one because color 0 is null 89 | if(this.colorPos !== undefined && this.colorPos>=0) rtf+="\\cf" + (this.colorPos).toString(); 90 | if(this.fontSize >0) rtf += "\\fs" + (this.fontSize*2).toString(); 91 | if(this.align.length > 0) rtf += align; 92 | if(this.leftIndent>0) rtf += "\\li" + (this.leftIndent*20).toString(); 93 | if(this.rightIndent>0) rtf += "\\ri" + this.rightIndent.toString(); 94 | 95 | //we don't escape text if there are other elements in it, so set a flag 96 | var content = ""; 97 | if(safeText === undefined || safeText){ 98 | content += Utils.getRTFSafeText(text); 99 | }else{ 100 | content += text; 101 | } 102 | 103 | if(this.bold) content = wrap(content, "\\b") ; 104 | if(this.italic) content = wrap(content, "\\i"); 105 | if(this.underline) content = wrap(content, "\\ul"); 106 | if(this.strike) content = wrap(content, "\\strike"); 107 | if(this.subScript) content = wrap(content, "\\sub"); 108 | if(this.superScript) content = wrap(content, "\\super"); 109 | rtf += content; 110 | 111 | //close paragraph 112 | if(this.makeParagraph) rtf += "\\par"; 113 | 114 | //close doc 115 | rtf+="}"; 116 | 117 | return rtf; 118 | }; 119 | -------------------------------------------------------------------------------- /lib/rtf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RTF Library, for making rich text documents from scratch! 3 | * by Jonathan Rowny 4 | * 5 | */ 6 | 7 | var RGB = require("./rgb"), 8 | Element = require("./elements/element"), 9 | Format = require("./format"), 10 | Utils = require("./rtf-utils"), 11 | Language = require("./language"), 12 | Orientation = require("./orientation"), 13 | TextElement = require("./elements/text"), 14 | GroupElement = require("./elements/group"), 15 | async = require('async'); 16 | 17 | module.exports = RTF = function () { 18 | //Options 19 | this.pageNumbering = false; 20 | this.marginLeft = 1800; 21 | this.marginRight = 1800; 22 | this.marginBottom = 1440; 23 | this.marginTop = 1440; 24 | 25 | this.language = Language.ENG_US; 26 | 27 | this.columns = 0;//columns? 28 | this.columnLines = false;//lines between columns 29 | this.orientation = Orientation.PORTRAIT; 30 | 31 | //stores the elemnts 32 | this.elements = []; 33 | //stores the colors 34 | this.colorTable = []; 35 | //stores the fonts 36 | this.fontTable = []; 37 | }; 38 | 39 | RTF.prototype.writeText = function (text, format, groupName) { 40 | element = new TextElement(text, format); 41 | if(groupName !== undefined && this._groupIndex(groupName) >= 0) { 42 | this.elements[this._groupIndex(groupName)].push(element); 43 | } else { 44 | this.elements.push(element); 45 | } 46 | }; 47 | 48 | //TODO: not sure why this function exists... probably to validate incoming tables later on 49 | RTF.prototype.addTable = function (table) { 50 | this.elements.push(table); 51 | }; 52 | 53 | RTF.prototype.addTextGroup = function (name, format) { 54 | if(this._groupIndex(name)<0) {//make sure we don't have duplicate groups! 55 | formatGroup = new GroupElement(name, format); 56 | this.elements.push(formatGroup); 57 | } 58 | }; 59 | 60 | //adds a single command to a given group or as an element 61 | //TODO this should not be in prototype. 62 | RTF.prototype.addCommand = function (command, groupName) { 63 | if(groupName !== undefined && this._groupIndex(groupName)>=0) { 64 | this.elements[this._groupIndex(groupName)].addElement({text:command, safe:false}); 65 | } else { 66 | this.elements.push({text:command, safe:false}); 67 | } 68 | }; 69 | 70 | //page break shortcut 71 | RTF.prototype.addPage = function (groupName) { 72 | this.addCommand("\\page", groupName); 73 | }; 74 | 75 | //line break shortcut 76 | RTF.prototype.addLine = function (groupName) { 77 | this.addCommand("\\line", groupName); 78 | }; 79 | 80 | //tab shortcut 81 | RTF.prototype.addTab = function (groupName) { 82 | this.addCommand("\\tab", groupName); 83 | }; 84 | 85 | 86 | //gets the index of a group 87 | //TODO: make this more private by removing it from prototype and passing elements 88 | RTF.prototype._groupIndex = function (name) { 89 | this.elements.forEach(function(el, i){ 90 | if(el instanceof GroupElement && el.name===name) { 91 | return i; 92 | } 93 | }); 94 | return -1; 95 | }; 96 | 97 | RTF.prototype.createDocument = function (callback) { 98 | var output = "{\\rtf1\\ansi\\deff0"; 99 | if(this.orientation == Orientation.LANDSCAPE) output+="\\landscape"; 100 | //margins 101 | if(this.marginLeft > 0) output+="\\margl" + this.marginLeft; 102 | if(this.marginRight > 0) output+="\\margr" + this.marginRight; 103 | if(this.marginTop > 0) output+="\\margt" + this.marginTop; 104 | if(this.marginBottom > 0) output+="\\margb" + this.marginBottom; 105 | output+="\\deflang" + this.language; 106 | 107 | var tasks = []; 108 | var ct = this.colorTable; 109 | var ft = this.fontTable; 110 | this.elements.forEach(function(el, i) { 111 | if (el instanceof Element){ 112 | tasks.push(function(cb) { el.getRTFCode(ct, ft, cb); }); 113 | } else { 114 | tasks.push(function(cb) { cb(null, Utils.getRTFSafeText(el)); }); 115 | } 116 | }); 117 | 118 | return async.parallel(tasks, function(err, results) { 119 | var elementOutput = ""; 120 | results.forEach(function(result) { 121 | elementOutput+=result; 122 | }); 123 | 124 | //now that the tasks are done running: create tables, data populated during element output 125 | output+=Utils.createColorTable(ct); 126 | output+=Utils.createFontTable(ft); 127 | 128 | //other options 129 | if(this.pageNumbering) output+="{\\header\\pard\\qr\\plain\\f0\\chpgn\\par}"; 130 | if(this.columns > 0) output+="\\cols" + this.columns; 131 | if(this.columnLines) output+="\\linebetcol"; 132 | 133 | //final output 134 | output+=elementOutput+"}"; 135 | 136 | return callback(null, output); 137 | }); 138 | }; 139 | --------------------------------------------------------------------------------