philipjscott / simple-thumbnail

A library that produces thumbnails from images, videos and URLs :mag_right:
https://www.npmjs.com/package/simple-thumbnail
MIT License
25 stars 14 forks source link

Allow passing args to ffmpeg #58

Closed cmd430 closed 4 years ago

cmd430 commented 4 years ago

Context

Allows for a little extra control over the generation

Objective

Allow passing args to ffmpeg (I wanted to allow thumbnail creation of a txt file)

References

None

Example Usage

const fs = require('fs')
const simpleThumbnail = require('simple-thumbnail')
const ffmpeg = require('ffmpeg-static')

let text_input = 'example.txt'
let size = '640x480'

new Promise((resolve, reject) => {
  simpleThumbnail('', null, null, {
    args: [
      '-f lavfi',
      `-i color=c=white:s=${size}:d=5.396`,
      `-filter_complex "drawtext=textfile=${text_input}:x=0:y=0:fontsize=13:fontcolor=000000"`
    ],
    path: ffmpeg.path
  })
    .then(stream => {
      let image = []
      stream.on('data', chunk => image.push(chunk))
      stream.on('end', () => resolve(Buffer.concat(image)))
      stream.on('error', reject)
    })
})
.then(buffer => {
  let wstream = fs.createWriteStream('text_out.png')
  wstream.write(buffer)
  wstream.end()
})
.catch(console.error)

Result:

Notes

cmd430 commented 4 years ago

@ScottyFillups not sure why the Node8 test on travis is failing, Node8, Node10 and Node11 all pass locally for me both on Debian9 and on Windows10

philipjscott commented 4 years ago

@cmd430

Thanks for making this PR, I'll look it over more thoroughly tonight and figure out why Node8 is failling.

It looks good at a glance though, thanks! :+1:

philipjscott commented 4 years ago

I'm going to merge this into args-override and polish this a bit. I'm thinking of changing the API for args override to just be as follows:

  simpleThumbnail({
    args: [
      '-f lavfi',
      `-i color=c=white:s=${size}:d=5.396`,
      `-filter_complex "drawtext=textfile=${text_input}:x=0:y=0:fontsize=13:fontcolor=000000"`
    ],
    path: ffmpeg.path
  })
    .then(stream => {
      let image = []
      stream.on('data', chunk => image.push(chunk))
      stream.on('end', () => resolve(Buffer.concat(image)))
      stream.on('error', reject)
    })

If only an options argument is passed, then we'll return a duplex stream only using the arguments passed in.

philipjscott commented 4 years ago

Actually I changed my mind. For the sake of consistency, we'll do what you originally suggested:

  simpleThumbnail(null, null, null, {
    args: [
      '-f lavfi',
      `-i color=c=white:s=${size}:d=5.396`,
      `-filter_complex "drawtext=textfile=${text_input}:x=0:y=0:fontsize=13:fontcolor=000000"`
    ],
    path: ffmpeg.path
  })
    .then(stream => {
      let image = []
      stream.on('data', chunk => image.push(chunk))
      stream.on('end', () => resolve(Buffer.concat(image)))
      stream.on('error', reject)
    })

The first three nulls won't be read (ie. they can be any arbitrary value). If args is passed in the config, simple-thumbnail will always return a duplex stream, passing in ONLY the arguments in args to ffmpeg.

It looks ugly, but I'd rather make the API consistent for now. I plan to work on a V2; that's when I'll clean things up. I'll @ you when I have a proposal up.

philipjscott commented 4 years ago

:tada: This PR is included in version 1.6.0 :tada:

The release is available on:

Your semantic-release bot :package::rocket: