Skip to content

Commit

Permalink
feat: avif removes the alphaQuality option and uses internal calculat…
Browse files Browse the repository at this point in the history
…ions
  • Loading branch information
yisibl committed Oct 25, 2021
1 parent fdefa5d commit 8de6e95
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 37 deletions.
14 changes: 13 additions & 1 deletion __test__/draw.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ test('toDataURL', async (t) => {
t.deepEqual(pngBuffer, await canvas.encode('png'))
})

test('toDataURL with quality', async (t) => {
test('JPEG toDataURL with quality', async (t) => {
const { ctx, canvas } = t.context
drawTranslate(ctx)

Expand All @@ -928,6 +928,18 @@ test('toDataURL with quality', async (t) => {
t.deepEqual(pngBuffer, await canvas.encode('jpeg', 20))
})

test('WebP toDataURL with quality', async (t) => {
const { ctx, canvas } = t.context
drawTranslate(ctx)

const output = canvas.toDataURL('image/webp', 100)
const prefix = 'data:image/webp;base64,'
t.true(output.startsWith(prefix))
const imageBase64 = output.substr(prefix.length)
const pngBuffer = Buffer.from(imageBase64, 'base64')
t.deepEqual(pngBuffer, await canvas.encode('webp', 100))
})

test('toDataURLAsync', async (t) => {
const { ctx, canvas } = t.context
drawTranslate(ctx)
Expand Down
Binary file modified example/anime-girl.avif
Binary file not shown.
5 changes: 4 additions & 1 deletion example/anime-girl.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ async function main() {
await fs.writeFile(join(__dirname, 'anime-girl.png'), pngData)
const t1 = performance.now()

const avifData = await canvas.encode('avif')
const avifData = await canvas.encode('avif', {
quality: 79,
speed: 5,
})
await fs.writeFile(join(__dirname, 'anime-girl.avif'), avifData)

const t2 = performance.now()
Expand Down
1 change: 0 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,6 @@ export interface SvgCanvas {

export interface AvifConfig {
quality?: number
alphaQuality?: number
speed?: number
threads?: number
}
Expand Down
40 changes: 20 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,16 +221,28 @@ function createCanvas(width, height, flag) {
toDataURLAsync: canvasToDataURLAsync,
} = Object.getPrototypeOf(canvasElement)

// See also: https://github.com/kornelski/cavif-rs#usage
const avifDefaultQuality = 80
const avifConfig = {
// Quality from 1 (worst) to 100 (best), the default value is 80. The numbers have different meaning than JPEG's quality scale. Beware when comparing codecs. There is no lossless compression support.
quality: avifDefaultQuality,

// Calculate alphaQuality, this is consistent with cavif.
// https://github.com/kornelski/cavif-rs/blob/37847b95bb81d4cf90e36b7fab2c7fbbcf95abe2/src/main.rs#L97
alphaQuality: Math.min((avifDefaultQuality + 100) / 2, avifDefaultQuality + avifDefaultQuality / 4 + 2),
threads: 0,

// Encoding speed between 1 (best, but slowest) and 10 (fastest, but a blurry mess), the default value is 4. Speeds 1 and 2 are unbelievably slow, but make files ~3-5% smaller. Speeds 7 and above degrade compression significantly, and are not recommended.
speed: 4,
}

canvasElement.encode = function encode(type, qualityOrConfig) {
if (type === 'avif') {
return canvasEncode.call(
this,
type,
JSON.stringify({
quality: 80,
alphaQuality: 92,
threads: 0,
speed: 4,
...avifConfig,
...(qualityOrConfig || {}),
}),
)
Expand All @@ -244,10 +256,7 @@ function createCanvas(width, height, flag) {
this,
type,
JSON.stringify({
quality: 80,
alphaQuality: 92,
threads: 0,
speed: 4,
...avifConfig,
...(qualityOrConfig || {}),
}),
)
Expand All @@ -261,10 +270,7 @@ function createCanvas(width, height, flag) {
this,
type,
JSON.stringify({
quality: 80,
alphaQuality: 92,
threads: 0,
speed: 4,
...avifConfig,
...(qualityOrConfig || {}),
}),
)
Expand All @@ -278,10 +284,7 @@ function createCanvas(width, height, flag) {
this,
type,
JSON.stringify({
quality: 80,
alphaQuality: 92,
threads: 0,
speed: 4,
...avifConfig,
...(qualityOrConfig || {}),
}),
)
Expand All @@ -295,10 +298,7 @@ function createCanvas(width, height, flag) {
this,
type,
JSON.stringify({
quality: 80,
alphaQuality: 92,
threads: 0,
speed: 4,
...avifConfig,
...(qualityOrConfig || {}),
}),
)
Expand Down
5 changes: 2 additions & 3 deletions src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2135,8 +2135,6 @@ fn get_text_baseline(ctx: CallContext) -> Result<JsString> {
#[derive(Debug, Clone, Copy, PartialEq, Deserialize)]
pub struct AVIFConfig {
pub quality: f32,
#[serde(rename = "alphaQuality")]
pub alpha_quality: f32,
pub speed: u8,
pub threads: u8,
}
Expand Down Expand Up @@ -2208,7 +2206,8 @@ impl Task for ContextData {
),
&ravif::Config {
quality: config.quality,
alpha_quality: config.alpha_quality,
alpha_quality: ((config.quality + 100.) / 2.)
.min(config.quality + config.quality / 4. + 2.),
speed: config.speed,
premultiplied_alpha: false,
threads: 0,
Expand Down
31 changes: 20 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ fn encode_sync(ctx: CallContext) -> Result<JsBuffer> {
),
&ravif::Config {
quality: config.quality,
alpha_quality: config.alpha_quality,
alpha_quality: ((config.quality + 100.) / 2.)
.min(config.quality + config.quality / 4. + 2.),
speed: config.speed,
premultiplied_alpha: false,
threads: 0,
Expand Down Expand Up @@ -280,10 +281,13 @@ fn encode_sync(ctx: CallContext) -> Result<JsBuffer> {
fn to_buffer(ctx: CallContext) -> Result<JsBuffer> {
let mime_js = ctx.get::<JsString>(0)?.into_utf8()?;
let mime = mime_js.as_str()?;
let quality = if ctx.length < 2 {
DEFAULT_JPEG_QUALITY
} else {
let quality = if mime != MIME_AVIF {
ctx.get::<JsNumber>(1)?.get_uint32()? as u8
} else if mime == MIME_WEBP {
DEFAULT_WEBP_QUALITY
} else {
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL
DEFAULT_JPEG_QUALITY
};

let context_data = get_data_ref(&ctx, mime, quality)?;
Expand Down Expand Up @@ -332,11 +336,13 @@ fn data(ctx: CallContext) -> Result<JsBuffer> {
fn to_data_url(ctx: CallContext) -> Result<JsString> {
let mime_js = ctx.get::<JsString>(0)?.into_utf8()?;
let mime = mime_js.as_str()?;
let quality = if ctx.length < 2 {
let quality = if mime != MIME_AVIF {
ctx.get::<JsNumber>(1)?.get_uint32()? as u8
} else if mime == MIME_WEBP {
DEFAULT_WEBP_QUALITY
} else {
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL
DEFAULT_JPEG_QUALITY
} else {
ctx.get::<JsNumber>(1)?.get_uint32()? as u8
};
let data_ref = get_data_ref(&ctx, mime, quality)?;
let mut output = format!("data:{};base64,", &mime);
Expand All @@ -355,11 +361,13 @@ fn to_data_url(ctx: CallContext) -> Result<JsString> {
fn to_data_url_async(ctx: CallContext) -> Result<JsObject> {
let mime_js = ctx.get::<JsString>(0)?.into_utf8()?;
let mime = mime_js.as_str()?;
let quality = if ctx.length < 2 {
let quality = if mime != MIME_AVIF {
ctx.get::<JsNumber>(1)?.get_uint32()? as u8
} else if mime == MIME_WEBP {
DEFAULT_WEBP_QUALITY
} else {
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL
DEFAULT_JPEG_QUALITY
} else {
ctx.get::<JsNumber>(1)?.get_uint32()? as u8
};
let data_ref = get_data_ref(&ctx, mime, quality)?;
let async_task = AsyncDataUrl {
Expand Down Expand Up @@ -414,7 +422,8 @@ fn get_data_ref(ctx: &CallContext, mime: &str, quality: u8) -> Result<ContextOut
),
&ravif::Config {
quality: config.quality,
alpha_quality: config.alpha_quality,
alpha_quality: ((config.quality + 100.) / 2.)
.min(config.quality + config.quality / 4. + 2.),
speed: config.speed,
premultiplied_alpha: false,
threads: 0,
Expand Down

1 comment on commit 8de6e95

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 8de6e95 Previous: ae55276 Ratio
Draw house#skia-canvas 22 ops/sec (±0.72%) 22 ops/sec (±0.4%) 1
Draw house#node-canvas 18 ops/sec (±0.29%) 18 ops/sec (±0.37%) 1
Draw house#@napi-rs/skia 21 ops/sec (±0.86%) 20 ops/sec (±0.93%) 0.95
Draw gradient#skia-canvas 22 ops/sec (±0.6%) 21 ops/sec (±0.2%) 0.95
Draw gradient#node-canvas 18 ops/sec (±1%) 17 ops/sec (±0.13%) 0.94
Draw gradient#@napi-rs/skia 21 ops/sec (±1.05%) 19 ops/sec (±0.71%) 0.90

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.