Skip to content

Commit

Permalink
Add post processing
Browse files Browse the repository at this point in the history
  • Loading branch information
workeffortwaste committed Jan 3, 2025
1 parent 7f60e22 commit 0e21dc1
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 7 deletions.
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ What makes `gsap-video-export` different from other solutions is rather than sim
- [gsap-video-export](#gsap-video-export)
- [Contents](#contents)
- [What's New](#whats-new)
- [2.1.0 🆕](#210-)
- [2.0.3 🆕](#203-)
- [2.0.2 🆕](#202-)
- [2.0.1 🆕](#201-)
Expand All @@ -32,6 +33,7 @@ What makes `gsap-video-export` different from other solutions is rather than sim
- [Lossless\* Export](#lossless-export)
- [Timeweb Frame Advancement 🆕](#timeweb-frame-advancement-)
- [Alpha Transparency 🆕](#alpha-transparency-)
- [Post Processing 🆕](#post-processing-)
- [Advanced](#advanced)
- [Cookies 🆕](#cookies-)
- [Chrome 🆕](#chrome-)
Expand All @@ -44,6 +46,10 @@ What makes `gsap-video-export` different from other solutions is rather than sim

## What's New

### 2.1.0 🆕

* Added a `post-process` option, allowing a script to modify the image buffer before it's saved to temp storage.

### 2.0.3 🆕

* Added `prepare-page` and `prepare-frame` options, allowing a script to be run once at page load or before each frame.
Expand Down Expand Up @@ -141,9 +147,10 @@ All additional options are available when used as a module or via the CLI.
| `--help` | | General | Show help | `boolean` | |
| `--version` | | General | Show version number | `boolean` | |
| `-q`, `--verbose` | `verbose` | General | Verbose output. | `boolean` | `true` |
| `-i`, `--info` | `info` | General | Information only. | `boolean` | `false` |
| `-i`, `--info` | `info` | General | Information only. | `boolean` | `false` |
| `-s`, `--prepare-page`, `--script` | `preparePage`, `script` | Browser | Custom script to run once on page load. | `string`, `function` | |
| `--prepare-frame` | `prepareFrame` | Browser | Custom script to run before every frame. | `string`, `function` | |
| `--post-process` | `postProcess` | Browser | Custom script to modify the image buffer. | `string`, `function` | |
| `-S`, `--selector` | `selector` | Browser | DOM selector of element to capture. | `string` | `"document"` |
| `-t`, `--timeline` | `timeline` | Browser | GSAP timeline object. | `string` | `"gsap"` |
| `-z`, `--scale` | `scale` | Browser | Scale factor for higher quality capture. | `number` | `1` |
Expand Down Expand Up @@ -310,6 +317,31 @@ gsap-video-export https://codepen.io/defaced/pen/GRVbwNQ -S svg -v 1080x1080 -o
```
The important part of the command is `-o video.mov -p transparent -c prores_ks -C mov -- -E "'-pix_fmt yuva444p10le'"` which sets ffmpeg to use a video format that's compatible with transparency and tells `gsap-video-export` to respect transparent backgrounds.

### Post Processing 🆕

`gsap-video-export` now lets you modify the image buffer of each frame before it is saved to disk using the `post-processs` option. `post-process` supplies an image buffer to your function and expects you to return one.

Here's an example that dithers each frame with a CGA palette.

```javascript
import { videoExport } from 'gsap-video-export'
import DitherJS from 'ditherjs/server.js'

const dither = new DitherJS({
step: 6,
algorithm: 'diffusion'
})

await videoExport({
url: 'https://codepen.io/cassie-codes/pen/eYzOBGq',
selector: 'svg',
scale: 2,
postProcess: async (buffer) => { return dither.dither(buffer) }
})
```

https://github.com/user-attachments/assets/467c6a87-e3d1-459d-99be-928d8749026e

## Advanced

### Cookies 🆕
Expand Down
1 change: 1 addition & 0 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const options = _yargs
.usage('$0 <url>', 'Export GreenSock (GSAP) animation to video')
.describe('s', '[browser] Custom script (Page)')
.describe('prepare-frame', '[browser] Custom script (Frame)')
.describe('post-process', '[browser] Custom script (Post Process)')
.describe('S', '[browser] DOM selector')
.describe('t', '[browser] GSAP timeline object')
.describe('z', '[browser] Scale factor')
Expand Down
46 changes: 43 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ const videoExport = async (options) => {
log(padCenter('Browser', 'OK'), options.verbose)

/* If a custom script is specified and exists */
if (options.script) options.preparePage = options.script
if (options.script) options.preparePage = options.script
if (options.preparePage) {
let customScript

Expand Down Expand Up @@ -529,8 +529,48 @@ const videoExport = async (options) => {
/* Select the DOM element via the specified selector */
const el = options.selector === 'document' ? page : await page.$(options.selector)

/* Take a screenshot */
await el.screenshot({ path: tmpobj.name + '/' + frameStep + '.png', omitBackground: options.color === 'transparent' })
/* If we're not supplying a post processor script then we can just take a screenshot and save it */
if (!options.postProcess) await el.screenshot({ path: tmpobj.name + '/' + frameStep + '.png', omitBackground: options.color === 'transparent' })

/* Otherwise we need to take a screenshot and then run the post processor script */
if (options.postProcess) {
/* Take a screenshot */
const screenshot = await el.screenshot({ omitBackground: options.color === 'transparent' })

/* If a custom frame script is specified and exists */
let customScript

if (typeof options.postProcess === 'function') {
customScript = options.postProcess
} else {
if (!fs.existsSync(options.postProcess)) {
await dirtyExit(browser, 'The specified script does not exist')
}
/* Load the script */
customScript = fs.readFileSync(options.postProcess, 'utf8')
}

const screenshotBuffer = Buffer.from(screenshot, 'base64')

let updatedScreenshotBuffer
try {
if (typeof customScript === 'function') {
updatedScreenshotBuffer = await customScript(screenshotBuffer)
} else {
// eslint-disable-next-line no-new-func
updatedScreenshotBuffer = await (new Function('imageBuffer', customScript))(screenshotBuffer)
}

/* Write the updated screenshot to the tmp directory */
fs.writeFileSync(tmpobj.name + '/' + frameStep + '.png', updatedScreenshotBuffer)
} catch (err) {
if (options.cli) {
await cleanExit(browser)
} else {
await dirtyExit(browser, 'Unable to run the specified script: ' + err)
}
}
}

/* Increment and update the CLI export progress bar */
if (options.verbose) b1.increment()
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gsap-video-export",
"version": "2.0.4",
"version": "2.1.0",
"description": "Export GreenSock (GSAP) animation to video.",
"main": "index.js",
"type": "module",
Expand Down

0 comments on commit 0e21dc1

Please sign in to comment.