Skip to content

Commit 24540f9

Browse files
committed
Move encoder options from constructor to getBuffer and writeToFile, re-add Node 18 & 20 tests
1 parent ff1c3ba commit 24540f9

6 files changed

Lines changed: 88 additions & 84 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ jobs:
203203
if-no-files-found: error
204204

205205
test-macOS-windows-binding:
206-
name: Test on ${{ matrix.settings.target }}
206+
name: Test on ${{ matrix.settings.target }} - Node ${{ matrix.node }}
207207
needs:
208208
- host-build
209209
strategy:
@@ -216,6 +216,7 @@ jobs:
216216
target: 'aarch64-apple-darwin'
217217
- host: windows-latest
218218
target: 'x86_64-pc-windows-msvc'
219+
node: [18, 20, 22]
219220
runs-on: ${{ matrix.settings.host }}
220221
steps:
221222
- name: Checkout code
@@ -230,15 +231,15 @@ jobs:
230231
uses: actions/setup-node@v4
231232
if: startsWith(matrix.settings.target, 'x86_64')
232233
with:
233-
node-version: 22
234+
node-version: ${{ matrix.node }}
234235
cache: pnpm
235236
architecture: 'x64'
236237

237238
- name: Setup node
238239
uses: actions/setup-node@v4
239240
if: startsWith(matrix.settings.target, 'aarch64')
240241
with:
241-
node-version: 22
242+
node-version: ${{ matrix.node }}
242243
cache: pnpm
243244
architecture: 'arm64'
244245

@@ -255,11 +256,13 @@ jobs:
255256
run: pnpm test
256257

257258
test-linux-x64-gnu-binding:
258-
name: Test bindings on linux-x64-gnu
259+
name: Test bindings on linux-x64-gnu - Node ${{ matrix.node }}
259260
needs:
260261
- cross-build
261262
strategy:
262263
fail-fast: false
264+
matrix:
265+
node: [18, 20, 22]
263266
runs-on: ubuntu-latest
264267
steps:
265268
- name: Checkout code
@@ -273,7 +276,7 @@ jobs:
273276
- name: Setup node
274277
uses: actions/setup-node@v4
275278
with:
276-
node-version: 22
279+
node-version: ${{ matrix.node }}
277280
cache: pnpm
278281

279282
- name: Install dependencies

README.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,9 @@ npm install napi-webp-animation
1515
| | node18 | node20 | node22 |
1616
| ---------------- | ------ | ------ | ------ |
1717
| Windows x64 ||||
18-
| Windows arm64 ||||
1918
| Linux x64 gnu ||||
20-
| Linux x64 musl ||||
21-
| Linux arm gnu ||||
22-
| Linux arm64 gnu ||||
23-
| Linux arm64 musl ||||
24-
| Android arm64 ||||
25-
| Android armv7 ||||
19+
| macOS x64 ||||
20+
| macOS aarch64 ||||
2621

2722

2823
## Developing

index.d.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,13 @@ export interface JsWebpEncoderOptions {
1111
}
1212
export type JsWebpEncoder = WebpEncoder
1313
export declare class WebpEncoder {
14-
constructor(width: number, height: number, options?: JsWebpEncoderOptions)
14+
constructor(width: number, height: number)
1515
setFrameRate(frameRate: number): void
1616
addFrame(frameData: Buffer, duration?: number): void
17-
getBuffer(): Promise<Buffer>
18-
getBufferSync(): Buffer
19-
writeToFile(path: string): Promise<Buffer>
20-
writeToFileSync(path: string): Buffer
17+
getBuffer(options?: JsWebpEncoderOptions): Promise<Buffer>
18+
getBufferSync(options?: JsWebpEncoderOptions): Buffer
19+
writeToFile(path: string, options?: JsWebpEncoderOptions): Promise<Buffer>
20+
writeToFileSync(path: string, options?: JsWebpEncoderOptions): Buffer
2121
clearFrames(): void
2222
setDimensions(width: number, height: number): void
23-
setOptions(options: JsWebpEncoderOptions): void
2423
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"build:debug": "napi build --platform",
5353
"create-npm-dir": "napi create-npm-dir -t .",
5454
"prepublishOnly": "napi prepublish -t npm",
55-
"test": "node --experimental-strip-types test/main.test.mts",
55+
"test": "node test/main.test.mjs",
5656
"version": "napi version"
5757
},
5858
"devDependencies": {

src/encoder.rs

Lines changed: 57 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,15 @@ impl Clone for WebpEncoderFrame {
1919
pub struct WebpEncoder {
2020
width: u32,
2121
height: u32,
22-
options: EncoderOptions,
2322
frame_rate: u16,
2423
frames: Vec<WebpEncoderFrame>,
2524
}
2625

2726
impl WebpEncoder {
28-
pub fn new(width: u32, height: u32, options: Option<EncoderOptions>) -> Self {
27+
pub fn new(width: u32, height: u32) -> Self {
2928
WebpEncoder {
3029
width,
3130
height,
32-
options: options.unwrap_or_else(EncoderOptions::default),
3331
frame_rate: 30,
3432
frames: Vec::new(),
3533
}
@@ -46,10 +44,10 @@ impl WebpEncoder {
4644
});
4745
}
4846

49-
pub fn get_buffer(&self) -> Result<Vec<u8>> {
50-
let mut encoder =
51-
Encoder::new_with_options((self.width, self.height), self.options.to_owned())
52-
.map_err(EncoderError::EncoderError)?;
47+
pub fn get_buffer(&self, options: Option<EncoderOptions>) -> Result<Vec<u8>> {
48+
let options = options.unwrap_or_else(|| EncoderOptions::default());
49+
let mut encoder = Encoder::new_with_options((self.width, self.height), options)
50+
.map_err(EncoderError::EncoderError)?;
5351
let mut timestamp: i32 = 0;
5452
for frame in &self.frames {
5553
encoder
@@ -63,8 +61,8 @@ impl WebpEncoder {
6361
.to_vec())
6462
}
6563

66-
pub fn write_to_file(&self, path: String) -> Result<Vec<u8>> {
67-
let buffer = self.get_buffer()?;
64+
pub fn write_to_file(&self, path: String, options: Option<EncoderOptions>) -> Result<Vec<u8>> {
65+
let buffer = self.get_buffer(options)?;
6866
std::fs::write(
6967
match path.ends_with(".webp") {
7068
true => path,
@@ -85,15 +83,10 @@ impl WebpEncoder {
8583
self.height = height;
8684
}
8785

88-
pub fn set_options(&mut self, options: EncoderOptions) {
89-
self.options = options;
90-
}
91-
9286
pub fn clone(&self) -> Self {
9387
WebpEncoder {
9488
width: self.width,
9589
height: self.height,
96-
options: self.options.clone(),
9790
frame_rate: self.frame_rate,
9891
frames: self.frames.clone(),
9992
}
@@ -110,6 +103,7 @@ pub struct JsWebpEncoderOptions {
110103

111104
pub struct AsyncGetBuffer {
112105
encoder: WebpEncoder,
106+
options: Option<EncoderOptions>,
113107
}
114108

115109
#[napi]
@@ -118,7 +112,7 @@ impl Task for AsyncGetBuffer {
118112
type JsValue = Buffer;
119113

120114
fn compute(&mut self) -> Result<Self::Output> {
121-
self.encoder.get_buffer()
115+
self.encoder.get_buffer(self.options.clone())
122116
}
123117

124118
fn resolve(&mut self, _: Env, output: Self::Output) -> Result<Self::JsValue> {
@@ -129,6 +123,7 @@ impl Task for AsyncGetBuffer {
129123
pub struct AsyncWriteToFile {
130124
encoder: WebpEncoder,
131125
path: String,
126+
options: Option<EncoderOptions>,
132127
}
133128

134129
#[napi]
@@ -137,7 +132,8 @@ impl Task for AsyncWriteToFile {
137132
type JsValue = Buffer;
138133

139134
fn compute(&mut self) -> Result<Self::Output> {
140-
self.encoder.write_to_file(self.path.clone())
135+
self.encoder
136+
.write_to_file(self.path.clone(), self.options.clone())
141137
}
142138

143139
fn resolve(&mut self, _: Env, output: Self::Output) -> Result<Self::JsValue> {
@@ -153,28 +149,9 @@ pub struct JsWebpEncoder {
153149
#[napi]
154150
impl JsWebpEncoder {
155151
#[napi(constructor)]
156-
pub fn new(
157-
width: u32,
158-
height: u32,
159-
#[napi(ts_arg_type = "JsWebpEncoderOptions")] options: Option<JsWebpEncoderOptions>,
160-
) -> Self {
161-
let options = options.map(|options| EncoderOptions {
162-
anim_params: AnimParams {
163-
loop_count: options.loop_count.unwrap_or(0),
164-
},
165-
encoding_config: Some(EncodingConfig {
166-
encoding_type: if options.lossless.unwrap_or(true) {
167-
webp_animation::EncodingType::Lossless
168-
} else {
169-
webp_animation::EncodingType::Lossy(LossyEncodingConfig::default())
170-
},
171-
quality: options.quality.unwrap_or(1) as f32,
172-
method: options.method.unwrap_or(4) as usize,
173-
}),
174-
..Default::default()
175-
});
152+
pub fn new(width: u32, height: u32) -> Self {
176153
JsWebpEncoder {
177-
encoder: WebpEncoder::new(width, height, options),
154+
encoder: WebpEncoder::new(width, height),
178155
}
179156
}
180157

@@ -193,28 +170,50 @@ impl JsWebpEncoder {
193170
}
194171

195172
#[napi]
196-
pub fn get_buffer(&self) -> AsyncTask<AsyncGetBuffer> {
173+
pub fn get_buffer(
174+
&self,
175+
#[napi(ts_arg_type = "JsWebpEncoderOptions")] options: Option<JsWebpEncoderOptions>,
176+
) -> AsyncTask<AsyncGetBuffer> {
197177
AsyncTask::new(AsyncGetBuffer {
198178
encoder: self.encoder.clone(),
179+
options: options.map(map_js_webp_encoder_options),
199180
})
200181
}
201182

202183
#[napi]
203-
pub fn get_buffer_sync(&self) -> Result<Buffer> {
204-
Ok(self.encoder.get_buffer()?.into())
184+
pub fn get_buffer_sync(
185+
&self,
186+
#[napi(ts_arg_type = "JsWebpEncoderOptions")] options: Option<JsWebpEncoderOptions>,
187+
) -> Result<Buffer> {
188+
Ok(self
189+
.encoder
190+
.get_buffer(options.map(map_js_webp_encoder_options))?
191+
.into())
205192
}
206193

207194
#[napi]
208-
pub fn write_to_file(&self, path: String) -> AsyncTask<AsyncWriteToFile> {
195+
pub fn write_to_file(
196+
&self,
197+
path: String,
198+
#[napi(ts_arg_type = "JsWebpEncoderOptions")] options: Option<JsWebpEncoderOptions>,
199+
) -> AsyncTask<AsyncWriteToFile> {
209200
AsyncTask::new(AsyncWriteToFile {
210201
encoder: self.encoder.clone(),
211202
path,
203+
options: options.map(map_js_webp_encoder_options),
212204
})
213205
}
214206

215207
#[napi]
216-
pub fn write_to_file_sync(&self, path: String) -> Result<Buffer> {
217-
Ok(self.encoder.write_to_file(path)?.into())
208+
pub fn write_to_file_sync(
209+
&self,
210+
path: String,
211+
#[napi(ts_arg_type = "JsWebpEncoderOptions")] options: Option<JsWebpEncoderOptions>,
212+
) -> Result<Buffer> {
213+
Ok(self
214+
.encoder
215+
.write_to_file(path, options.map(map_js_webp_encoder_options))?
216+
.into())
218217
}
219218

220219
#[napi]
@@ -226,24 +225,23 @@ impl JsWebpEncoder {
226225
pub fn set_dimensions(&mut self, width: u32, height: u32) {
227226
self.encoder.set_dimensions(width, height);
228227
}
228+
}
229229

230-
#[napi]
231-
pub fn set_options(&mut self, options: JsWebpEncoderOptions) {
232-
self.encoder.set_options(EncoderOptions {
233-
anim_params: AnimParams {
234-
loop_count: options.loop_count.unwrap_or(0),
230+
fn map_js_webp_encoder_options(options: JsWebpEncoderOptions) -> EncoderOptions {
231+
EncoderOptions {
232+
anim_params: AnimParams {
233+
loop_count: options.loop_count.unwrap_or(0),
234+
},
235+
encoding_config: Some(EncodingConfig {
236+
encoding_type: if options.lossless.unwrap_or(true) {
237+
webp_animation::EncodingType::Lossless
238+
} else {
239+
webp_animation::EncodingType::Lossy(LossyEncodingConfig::default())
235240
},
236-
encoding_config: Some(EncodingConfig {
237-
encoding_type: if options.lossless.unwrap_or(true) {
238-
webp_animation::EncodingType::Lossless
239-
} else {
240-
webp_animation::EncodingType::Lossy(LossyEncodingConfig::default())
241-
},
242-
quality: options.quality.unwrap_or(1) as f32,
243-
method: options.method.unwrap_or(4) as usize,
244-
}),
245-
..Default::default()
246-
});
241+
quality: options.quality.unwrap_or(1) as f32,
242+
method: options.method.unwrap_or(4) as usize,
243+
}),
244+
..Default::default()
247245
}
248246
}
249247

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1-
import fs from 'node:fs/promises'
1+
// @ts-check
2+
23
import assert from 'node:assert'
4+
import fs from 'node:fs/promises'
5+
import { dirname } from 'node:path'
36
import test from 'node:test'
7+
import { fileURLToPath } from 'node:url'
48
import { WebpEncoder } from '../index.js'
59
import { Canvas, loadImage } from '@napi-rs/canvas'
610

7-
async function getFrames(): Promise<Buffer[]> {
8-
const frames: Buffer[] = []
11+
/** @returns {Promise<Buffer[]>} */
12+
async function getFrames() {
13+
/** @type {Buffer[]} */
14+
const frames = []
915
const ctx = new Canvas(480, 270).getContext('2d')
1016
for (let i = 1; i <= 17; i++) {
11-
const path = `${import.meta.dirname}/fixtures/frames/${i}.png`
17+
const path = `${dirname(fileURLToPath(import.meta.url))}/fixtures/frames/${i}.png`
1218
const file = await fs.readFile(path)
1319
const img = await loadImage(file)
1420
ctx.drawImage(img, 0, 0)
@@ -20,13 +26,16 @@ async function getFrames(): Promise<Buffer[]> {
2026

2127
test('encodes webp', async () => {
2228
const frames = await getFrames()
23-
const encoder = new WebpEncoder(480, 270, { lossless: false, quality: 75 })
29+
const encoder = new WebpEncoder(480, 270)
2430

2531
encoder.setFrameRate(24)
2632

2733
for (const frame of frames) {
2834
encoder.addFrame(frame)
2935
}
30-
const data = encoder.writeToFileSync('test/output/test.webp')
36+
const data = encoder.writeToFileSync(
37+
'test/output/test.webp',
38+
{ lossless: false, quality: 75 }
39+
)
3140
assert.strictEqual(data.length, 178436)
3241
})

0 commit comments

Comments
 (0)