Skip to content

Commit

Permalink
feat: support svg source in image
Browse files Browse the repository at this point in the history
  • Loading branch information
Brooooooklyn committed Jun 21, 2021
1 parent ffe3d7a commit 8df688f
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 7 deletions.
3 changes: 3 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "link-args=/NODEFAULTLIB:libcmt.lib"]

[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc-10"

Expand Down
22 changes: 22 additions & 0 deletions __test__/draw.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,28 @@ test('drawImage', async (t) => {
await snapshotImage(t)
})

test('drawImage-svg', async (t) => {
const { ctx } = t.context
const filePath = './mountain.svg'
const file = await promises.readFile(join(__dirname, filePath))
const image = new Image()
image.src = file
ctx.drawImage(image, 0, 0)
await snapshotImage(t)
})

test('drawImage-svg without width height should be empty image', async (t) => {
const { ctx, canvas } = t.context
const filePath = './mountain.svg'
const svgContent = (await promises.readFile(join(__dirname, filePath))).toString('utf-8')
const image = new Image()
image.src = Buffer.from(svgContent.replace('width="128"', '').replace('height="128"', ''))
ctx.drawImage(image, 0, 0)
const output = await canvas.png()
const outputData = png.decoders['image/png'](output)
t.deepEqual(outputData.data, Buffer.alloc(outputData.width * outputData.height * 4, 0))
})

test('ellipse', async (t) => {
const { ctx } = t.context
// Draw the ellipse
Expand Down
2 changes: 1 addition & 1 deletion __test__/mountain.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added __test__/snapshots/drawImage-svg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ fn main() {

#[cfg(target_os = "linux")]
{
println!("cargo:rustc-link-lib=static=svg");
println!("cargo:rustc-link-lib=static=skia");
println!("cargo:rustc-link-lib=static=skiac");
println!("cargo:rustc-link-lib=skparagraph");
Expand All @@ -184,6 +185,7 @@ fn main() {

#[cfg(not(target_os = "linux"))]
{
println!("cargo:rustc-link-lib=svg");
println!("cargo:rustc-link-lib=skia");
println!("cargo:rustc-link-lib=skiac");
println!("cargo:rustc-link-lib=skparagraph");
Expand Down
4 changes: 3 additions & 1 deletion scripts/build-skia.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ const GN_ARGS = [
`skia_enable_skshaper=true`,
`skia_enable_tools=false`,
`skia_enable_svg=true`,
`skia_use_expat=false`,
`skia_enable_ccpr=true`,
`skia_enable_nga=false`,
`skia_use_expat=true`,
`skia_use_gl=false`,
`skia_use_harfbuzz=true`,
`skia_pdf_subset_harfbuzz=true`,
Expand Down
19 changes: 18 additions & 1 deletion skia-c/skia_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,7 @@ extern "C"

// Bitmap

skiac_bitmap *skiac_bitmap_make_from_buffer(uint8_t *ptr, size_t size)
skiac_bitmap *skiac_bitmap_make_from_buffer(const uint8_t *ptr, size_t size)
{
auto data = SkData::MakeWithoutCopy(reinterpret_cast<const void *>(ptr), size);
auto codec = SkCodec::MakeFromData(data);
Expand All @@ -955,6 +955,23 @@ extern "C"
return reinterpret_cast<skiac_bitmap *>(bitmap);
}

skiac_bitmap *skiac_bitmap_make_from_svg(const uint8_t *data, size_t length)
{
auto svg_stream = new SkMemoryStream(data, length, false);
auto svg_dom = SkSVGDOM::MakeFromStream(*svg_stream);
auto svg_container_size = svg_dom->containerSize();
auto imageinfo = SkImageInfo::Make(svg_container_size.width(), svg_container_size.height(), kRGBA_8888_SkColorType, SkAlphaType::kOpaque_SkAlphaType);
auto bitmap = new SkBitmap();
if (imageinfo.width() == 0 || imageinfo.height() == 0)
{
return nullptr;
}
bitmap->allocPixels(imageinfo);
auto sk_svg_canvas = new SkCanvas(*bitmap);
svg_dom->render(sk_svg_canvas);
return reinterpret_cast<skiac_bitmap *>(bitmap);
}

skiac_bitmap *skiac_bitmap_make_from_image_data(uint8_t *ptr, size_t width, size_t height, size_t row_bytes, size_t size, int ct, int at)
{
auto bitmap = new SkBitmap();
Expand Down
6 changes: 5 additions & 1 deletion skia-c/skia_c.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@
#include <include/core/SkPathEffect.h>
#include <include/core/SkSurface.h>
#include <include/core/SkMaskFilter.h>
#include <include/core/SkStream.h>
#include <include/core/SkStrokeRec.h>
#include <include/effects/SkDashPathEffect.h>
#include <include/effects/SkTrimPathEffect.h>
#include <include/effects/SkGradientShader.h>
#include <include/svg/SkSVGCanvas.h>
#include <modules/skparagraph/include/FontCollection.h>
#include <modules/skparagraph/include/Paragraph.h>
#include <modules/skparagraph/include/ParagraphBuilder.h>
#include <modules/skparagraph/include/TypefaceFontProvider.h>
#include <modules/svg/include/SkSVGDOM.h>

#include <stdint.h>

Expand Down Expand Up @@ -301,7 +304,8 @@ extern "C"
void skiac_sk_data_destroy(skiac_data *c_data);

// Bitmap
skiac_bitmap *skiac_bitmap_make_from_buffer(uint8_t *ptr, size_t size);
skiac_bitmap *skiac_bitmap_make_from_buffer(const uint8_t *ptr, size_t size);
skiac_bitmap *skiac_bitmap_make_from_svg(const uint8_t *data, size_t length);
skiac_bitmap *skiac_bitmap_make_from_image_data(uint8_t *ptr, size_t width, size_t height, size_t row_bytes, size_t size, int ct, int at);
uint32_t skiac_bitmap_get_width(skiac_bitmap *c_bitmap);
uint32_t skiac_bitmap_get_height(skiac_bitmap *c_bitmap);
Expand Down
6 changes: 6 additions & 0 deletions src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,12 @@ fn draw_image(ctx: CallContext) -> Result<JsUndefined> {
let context_2d = ctx.env.unwrap::<Context>(&this)?;
let image_js = ctx.get::<JsObject>(0)?;
let image = ctx.env.unwrap::<Image>(&image_js)?;

// SVG with 0 width or 0 height
if image.bitmap.is_none() {
return ctx.env.get_undefined();
}

let image_w = image.bitmap.as_ref().unwrap().width as f32;
let image_h = image.bitmap.as_ref().unwrap().height as f32;

Expand Down
26 changes: 23 additions & 3 deletions src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,30 @@ fn set_src(ctx: CallContext) -> Result<JsUndefined> {
let image = ctx.env.unwrap::<Image>(&this)?;

let length = (&src_data).len();
let data_ref: &[u8] = &src_data;
let mut is_svg = false;
for i in 3..length {
if '<' == data_ref[i - 3] as char {
match data_ref[i - 2] as char {
'?' | '!' => break,
's' => {
is_svg = 'v' == data_ref[i - 1] as char && 'g' == data_ref[i] as char;
break;
}
_ => {
is_svg = false;
}
}
}
}
image.complete = true;
image
.bitmap
.get_or_insert(Bitmap::from_buffer(src_data.as_ptr() as *mut u8, length));
if is_svg {
image.bitmap = Bitmap::from_svg_data(src_data.as_ptr(), length);
} else {
image
.bitmap
.get_or_insert(Bitmap::from_buffer(src_data.as_ptr() as *mut u8, length));
}

this.set_named_property("_src", src_data.into_raw())?;
ctx.env.get_undefined()
Expand Down
18 changes: 18 additions & 0 deletions src/sk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,8 @@ mod ffi {

pub fn skiac_bitmap_make_from_buffer(ptr: *mut u8, size: usize) -> *mut skiac_bitmap;

pub fn skiac_bitmap_make_from_svg(data: *const u8, size: usize) -> *mut skiac_bitmap;

pub fn skiac_bitmap_make_from_image_data(
ptr: *mut u8,
width: usize,
Expand Down Expand Up @@ -2568,6 +2570,22 @@ impl Bitmap {
}
}

#[inline]
pub fn from_svg_data(data: *const u8, size: usize) -> Option<Self> {
unsafe {
let bitmap = ffi::skiac_bitmap_make_from_svg(data, size);

if bitmap.is_null() {
return None;
}
Some(Bitmap {
width: ffi::skiac_bitmap_get_width(bitmap) as usize,
height: ffi::skiac_bitmap_get_height(bitmap) as usize,
bitmap,
})
}
}

#[inline]
pub fn from_image_data(
ptr: *mut u8,
Expand Down

1 comment on commit 8df688f

@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: 8df688f Previous: a402cb2 Ratio
Draw house#@napi-rs/skia 26 ops/sec (±0.35%) 23.9 ops/sec (±1.57%) 0.92
Draw house#node-canvas 21 ops/sec (±0.56%) 23.6 ops/sec (±1.73%) 1.12
Draw gradient#@napi-rs/skia 25 ops/sec (±0.1%) 23.5 ops/sec (±1.43%) 0.94
Draw gradient#node-canvas 20 ops/sec (±0.18%) 23.1 ops/sec (±1.74%) 1.16

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

Please sign in to comment.