Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for logo/watermark #125

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,11 @@ Edit specs are JavaScript / JSON objects describing the whole edit operation wit
| `audioNorm.enable` | | Enable audio normalization? See [audio normalization](#audio-normalization). | `false` | |
| `audioNorm.gaussSize` | | Audio normalization gauss size. See [audio normalization](#audio-normalization). | `5` | |
| `audioNorm.maxGain` | | Audio normalization max gain. See [audio normalization](#audio-normalization). | `30` | |
| `logoPath` | | Path to logo image. Only local paths are supported, even with `allowRemoteRequests`. Logo parameters are ignored if output is a `.gif`. | | |
| `logoWidth` | | Logo width relative to screen width. Specify only one of `logoWidth` or `logoHeight` to retain the aspect ratio of the logo. | 0.2 | `0` to `1` |
| `logoHeight` | | Logo height relative to screen height. Specify only one of `logoWidth` or `logoHeight` to retain the aspect ratio of the logo.| | `0` to `1` |
| `logoX` | | X-position of the left edge of the logo relative to the screen width. | 0.78 | `0` to `1` |
| `logoY` | | Y-position of the bottom edge of the logo relative to the screen height. | 0.98 | `0` to `1` |

### Transition types

Expand Down Expand Up @@ -301,6 +306,7 @@ Title with background
#### Layer type 'news-title'
- `fontPath` - See `defaults.layer.fontPath`
- `text`
- `fontSize`
- `textColor` - default `#ffffff`
- `backgroundColor` - default `#d02a42`
- `position` - See [Position parameter](#position-parameter)
Expand Down
6 changes: 5 additions & 1 deletion cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const cli = meow(`
params.clips = clips.map((clip) => ({ layers: [clip] }));
}

const { verbose, transitionName, transitionDuration, clipDuration, width, height, fps, audioFilePath, fontPath, fast, out: outPath, keepSourceAudio, loopAudio, outputVolume, allowRemoteRequests } = cli.flags;
const { verbose, transitionName, transitionDuration, clipDuration, width, height, fps, audioFilePath, fontPath, fast, out: outPath, keepSourceAudio, loopAudio, outputVolume, allowRemoteRequests, logoPath, logoWidth, logoHeight, logoX, logoY } = cli.flags;

if (transitionName || transitionDuration != null) {
params.defaults.transition = {};
Expand All @@ -130,6 +130,10 @@ const cli = meow(`
if (height) params.height = height;
if (fps) params.fps = fps;

if (!params.logoWidth && !params.logoHeight) params.logoWidth = 0.2;
if (!params.logoX) params.logoX = 0.78;
if (!params.logoY) params.logoY = 0.98;

if (fast) params.fast = fast;
if (verbose) params.verbose = verbose;

Expand Down
23 changes: 17 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ async function Editly(config = {}) {

ffmpegPath = 'ffmpeg',
ffprobePath = 'ffprobe',
logoPath,
logoWidth,
logoHeight,
logoX,
logoY,
} = config;

await testFf(ffmpegPath, 'ffmpeg');
Expand Down Expand Up @@ -141,15 +146,15 @@ async function Editly(config = {}) {
let fps;
let framerateStr;

if (fast) {
if (isGif) {
fps = 10;
framerateStr = String(fps);
} else if (fast) {
fps = 15;
framerateStr = String(fps);
} else if (requestedFps && typeof requestedFps === 'number') {
fps = requestedFps;
framerateStr = String(requestedFps);
} else if (isGif) {
fps = 10;
framerateStr = String(fps);
} else if (firstVideoFramerateStr) {
fps = parseFps(firstVideoFramerateStr);
framerateStr = firstVideoFramerateStr;
Expand Down Expand Up @@ -183,12 +188,17 @@ async function Editly(config = {}) {
return customOutputArgs;
}

// if one of logo height or width has been specified, retain logo aspect ratio
var logoW = logoWidth ? (width + '*' + logoWidth) : 'oh*mdar';
var logoH = logoHeight ? (height + '*' + logoHeight) : 'ow/mdar';
// https://superuser.com/questions/556029/how-do-i-convert-a-video-to-gif-using-ffmpeg-with-reasonable-quality
const videoOutputArgs = isGif ? [
'-vf', `format=rgb24,fps=${fps},scale=${width}:${height}:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse`,
'-loop', 0,
] : [
'-vf', 'format=yuv420p',
...(logoPath ? ['-filter_complex', '[0]format=yuv420p[main],[1][main]scale2ref=w=ceil(' + logoW + '/2)*2:h=ceil(' + logoH + '/2)*2[logo][mainvid];[mainvid][logo]overlay=x=' + width + '*' + logoX + ':y=' + height + '*' + logoY + '-overlay_h'] : ['-vf', 'format=yuv420p']),
// scale2ref= scales the logo, keeping its aspect ratio, with outputs [logo] and [mainvid]
// overlay= overlays [logo] onto [mainvid]
'-vcodec', 'libx264',
'-profile:v', 'high',
...(fast ? ['-preset:v', 'ultrafast'] : ['-preset:v', 'medium']),
Expand All @@ -213,10 +223,11 @@ async function Editly(config = {}) {
'-r', framerateStr,
'-i', '-',

...(logoPath && !isGif ? ['-i', logoPath] : []),
...(audioFilePath ? ['-i', audioFilePath] : []),

...(!isGif ? ['-map', '0:v:0'] : []),
...(audioFilePath ? ['-map', '1:a:0'] : []),
...(audioFilePath ? ['-map', (logoPath && !isGif ? '2' : '1') + ':a:0'] : []),

...getOutputArgs(),

Expand Down
18 changes: 11 additions & 7 deletions sources/fabric/fabricFrameSources.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,36 +304,40 @@ export async function titleFrameSource({ width, height, params }) {
}

export async function newsTitleFrameSource({ width, height, params }) {
const { text, textColor = '#ffffff', backgroundColor = '#d02a42', fontFamily = defaultFontFamily, delay = 0, speed = 1 } = params;
const { text, textColor = '#ffffff', backgroundColor = '#d02a42', fontFamily = defaultFontFamily, fontSize = 0.05, position = { x:0, y:0.08 }, delay = 0, speed = 1 } = params;

async function onRender(progress, canvas) {
const min = Math.min(width, height);

const fontSize = Math.round(min * 0.05);
const { left, top, originX, originY } = getPositionProps({ position, width, height });
const fromLeft = left / width < 0.5;
const fontSizeAbs = Math.round(min * fontSize);

const easedBgProgress = easeOutExpo(Math.max(0, Math.min((progress - delay) * speed * 3, 1)));
const easedTextProgress = easeOutExpo(Math.max(0, Math.min((progress - delay - 0.02) * speed * 4, 1)));
const easedTextOpacityProgress = easeOutExpo(Math.max(0, Math.min((progress - delay - 0.07) * speed * 4, 1)));

const top = height * 0.08;

const paddingV = 0.07 * min;
const paddingH = 0.03 * min;

const textBox = new fabric.Text(text, {
top,
left: paddingV + (easedTextProgress - 1) * width,
fill: textColor,
opacity: easedTextOpacityProgress,
fontFamily,
fontSize,
fontSize: fontSizeAbs,
charSpacing: width * 0.1,
});
if (fromLeft) {
textBox.set('left', left + paddingV + (easedTextProgress - 1) * width);
} else {
textBox.set('left', left - paddingV - easedTextProgress * textBox.width);
}

const bgWidth = textBox.width + (paddingV * 2);
const rect = new fabric.Rect({
top: top - paddingH,
left: (easedBgProgress - 1) * bgWidth,
left: fromLeft ? (left + (easedBgProgress - 1) * bgWidth) : (left - (easedBgProgress * bgWidth)),
width: bgWidth,
height: textBox.height + (paddingH * 2),
fill: backgroundColor,
Expand Down