UNPKG

assjs

Version:

A lightweight JavaScript ASS subtitle renderer

115 lines (112 loc) 3.51 kB
import { color2rgba, createSVGEl, uuid } from '../utils.js'; export function createStrokeFilter(tag, scale) { const id = `ASS-${uuid()}`; const hasBorder = tag.xbord || tag.ybord; const hasShadow = tag.xshad || tag.yshad; const isOpaque = (tag.a1 || '00').toLowerCase() !== 'ff'; const blur = (tag.blur || tag.be || 0) * scale; const $filter = createSVGEl('filter', [['id', id]]); $filter.append(createSVGEl('feGaussianBlur', [ ['stdDeviation', hasBorder ? 0 : blur], ['in', 'SourceGraphic'], ['result', 'sg_b'], ])); $filter.append(createSVGEl('feFlood', [ ['flood-color', 'var(--ass-fill-color)'], ['result', 'c1'], ])); $filter.append(createSVGEl('feComposite', [ ['operator', 'in'], ['in', 'c1'], ['in2', 'sg_b'], ['result', 'main'], ])); if (hasBorder) { $filter.append(createSVGEl('feMorphology', [ ['radius', `${tag.xbord * scale} ${tag.ybord * scale}`], ['operator', 'dilate'], ['in', 'SourceGraphic'], ['result', 'dil'], ])); $filter.append(createSVGEl('feGaussianBlur', [ ['stdDeviation', blur], ['in', 'dil'], ['result', 'dil_b'], ])); $filter.append(createSVGEl('feComposite', [ ['operator', 'out'], ['in', 'dil_b'], ['in2', 'SourceGraphic'], ['result', 'dil_b_o'], ])); $filter.append(createSVGEl('feFlood', [ ['flood-color', 'var(--ass-border-color)'], ['result', 'c3'], ])); $filter.append(createSVGEl('feComposite', [ ['operator', 'in'], ['in', 'c3'], ['in2', 'dil_b_o'], ['result', 'border'], ])); } if (hasShadow && (hasBorder || isOpaque)) { $filter.append(createSVGEl('feOffset', [ ['dx', tag.xshad * scale], ['dy', tag.yshad * scale], ['in', hasBorder ? (isOpaque ? 'dil' : 'dil_b_o') : 'SourceGraphic'], ['result', 'off'], ])); $filter.append(createSVGEl('feGaussianBlur', [ ['stdDeviation', blur], ['in', 'off'], ['result', 'off_b'], ])); if (!isOpaque) { $filter.append(createSVGEl('feOffset', [ ['dx', tag.xshad * scale], ['dy', tag.yshad * scale], ['in', 'SourceGraphic'], ['result', 'sg_off'], ])); $filter.append(createSVGEl('feComposite', [ ['operator', 'out'], ['in', 'off_b'], ['in2', 'sg_off'], ['result', 'off_b_o'], ])); } $filter.append(createSVGEl('feFlood', [ ['flood-color', 'var(--ass-shadow-color)'], ['result', 'c4'], ])); $filter.append(createSVGEl('feComposite', [ ['operator', 'in'], ['in', 'c4'], ['in2', isOpaque ? 'off_b' : 'off_b_o'], ['result', 'shadow'], ])); } const $merge = createSVGEl('feMerge', []); if (hasShadow && (hasBorder || isOpaque)) { $merge.append(createSVGEl('feMergeNode', [['in', 'shadow']])); } if (hasBorder) { $merge.append(createSVGEl('feMergeNode', [['in', 'border']])); } $merge.append(createSVGEl('feMergeNode', [['in', 'main']])); $filter.append($merge); return { id, el: $filter }; } export function createStrokeVars(tag) { return [ ['border-width', tag.xbord * 2], ['border-color', color2rgba(`${tag.a3}${tag.c3}`)], ['shadow-color', color2rgba(`${tag.a4}${tag.c4}`)], ['tag-blur', tag.blur || tag.be || 0], ['tag-xbord', tag.xbord], ['tag-ybord', tag.ybord], ['tag-xshad', tag.xshad], ['tag-yshad', tag.yshad], ].map(([k, v]) => [`--ass-${k}`, v]); }