ass-compiler
Version:
Parses and compiles ASS subtitle format to easy-to-use data structure.
102 lines (99 loc) • 2.67 kB
JavaScript
// same as Aegisub
// https://github.com/Aegisub/Aegisub/blob/master/src/ass_style.h
const DEFAULT_STYLE = {
Name: 'Default',
Fontname: 'Arial',
Fontsize: '20',
PrimaryColour: '&H00FFFFFF&',
SecondaryColour: '&H000000FF&',
OutlineColour: '&H00000000&',
BackColour: '&H00000000&',
Bold: '0',
Italic: '0',
Underline: '0',
StrikeOut: '0',
ScaleX: '100',
ScaleY: '100',
Spacing: '0',
Angle: '0',
BorderStyle: '1',
Outline: '2',
Shadow: '2',
Alignment: '2',
MarginL: '10',
MarginR: '10',
MarginV: '10',
Encoding: '1',
};
/**
* @param {String} color
* @returns {Array} [AA, BBGGRR]
*/
export function parseStyleColor(color) {
if (/^(&|H|&H)[0-9a-f]{6,}/i.test(color)) {
const [, a, c] = color.match(/&?H?([0-9a-f]{2})?([0-9a-f]{6})/i);
return [a || '00', c];
}
const num = parseInt(color, 10);
if (!Number.isNaN(num)) {
const min = -2147483648;
const max = 2147483647;
if (num < min) {
return ['00', '000000'];
}
const aabbggrr = (min <= num && num <= max)
? `00000000${(num < 0 ? num + 4294967296 : num).toString(16)}`.slice(-8)
: String(num).slice(0, 8);
return [aabbggrr.slice(0, 2), aabbggrr.slice(2)];
}
return ['00', '000000'];
}
export function compileStyles({ info, style, defaultStyle }) {
const result = {};
const styles = [Object.assign({}, defaultStyle, { Name: 'Default' })].concat(style);
for (let i = 0; i < styles.length; i++) {
const s = Object.assign({}, DEFAULT_STYLE, styles[i]);
// this behavior is same as Aegisub by black-box testing
if (/^(\*+)Default$/.test(s.Name)) {
s.Name = 'Default';
}
Object.keys(s).forEach((key) => {
if (key !== 'Name' && key !== 'Fontname' && !/Colour/.test(key)) {
s[key] *= 1;
}
});
const [a1, c1] = parseStyleColor(s.PrimaryColour);
const [a2, c2] = parseStyleColor(s.SecondaryColour);
const [a3, c3] = parseStyleColor(s.OutlineColour);
const [a4, c4] = parseStyleColor(s.BackColour);
const tag = {
fn: s.Fontname,
fs: s.Fontsize,
c1,
a1,
c2,
a2,
c3,
a3,
c4,
a4,
b: Math.abs(s.Bold),
i: Math.abs(s.Italic),
u: Math.abs(s.Underline),
s: Math.abs(s.StrikeOut),
fscx: s.ScaleX,
fscy: s.ScaleY,
fsp: s.Spacing,
frz: s.Angle,
xbord: s.Outline,
ybord: s.Outline,
xshad: s.Shadow,
yshad: s.Shadow,
fe: s.Encoding,
// TODO: [breaking change] remove `q` from style
q: /^[0-3]$/.test(info.WrapStyle) ? info.WrapStyle * 1 : 2,
};
result[s.Name] = { style: s, tag };
}
return result;
}