propresenter-parser
Version:
Parses ProPresenter 4, 5, and 6 files to extract the data, and can build ProPresenter 5 and 6 files
117 lines (116 loc) • 5.02 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizeColorToHex = exports.normalizeColorToRgbObj = exports.normalizeColorToRgbaString = exports.hexToRgb = exports.getUniqueID = exports.getIsoDateString = exports.getTextPropsFromRtf = exports.formatRtf = exports.stripRtf = exports.patternRgbaStr = exports.patternRgbaStrAsString = exports.patternHexColor = void 0;
exports.patternHexColor = /^#?[a-f\d]{6}$/i;
exports.patternRgbaStrAsString = '[10](?:\\.\\d+)? [10](?:\\.\\d+)? [10](?:\\.\\d+)? [10](?:\\.\\d+)?';
exports.patternRgbaStr = new RegExp('^' + exports.patternRgbaStrAsString + '$');
const stripRtf = (str) => {
const basicRtfPattern = /\{\*?\\[^{}]+;}|[{}]|\\[A-Za-z]+\n?(?:-?\d+)?[ ]?/g;
const newLineSlashesPattern = /\\\n/g;
const ctrlCharPattern = /\n\\f[0-9]\s/g;
return str.replace(ctrlCharPattern, '').replace(basicRtfPattern, '').replace(newLineSlashesPattern, '\n').trim();
};
exports.stripRtf = stripRtf;
const formatRtf = (text, font = 'Arial', size = 60, color = { r: 255, g: 255, b: 255 }) => {
return `{\\rtf1\\ansi\\ansicpg1252\\cocoartf1038\\cocoasubrtf320{\\fonttbl\\f0\\fswiss\\fcharset0 ${font};}{\\colortbl;\\red${color.r}\\green${color.g}\\blue${color.b};}\\pard\\tx560\\tx1120\\tx1680\\tx2240\\tx2800\\tx3360\\tx3920\\tx4480\\tx5040\\tx5600\\tx6160\\tx6720\\qc\\pardirnatural\\f0\\fs${size * 2} \\cf1 ${text.replace(/\r|\n/g, '\\\r')}}`;
};
exports.formatRtf = formatRtf;
const getTextPropsFromRtf = (str) => {
const color = { r: 0, g: 0, b: 0 };
let font = '';
let size = 0;
const fontMatches = Array.from(str.matchAll(/\\fcharset0 (.+?);/gi));
if (fontMatches.length > 0) {
font = fontMatches[fontMatches.length - 1][1];
}
const colorMatch = /\\red(\d+)\\green(\d+)\\blue(\d+);}/i.exec(str);
if (colorMatch) {
color.r = parseInt(colorMatch[1], 10);
color.g = parseInt(colorMatch[2], 10);
color.b = parseInt(colorMatch[3], 10);
}
const sizeMatch = Array.from(str.matchAll(/\\fs(\d+) ?\\/gi));
if (sizeMatch.length > 0) {
size = parseInt(sizeMatch[sizeMatch.length - 1][1], 10) / 2;
}
return {
color,
font,
size,
};
};
exports.getTextPropsFromRtf = getTextPropsFromRtf;
const getIsoDateString = () => {
return new Date().toISOString().replace(/\.\d{3}Z$/, '');
};
exports.getIsoDateString = getIsoDateString;
const getUniqueID = () => {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1)
.toUpperCase();
}
return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4() + s4() + s4()}`;
};
exports.getUniqueID = getUniqueID;
const hexToRgb = (hex) => {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
if (result) {
return {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16),
};
}
throw new Error(`Input color '${hex}' could not be parsed! Are you sure this is a hex color?`);
};
exports.hexToRgb = hexToRgb;
const normalizeColorToRgbaString = (color) => {
if (typeof color !== 'string') {
return `${color.r / 255} ${color.g / 255} ${color.b / 255} 1`;
}
if (exports.patternRgbaStr.test(color)) {
return color;
}
if (exports.patternHexColor.test(color)) {
return (0, exports.normalizeColorToRgbaString)((0, exports.hexToRgb)(color));
}
throw new Error(`Input color '${color}' could not be parsed to an RGBA color string!`);
};
exports.normalizeColorToRgbaString = normalizeColorToRgbaString;
const normalizeColorToRgbObj = (color) => {
if (typeof color !== 'string') {
return color;
}
if (exports.patternRgbaStr.test(color)) {
const parts = color.split(' ');
return {
r: parseFloat(parts[0]) * 255,
g: parseFloat(parts[1]) * 255,
b: parseFloat(parts[2]) * 255,
};
}
if (exports.patternHexColor.test(color)) {
return (0, exports.hexToRgb)(color);
}
throw new Error(`Input color '${color}' could not be parsed to an RGB color object!`);
};
exports.normalizeColorToRgbObj = normalizeColorToRgbObj;
const normalizeColorToHex = (color) => {
const to16Bit = (i) => ('00' + i.toString(16)).slice(-2).toUpperCase();
if (typeof color !== 'string') {
return to16Bit(color.r) + to16Bit(color.g) + to16Bit(color.b);
}
if (exports.patternRgbaStr.test(color)) {
const parts = color.split(' ');
return (to16Bit(Math.round(parseFloat(parts[0]) * 255)) +
to16Bit(Math.round(parseFloat(parts[1]) * 255)) +
to16Bit(Math.round(parseFloat(parts[2]) * 255)));
}
if (exports.patternHexColor.test(color)) {
return color.replace('#', '');
}
throw new Error(`Input color '${color}' could not be parsed to a HEX color!`);
};
exports.normalizeColorToHex = normalizeColorToHex;