Skip to content

Commit

Permalink
first draft of ability to output a specific single frame
Browse files Browse the repository at this point in the history
  • Loading branch information
amiantos committed Jan 4, 2021
1 parent fa74590 commit e7816e5
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 15 deletions.
47 changes: 32 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const injectLottie = `
* @param {string} [opts.path] - Relative path to the JSON file containing animation data
* @param {number} [opts.width] - Optional output width
* @param {number} [opts.height] - Optional output height
* @param {number} [opts.frame] - Optional specific frame to output
* @param {object} [opts.jpegQuality=90] - JPEG quality for frames (does nothing if using png)
* @param {object} [opts.quiet=false] - Set to true to disable console output
* @param {number} [opts.deviceScaleFactor=1] - Window device scale factor
Expand Down Expand Up @@ -83,7 +84,8 @@ module.exports = async (opts) => {

let {
width = undefined,
height = undefined
height = undefined,
frame = undefined
} = opts

ow(output, ow.string.nonEmpty, 'output')
Expand Down Expand Up @@ -146,13 +148,19 @@ module.exports = async (opts) => {
}

const fps = ~~lottieData.fr
const outPoint = ~~lottieData.op
const { w = 640, h = 480 } = lottieData
const aR = w / h

ow(fps, ow.number.integer.positive, 'animationData.fr')
ow(outPoint, ow.number.integer.positive, 'animationData.op')
ow(w, ow.number.integer.positive, 'animationData.w')
ow(h, ow.number.integer.positive, 'animationData.h')

if (frame && (outPoint > frame || frame < 0)) {
throw new Error('Specified frame is outside animation runtime')
}

if (!(width && height)) {
if (width) {
height = width / aR
Expand Down Expand Up @@ -356,26 +364,35 @@ ${inject.body || ''}
})
}

for (let frame = 0; frame < numFrames; ++frame) {
const frameOutputPath = isMultiFrame
? sprintf(tempOutput, frame + 1)
: tempOutput

if (frame) {
// eslint-disable-next-line no-undef
await page.evaluate((frame) => animation.goToAndStop(frame, true), frame)
const screenshot = await rootHandle.screenshot({
path: isMp4 ? undefined : frameOutputPath,
await rootHandle.screenshot({
path: tempOutput,
...screenshotOpts
})
} else {
for (let currentFrame = 0; currentFrame < numFrames; ++currentFrame) {
const frameOutputPath = isMultiFrame
? sprintf(tempOutput, currentFrame + 1)
: tempOutput

// eslint-disable-next-line no-undef
await page.evaluate((currentFrame) => animation.goToAndStop(currentFrame, true), currentFrame)
const screenshot = await rootHandle.screenshot({
path: isMp4 ? undefined : frameOutputPath,
...screenshotOpts
})

// single screenshot
if (!isMultiFrame) {
break
}
// single screenshot
if (!isMultiFrame) {
break
}

if (isApng || isMp4) {
if (ffmpegStdin.writable) {
ffmpegStdin.write(screenshot)
if (isApng || isMp4) {
if (ffmpegStdin.writable) {
ffmpegStdin.write(screenshot)
}
}
}
}
Expand Down
17 changes: 17 additions & 0 deletions index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,23 @@ test('bodymovin.json => single frame png', async (t) => {
await fs.remove(output)
})

test('bodymovin.json => single specific frame png', async (t) => {
const output = tempy.file({ extension: 'png' })

await renderLottie({
path: bodymovin,
quiet: true,
frame: 103,
output
})

const image = imageSize(output)
t.is(image.width, 1820)
t.is(image.height, 275)

await fs.remove(output)
})

test('bodymovin.json => single frame jpg scale=640:-1', async (t) => {
const output = tempy.file({ extension: 'jpg' })

Expand Down
7 changes: 7 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ await renderLottie({
path: 'fixtures/bodymovin.json',
output: 'preview.jpg'
})

// Render a single frame of the animation as a JPEG image
await renderLottie({
path: 'fixtures/bodymovin.json',
output: 'preview.jpg',
frame: 12,
})
```

#### Output Size
Expand Down

0 comments on commit e7816e5

Please sign in to comment.