Import Ruty

This commit is contained in:
2024-03-11 00:54:46 +01:00
parent 2c0c53a22b
commit fbf47eaa3a
485 changed files with 67750 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
pids
logs
results
node_modules
npm-debug.log
+4
View File
@@ -0,0 +1,4 @@
node-rtf
========
An RTF document creation library for node. Based on my old ActionScript3 implementation which has more documentation at http://code.google.com/p/rtflex/.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

+51
View File
@@ -0,0 +1,51 @@
var rtf = require('../lib/rtf'),
Format = require('../lib/format'),
Colors = require('../lib/colors'),
RGB = require('../lib/rgb'),
fs = require('fs');
var myDoc = new rtf(),
red_underline = new Format(),
blue_strike = new Format(),
green_bold = new Format(),
maroon_super = new Format(),
gray_sub = new Format(),
lime_indent = new Format(),
custom_blue = new Format();
red_underline.color = Colors.RED;
red_underline.underline = true;
red_underline.fontSize = 20;
myDoc.writeText("Red underlined", red_underline);
myDoc.addLine();
blue_strike.color = Colors.RED;
blue_strike.strike = true;
myDoc.writeText("Strikeout Blue", blue_strike);
myDoc.addLine();
green_bold.color = Colors.GREEN;
green_bold.bold = true;
myDoc.writeText("Bold Green", green_bold);
myDoc.addLine();
maroon_super.color = Colors.MAROON;
maroon_super.superScript = true;
myDoc.writeText("Superscripted Maroon", maroon_super);
myDoc.addLine();
gray_sub.color = Colors.GRAY;
gray_sub.subScript = true;
myDoc.writeText("Subscripted Gray", gray_sub);
myDoc.addLine();
lime_indent.color = Colors.LIME;
lime_indent.backgroundColor = Colors.Gray;
lime_indent.leftIndent = 50;
myDoc.writeText("Left indented Lime", lime_indent);
myDoc.addLine();
custom_blue.color = new RGB(3, 80, 150);
myDoc.writeText("Custom blue color", custom_blue);
myDoc.createDocument(
function(err, output){
console.log(output);
fs.writeFile('formatting.rtf', output, function (err) {
if (err) return console.log(err);
});
}
);
+21
View File
@@ -0,0 +1,21 @@
var rtf = require('../lib/rtf'),
Format = require('../lib/format'),
Colors = require('../lib/colors'),
fs = require('fs');
var myDoc = new rtf(),
format = new Format();
format.color = Colors.ORANGE;
myDoc.writeText("Happy Halloween", format);
myDoc.addPage();
myDoc.addLine();
myDoc.addTab();
myDoc.writeText("Trick or treat!");
myDoc.createDocument(
function(err, output){
console.log(output);
fs.writeFile('halloween.rtf', output, function (err) {
if (err) return console.log(err);
});
}
);
+16
View File
@@ -0,0 +1,16 @@
var rtf = require('../lib/rtf'),
fs = require('fs'),
ImageElement = require('../lib/elements/image');
var myDoc = new rtf();
myDoc.elements.push(new ImageElement('examples/dog.jpg'));
myDoc.createDocument(
function(err, output){
//console.log(output); //that's a little much to output to the console
fs.writeFile('image.rtf', output, function (err) {
if (err) return console.log(err);
});
}
);
+31
View File
@@ -0,0 +1,31 @@
var rtf = require('../lib/rtf'),
TableElement = require('../lib/elements/table'),
fs = require('fs');
var myDoc = new rtf(),
table = new TableElement(),
table2 = new TableElement();
//add rows
table.addRow(["I'm a table row", "with two columns"]);
table.addRow(["This is the second row", "and the second column"]);
myDoc.addTable(table);
//You can manually set the data *overwrites any data in the table
table2.setData([
["Name", "Price", "Sold"],
["Rubber Ducky", "$10.00", "22"],
["Widget", "$99.99", "42"],
["Sproket", "$5.24", "11"]
]);
//adding a row to an existing data set
table2.addRow(["Banana", "$0.12", "1"]);
myDoc.createDocument(
function(err, output){
console.log(output);
fs.writeFile('table-sample.rtf', output, function (err) {
if (err) return console.log(err);
});
}
);
+6
View File
@@ -0,0 +1,6 @@
module.exports = Align = {
LEFT : "\\ql",
RIGHT : "\\qr",
CENTER : "\\qc",
FULL : "\\qj"
};
+15
View File
@@ -0,0 +1,15 @@
RGB = require("./rgb");
module.exports = Colors =
{
BLACK : new RGB(0,0,0),
WHITE : new RGB(255,255,255),
RED : new RGB(255,0,0),
BLUE : new RGB(0,0,255),
LIME : new RGB(191,255,0),
YELLOW : new RGB(255,255,0),
MAROON : new RGB(128,0,0),
GREEN : new RGB(0,255,0),
GRAY : new RGB(80,80,80),
ORANGE : new RGB(255,127,0)
};
+13
View File
@@ -0,0 +1,13 @@
//inspired by bobnice: http://stackoverflow.com/questions/1595611/how-to-properly-create-a-custom-object-in-javascript
var Format = require('../format');
Function.prototype.subclass= function(base) {
var c= Function.prototype.subclass.nonconstructor;
c.prototype= base.prototype;
this.prototype= new c();
};
Function.prototype.subclass.nonconstructor= function() {};
module.exports = Element = function(format){
if(format === undefined) format = new Format();
this.format = format;
};
+37
View File
@@ -0,0 +1,37 @@
//thanks DTrejo for help using async
var Utils = require("../rtf-utils"),
Element = require('./element'),
async = require('async');
module.exports = GroupElement = function(name, format) {
Element.apply(this, [format]);
this.elements = [];
this.name = name;
};
GroupElement.subclass(Element);
GroupElement.prototype.addElement = function(element){
this.elements.push(element);
};
GroupElement.prototype.getRTFCode = function(colorTable, fontTable, callback){
var tasks = [];
var rtf = "";
this.elements.forEach(function(el, i) {
if (el instanceof Element){
tasks.push(function(cb) { el.getRTFCode(colorTable, fontTable, cb); });
} else {
tasks.push(function(cb) { cb(null, Utils.getRTFSafeText(el)); });
}
});
return async.parallel(tasks, function(err, results) {
results.forEach(function(result) {
rtf += result;
});
//formats the whole group
rtf = format.formatText(rtf, colorTable, fontTable, false);
return callback(null, rtf);
});
};
+41
View File
@@ -0,0 +1,41 @@
var Element = require('./element'),
fs = require('fs'),
imageinfo = require('imageinfo');
module.exports = ImageElement = function(path){
Element.apply(this, arguments);
this.path=path;
this.dpi=300;
};
ImageElement.subclass(Element);
ImageElement.prototype.getRTFCode = function(colorTable, fontTable, callback){
var self = this;
//read image file
return fs.readFile(this.path, function(err, buffer){
if(err) throw err;
//get image information and calculate twips based on DPI
var info = imageinfo(buffer);
var twipRatio = ((72/self.dpi) * 20);
var twipWidth = Math.round(info.width * twipRatio),
twipHeight = Math.round(info.height * twipRatio);
//output image information
var output = "{\\pict\\pngblip\\picw" + info.width + "\\pich" + info.height +
"\\picwgoal" + twipWidth + "\\pichgoal" + twipHeight + " ";
//output buffer to base16 (hex) and ensure prefixed 0 if single digit
var bufSize = buffer.length;
for(var i = 0; i < bufSize; i++){
var hex = buffer[i].toString(16);
output += (hex.length === 2) ? hex : "0" + hex;
}
output += "}";
return callback(null, output);
});
};
+88
View File
@@ -0,0 +1,88 @@
var Utils = require("../rtf-utils"),
Element = require('./element'),
async = require('async');
//TODO: probably replace this with something from underscore
function columnCount(target){
var rows = target.length, max = 0, i;
for(i = 0; i < rows; i++){
if(target[i].length > max) max = target[i].length;
}
return max;
}
module.exports = TableElement = function(){
Element.apply(this, arguments);
this._data = [];
this._rows = 0;
this._cols = 0;
};
TableElement.subclass(Element);
TableElement.prototype.addRow = function(row){
this._data.push(row);
};
TableElement.prototype.setData = function(data){
this._data = data;
};
function rowTask(row, numCols, colorTable, fontTable){
return function(rowcb){
var rowTasks = [];
//generate tasks for each column
row.forEach(function(el, i) {
if (el instanceof Element){
rowTasks.push(function(cb) { el.getRTFCode(colorTable, fontTable, cb); });
} else {
rowTasks.push(function(cb) { cb(null, Utils.getRTFSafeText(el)); });
}
});
//process the row
return async.parallel(rowTasks, function(err, results) {
var out = "";
results.forEach(function(result) {
out += (result + "\\cell ");
});
return rowcb(null, out);
});
};
}
TableElement.prototype.getRTFCode = function(colorTable, fontTable, callback){
var rtf = "",
i, j,
tasks = [];
this._rows = this._data.length;
this._cols = columnCount(this._data);
//eaech row requires all this data about columns
var pre = "\\trowd\\trautofit1\\intbl";
var post = "{\\trowd\\trautofit1\\intbl";
//now do the first \cellx things
for(j = 0; j<this._cols; j++){
pre += "\\clbrdrt\\brdrs\\brdrw10\\clbrdrl\\brdrs\\brdrw10\\clbrdrb\\brdrs\\brdrw10\\clbrdrr\\brdrs\\brdrw10";
pre += "\\cellx" + (j+1).toString();
post += "\\cellx" + (j+1).toString();
}
post += "\\row }";
//generate tasks for each row
for(i = 0; i < this._rows; i++){
if(this._data[i]){
tasks.push(rowTask(this._data[i], this._cols, colorTable, fontTable));
}
}
return async.parallel(tasks, function(err, results) {
var rows = "";
results.forEach(function(result) {
rows += (pre + "{" + result + " }" + post);
});
rtf = "\\par" + rows + "\\pard";
return callback(null, rtf);
});
};
+12
View File
@@ -0,0 +1,12 @@
var Element = require('./element');
module.exports = TextElement = function(text, format){
Element.apply(this, [format]);
this.text=text;
};
TextElement.subclass(Element);
TextElement.prototype.getRTFCode = function(colorTable, fontTable, callback){
return callback(null, this.format.formatText(this.text, colorTable, fontTable));
};
+12
View File
@@ -0,0 +1,12 @@
module.exports = Fonts = {
ARIAL : "Arial",
COMIC_SANS : "Comic Sans MS",
GEORGIA : "Georgia",
IMPACT : "Impact",
TAHOMA : "Tahoma",
HELVETICA : "Helvetica",
VERDANA : "Verdana",
COURIER_NEW : "Courier New",
PALATINO : "Palatino Linotype",
TIMES_NEW_ROMAN : "Times New Roman"
};
+118
View File
@@ -0,0 +1,118 @@
var Utils = require("./rtf-utils"),
Align = require("./Align"),
Fonts = require("./fonts");
module.exports = Format = function(){
this.underline=false;
this.bold=false;
this.italic=false;
this.strike=false;
this.superScript=false;
this.subScript=false;
this.makeParagraph=false;
this.align = "";
this.leftIndent=0;
this.rightIndent=0;
this.font = Fonts.ARIAL;
this.fontSize=0;
//this.color = rgb;
//this.backgroundColor = rgb;
this.colorPos = -1;
this.backgroundColorPos= -1;
this.fontPos = -1;
//if defined, this element will become a link to this url
//TODO: not implemented
//this.url;
};
//because JS doesn't have .equalsTo
function getColorPosition(table, find){
if(find !== undefined && find instanceof RGB){
table.forEach(function(color, index){
if(color.red === find.red &&
color.green === find.green &&
color.blue === find.blue){
return index;
}
});
}
return -1;
}
Format.prototype.updateTables = function(colorTable, fontTable){
this.fontPos = fontTable.indexOf(this.font);
this.colorPos = getColorPosition(colorTable, this.color);
this.backgroundColorPos = getColorPosition(colorTable, this.backgroundColor);
//if a a font was defined, and it's not in a table, add it in!
if(this.fontPos < 0 && this.font !== undefined && this.font.length > 0) {
fontTable.push(this.font);
this.fontPos = fontTable.length-1;
}
//if a color was defined, and it's not in the table, add it as well
if(this.colorPos < 0 && this.color !== undefined) {
colorTable.push(this.color);
this.colorPos = colorTable.length;
}
//background colors use the same table as color
if(this.backgroundColorPos < 0 && this.backgroundColor !== undefined) {
colorTable.push(this.backgroundColor);
this.backgroundColorPos = colorTable.length;
}
};
//some RTF elements require that they are wrapped, closed by a trailing 0 and must have a spacebefore the text.
function wrap(text, rtfwrapper){
return rtfwrapper + " " + text + rtfwrapper + "0";
}
/**
* Applies a format to some text
*/
Format.prototype.formatText = function(text, colorTable, fontTable, safeText){
this.updateTables(colorTable, fontTable);
var rtf = "{";
if(this.makeParagraph) rtf+="\\pard";
if(this.fontPos !== undefined && this.fontPos>=0) rtf+="\\f" + this.fontPos.toString();
//Add one because color 0 is null
if(this.backgroundColorPos !== undefined && this.backgroundColorPos >= 0) rtf+="\\cb" + (this.backgroundColorPos+1).toString();
//Add one because color 0 is null
if(this.colorPos !== undefined && this.colorPos>=0) rtf+="\\cf" + (this.colorPos).toString();
if(this.fontSize >0) rtf += "\\fs" + (this.fontSize*2).toString();
if(this.align.length > 0) rtf += align;
if(this.leftIndent>0) rtf += "\\li" + (this.leftIndent*20).toString();
if(this.rightIndent>0) rtf += "\\ri" + this.rightIndent.toString();
//we don't escape text if there are other elements in it, so set a flag
var content = "";
if(safeText === undefined || safeText){
content += Utils.getRTFSafeText(text);
}else{
content += text;
}
if(this.bold) content = wrap(content, "\\b") ;
if(this.italic) content = wrap(content, "\\i");
if(this.underline) content = wrap(content, "\\ul");
if(this.strike) content = wrap(content, "\\strike");
if(this.subScript) content = wrap(content, "\\sub");
if(this.superScript) content = wrap(content, "\\super");
rtf += content;
//close paragraph
if(this.makeParagraph) rtf += "\\par";
//close doc
rtf+="}";
return rtf;
};
+6
View File
@@ -0,0 +1,6 @@
module.exports = Language = {
ENG_US : "1033",
SP_MX : "2058",
FR : "1036",
NONE : "1024"
};
+4
View File
@@ -0,0 +1,4 @@
module.exports = Orientation = {
PORTRAIT : false,
LANDSCAPE : true
};
+5
View File
@@ -0,0 +1,5 @@
module.exports = RGB = function(red, green, blue){
this.red = red;
this.green = green;
this.blue = blue;
};
+76
View File
@@ -0,0 +1,76 @@
var Fonts = require('./fonts');
/**
* ReplaceAll by Fagner Brack (MIT Licensed)
* Replaces all occurrences of a substring in a string
*/
String.prototype.replaceAll = function(token, newToken, ignoreCase) {
var str = this.toString(), i = -1, _token;
if(typeof token === "string") {
if(ignoreCase === true) {
_token = token.toLowerCase();
while((i = str.toLowerCase().indexOf( token, i >= 0? i + newToken.length : 0 )) !== -1 ) {
str = str.substring(0, i)
.concat(newToken)
.concat(str.substring(i + token.length));
}
} else {
return this.split(token).join(newToken);
}
}
return str;
};
/**
* makes text safe for RTF by escaping characters and it also converts linebreaks
* also checks to see if safetext should be overridden by non-elements like "\line"
*/
function getRTFSafeText(text){
//if text is overridden not to be safe
if(typeof text === "object" && text.hasOwnProperty("safe") && !text.safe){
return text.text;
}
//this could probably all be replaced by a bit of regex
return text.replaceAll('\\','\\\\')
.replaceAll('{','\\{')
.replaceAll('}','\\}')
.replaceAll('~','\\~')
.replaceAll('-','\\-')
.replaceAll('_','\\_')
//turns line breaks into \line commands
.replaceAll('\n\r',' \\line ')
.replaceAll('\n',' \\line ')
.replaceAll('\r',' \\line ');
}
//gneerates a color table
function createColorTable(colorTable) {
var table = "",
c;
table+="{\\colortbl;";
for(c=0; c < colorTable.length; c++) {
rgb = colorTable[c];
table+="\\red" + rgb.red + "\\green" + rgb.green + "\\blue" + rgb.blue + ";";
}
table+="}";
return table;
}
//gneerates a font table
function createFontTable(fontTable) {
var table = "",
f;
table+="{\\fonttbl;";
if(fontTable.length === 0) {
table+="{\\f0 " + Fonts.ARIAL + "}"; //if no fonts are defined, use arial
} else {
for(f=0;f<fontTable.length;f++) {
table+="{\\f" + f + " " + fontTable[f] + "}";
}
}
table+="}";
return table;
}
exports.getRTFSafeText = getRTFSafeText;
exports.createColorTable = createColorTable;
exports.createFontTable = createFontTable;
+138
View File
@@ -0,0 +1,138 @@
/**
* RTF Library, for making rich text documents from scratch!
* by Jonathan Rowny
*
*/
var RGB = require("./rgb"),
Element = require("./elements/element"),
Format = require("./format"),
Utils = require("./rtf-utils"),
Language = require("./language"),
Orientation = require("./orientation"),
TextElement = require("./elements/text"),
GroupElement = require("./elements/group"),
async = require('async');
module.exports = RTF = function () {
//Options
this.pageNumbering = false;
this.marginLeft = 1800;
this.marginRight = 1800;
this.marginBottom = 1440;
this.marginTop = 1440;
this.language = Language.ENG_US;
this.columns = 0;//columns?
this.columnLines = false;//lines between columns
this.orientation = Orientation.PORTRAIT;
//stores the elemnts
this.elements = [];
//stores the colors
this.colorTable = [];
//stores the fonts
this.fontTable = [];
};
RTF.prototype.writeText = function (text, format, groupName) {
element = new TextElement(text, format);
if(groupName !== undefined && this._groupIndex(groupName) >= 0) {
this.elements[this._groupIndex(groupName)].push(element);
} else {
this.elements.push(element);
}
};
//TODO: not sure why this function exists... probably to validate incoming tables later on
RTF.prototype.addTable = function (table) {
this.elements.push(table);
};
RTF.prototype.addTextGroup = function (name, format) {
if(this._groupIndex(name)<0) {//make sure we don't have duplicate groups!
formatGroup = new GroupElement(name, format);
this.elements.push(formatGroup);
}
};
//adds a single command to a given group or as an element
//TODO this should not be in prototype.
RTF.prototype.addCommand = function (command, groupName) {
if(groupName !== undefined && this._groupIndex(groupName)>=0) {
this.elements[this._groupIndex(groupName)].addElement({text:command, safe:false});
} else {
this.elements.push({text:command, safe:false});
}
};
//page break shortcut
RTF.prototype.addPage = function (groupName) {
this.addCommand("\\page", groupName);
};
//line break shortcut
RTF.prototype.addLine = function (groupName) {
this.addCommand("\\line", groupName);
};
//tab shortcut
RTF.prototype.addTab = function (groupName) {
this.addCommand("\\tab", groupName);
};
//gets the index of a group
//TODO: make this more private by removing it from prototype and passing elements
RTF.prototype._groupIndex = function (name) {
this.elements.forEach(function(el, i){
if(el instanceof GroupElement && el.name===name) {
return i;
}
});
return -1;
};
RTF.prototype.createDocument = function (callback) {
var output = "{\\rtf1\\ansi\\deff0";
if(this.orientation == Orientation.LANDSCAPE) output+="\\landscape";
//margins
if(this.marginLeft > 0) output+="\\margl" + this.marginLeft;
if(this.marginRight > 0) output+="\\margr" + this.marginRight;
if(this.marginTop > 0) output+="\\margt" + this.marginTop;
if(this.marginBottom > 0) output+="\\margb" + this.marginBottom;
output+="\\deflang" + this.language;
var tasks = [];
var ct = this.colorTable;
var ft = this.fontTable;
this.elements.forEach(function(el, i) {
if (el instanceof Element){
tasks.push(function(cb) { el.getRTFCode(ct, ft, cb); });
} else {
tasks.push(function(cb) { cb(null, Utils.getRTFSafeText(el)); });
}
});
return async.parallel(tasks, function(err, results) {
var elementOutput = "";
results.forEach(function(result) {
elementOutput+=result;
});
//now that the tasks are done running: create tables, data populated during element output
output+=Utils.createColorTable(ct);
output+=Utils.createFontTable(ft);
//other options
if(this.pageNumbering) output+="{\\header\\pard\\qr\\plain\\f0\\chpgn\\par}";
if(this.columns > 0) output+="\\cols" + this.columns;
if(this.columnLines) output+="\\linebetcol";
//final output
output+=elementOutput+"}";
return callback(null, output);
});
};
+21
View File
@@ -0,0 +1,21 @@
{
"name" : "rtf",
"version" : "0.0.4",
"description" : "Assists with creating rich text documents.",
"main" : "./lib/rtf.js",
"author" : "Jonathan Rowny",
"repository" : {
"type" : "git",
"url" : "https://github.com/jrowny/node-rtf.git"
},
"keywords": [
"rtf",
"rich text",
"documents"
],
"license" : "MIT",
"dependencies": {
"async" : "~0",
"imageinfo" : "~1"
}
}