Skip to content

Commit

Permalink
feat: support gradient in fill/stroke style
Browse files Browse the repository at this point in the history
  • Loading branch information
Brooooooklyn committed Dec 25, 2020
1 parent 99ef1cd commit 12e061c
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 56 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ crate-type = ["cdylib"]
[dependencies]
anyhow = "1"
cssparser = "0.28"
napi = "1.0.0-alpha.7"
napi = "1.0.0-alpha.9"
napi-derive = "1.0.0-alpha.0"
thiserror = "1"

Expand Down
51 changes: 3 additions & 48 deletions benchmark/bench.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,13 @@
import { promises as fs } from 'fs'
import { join } from 'path'

import b from 'benny'
import { Summary } from 'benny/lib/internal/common-types'
import { createCanvas, Canvas } from 'canvas'

import { createCanvas as skiaCreateCanvas } from '../index'

function draw(factory: (width: number, height: number) => Canvas) {
const canvas = factory(1024, 768)

const ctx = canvas.getContext('2d')!

ctx.lineWidth = 10
ctx.strokeStyle = '#03a9f4'
ctx.fillStyle = '#03a9f4'

// Wall
ctx.strokeRect(75, 140, 150, 110)

// Door
ctx.fillRect(130, 190, 40, 60)

// Roof
ctx.beginPath()
ctx.moveTo(50, 140)
ctx.lineTo(150, 60)
ctx.lineTo(250, 140)
ctx.closePath()
ctx.stroke()

canvas.toBuffer('image/png')
}

function house() {
return b.suite(
'Draw house',

b.add('@napi-rs/skia', () => {
// @ts-expect-error
draw(skiaCreateCanvas)
}),

b.add('node-canvas', () => {
draw(createCanvas)
}),

b.cycle(),
b.complete(),
)
}
import { house } from './house'
import { gradient } from './gradient'

async function run() {
const output = [await house()].map(formatSummary).join('\n')
const output = [await house(), await gradient()].map(formatSummary).join('\n')
await fs.writeFile(join(process.cwd(), 'bench.txt'), output, 'utf8')
}

Expand Down
42 changes: 42 additions & 0 deletions benchmark/gradient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import b from 'benny'

import { createCanvas, Canvas } from 'canvas'

import { createCanvas as skiaCreateCanvas } from '../index'

function drawGradient(factory: (width: number, height: number) => Canvas) {
const canvas = factory(1024, 768)

const ctx = canvas.getContext('2d')!

const gradient = ctx.createLinearGradient(20, 0, 220, 0)

// Add three color stops
gradient.addColorStop(0, 'green')
gradient.addColorStop(0.5, 'cyan')
gradient.addColorStop(1, 'green')

// Set the fill style and draw a rectangle
ctx.fillStyle = gradient
ctx.fillRect(20, 20, 200, 100)

canvas.toBuffer('image/png')
}

export function gradient() {
return b.suite(
'Draw gradient',

b.add('@napi-rs/skia', () => {
// @ts-expect-error
drawGradient(skiaCreateCanvas)
}),

b.add('node-canvas', () => {
drawGradient(createCanvas)
}),

b.cycle(),
b.complete(),
)
}
49 changes: 49 additions & 0 deletions benchmark/house.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import b from 'benny'

import { createCanvas, Canvas } from 'canvas'

import { createCanvas as skiaCreateCanvas } from '../index'

function drawHouse(factory: (width: number, height: number) => Canvas) {
const canvas = factory(1024, 768)

const ctx = canvas.getContext('2d')!

ctx.lineWidth = 10
ctx.strokeStyle = '#03a9f4'
ctx.fillStyle = '#03a9f4'

// Wall
ctx.strokeRect(75, 140, 150, 110)

// Door
ctx.fillRect(130, 190, 40, 60)

// Roof
ctx.beginPath()
ctx.moveTo(50, 140)
ctx.lineTo(150, 60)
ctx.lineTo(250, 140)
ctx.closePath()
ctx.stroke()

canvas.toBuffer('image/png')
}

export function house() {
return b.suite(
'Draw house',

b.add('@napi-rs/skia', () => {
// @ts-expect-error
drawHouse(skiaCreateCanvas)
}),

b.add('node-canvas', () => {
drawHouse(createCanvas)
}),

b.cycle(),
b.complete(),
)
}
26 changes: 26 additions & 0 deletions example/gradient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const { promises } = require('fs')
const { join } = require('path')

const { createCanvas } = require('../index')

const canvas = createCanvas(1024, 768)

const ctx = canvas.getContext('2d')

const gradient = ctx.createLinearGradient(20, 0, 220, 0)

// Add three color stops
gradient.addColorStop(0, 'green')
gradient.addColorStop(0.5, 'cyan')
gradient.addColorStop(1, 'green')

// Set the fill style and draw a rectangle
ctx.fillStyle = gradient
ctx.fillRect(20, 20, 200, 100)

canvas
.png()
.then((data) => promises.writeFile(join(__dirname, 'gradient.png'), data))
.catch((e) => {
console.error(e)
})
17 changes: 12 additions & 5 deletions src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1060,13 +1060,15 @@ fn set_fill_style(ctx: CallContext) -> Result<JsUndefined> {
match js_fill_style.get_type()? {
ValueType::String => {
let js_color =
unsafe { JsString::from_raw_unchecked(ctx.env.raw(), js_fill_style.raw()) }.into_utf8()?;
unsafe { js_fill_style.cast::<JsString>() }.into_utf8()?;
context_2d.set_fill_style(Pattern::from_color(js_color.as_str()?)?)?;
}
// TODO, image and gradient
ValueType::External => {
todo!();
ValueType::Object => {
let fill_object = unsafe { js_fill_style.cast::<JsObject>() };
let gradient = ctx.env.unwrap::<CanvasGradient>(&fill_object)?;
context_2d.set_fill_style(Pattern::Gradient(gradient.clone()));
}
// todo ImagePattern
_ => return Err(Error::new(Status::InvalidArg, format!("Invalid fillStyle"))),
}

Expand Down Expand Up @@ -1094,7 +1096,12 @@ fn set_stroke_style(ctx: CallContext) -> Result<JsUndefined> {
.into_utf8()?;
context_2d.set_stroke_style(Pattern::from_color(js_color.as_str()?)?)?;
}
// TODO, image and gradient
ValueType::Object => {
let stroke_object = unsafe { js_stroke_style.cast::<JsObject>() };
let gradient = ctx.env.unwrap::<CanvasGradient>(&stroke_object)?;
context_2d.set_stroke_style(Pattern::Gradient(gradient.clone()));
}
// todo ImagePattern
ValueType::External => {}
_ => {
return Err(Error::new(
Expand Down
4 changes: 2 additions & 2 deletions src/sk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1597,8 +1597,8 @@ impl Transform {
let x_trans = self.a * x + self.b * y + self.c;
// Dx+Ey+F
let y_trans = self.d * x + self.e * y + self.e;
result_arr[i] = x_trans / denom;
result_arr[i + 1] = y_trans / denom;
result_arr.push(x_trans / denom);
result_arr.push(y_trans / denom);
i += 2;
}
result_arr
Expand Down

1 comment on commit 12e061c

@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: 12e061c Previous: 99ef1cd Ratio
Draw house#@napi-rs/skia 21 ops/sec (±0.47%) 21 ops/sec (±0.81%) 1
Draw house#node-canvas 20 ops/sec (±0.41%) 19 ops/sec (±1.73%) 0.95
Draw gradient#@napi-rs/skia 20 ops/sec (±1.45%)
Draw gradient#node-canvas 19 ops/sec (±0.9%)

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

Please sign in to comment.