Code Monkey home page Code Monkey logo

skia_canvas's Introduction

Skia Canvas

Tags Doc Checks License Sponsor

Fast HTML Canvas API implementation for Deno using Skia.

Example

import { createCanvas } from "jsr:@gfx/[email protected]";

const canvas = createCanvas(300, 300);
const ctx = canvas.getContext("2d");

// Set line width
ctx.lineWidth = 10;

// 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.save("image.png");

Usage

Since this library depends on the unstable FFI API, you must pass --allow-env, --allow-ffi and --unstable-ffi flags. Without it, the module will fail to find and open native library.

deno run --allow-ffi --allow-env --unstable-ffi <file>
# or just
deno run -A --unstable-ffi <file>

API

Check the API reference here.

Since this module implements the Canvas Web API, you can also refer to the MDN docs.

Non-standard APIs

For non-standard APIs, see to the API reference mentioned above.

  • Canvas#save - save canvas render as file
  • Canvas#encode - encode render into in-memory buffer
  • Image - provides utility to load image files for drawing on canvas
  • Fonts - provides utility to manage fonts used by Skia
  • PdfDocument - create PDF documents using 2D Canvas API
  • SvgCanvas - like Canvas but creates an SVG as output instead
  • Several additional methods in Path2D object such as toSVGString, simplify, difference, xor, etc.

Benchmarks

Benchmark Results

Source: bench/main.js

Building

First you need to setup depot_tools.

Then, clone the repository with submodules.

And run the following commands:

deno task build-skia
deno task build

By default, the module will download and cache the prebuilt binaries for your platform. However this is not intended behavior when developing locally. To use locally built binaries, set DENO_SKIA_LOCAL environment variable to 1. Or you can also set DENO_SKIA_PATH to a complete path to dynamic library built from the native directory.

License

Apache-2.0 licensed.

Copyright 2022-present © DjDeveloperr

skia_canvas's People

Contributors

djdeveloperr avatar enricobuehler avatar helloyunho avatar lino-levan avatar load1n9 avatar retraigo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

skia_canvas's Issues

canvas.encode() does not work with Deno 1.40.4 or later.

This occurs when the following code is executed with Deno 1.40.4 or later.

import { createCanvas } from "https://deno.land/x/[email protected]/mod.ts"
const canvas = createCanvas(100, 100)
canvas.encode("png")

Returning this error.

error: (in promise) TypeError: getBuffer is not a function
    const buffer = new Uint8Array(getBuffer(bufptr, 0, size));
                                  ^
    at Canvas.encode (https://deno.land/x/[email protected]/src/canvas.ts:141:35)

Since Deno 1.40.4, many functions in Deno[Deno.internal].core.ops seem to be unavailable.

> Deno[Deno.internal].core.ops
{
  op_napi_open: [Function: op_napi_open],
  op_npm_process_state: [Function: op_npm_process_state],
  op_set_exit_code: [Function: op_set_exit_code],
  op_pledge_test_permissions: [Function: op_pledge_test_permissions],
  op_restore_test_permissions: [Function: op_restore_test_permissions],
  op_register_test: [Function: op_register_test],
  op_register_test_step: [Function: op_register_test_step],
  op_test_event_step_wait: [Function: op_test_event_step_wait],
  op_test_event_step_result_ok: [Function: op_test_event_step_result_ok],
  op_test_event_step_result_ignored: [Function: op_test_event_step_result_ignored],
  op_test_event_step_result_failed: [Function: op_test_event_step_result_failed],
  op_test_op_sanitizer_collect: [Function: op_test_op_sanitizer_collect],
  op_test_op_sanitizer_finish: [Function: op_test_op_sanitizer_finish],
  op_test_op_sanitizer_report: [Function: op_test_op_sanitizer_report],
  op_test_op_sanitizer_get_async_message: [Function: op_test_op_sanitizer_get_async_message]
}

PDF Document API

For creating multi-paged PDFs using canvas API. Would need a non-standard API, ideally one extending current Canvas, such as PdfCanvas

`Canvas.toDataURL` doesn't work

Canvas.toDataURL doesn't work, returning this error:

error: Uncaught (in promise) TypeError: encodeBase64 is not a function
    return `data:image/${format};base64,${encodeBase64(buffer)}`;
                                          ^
    at Canvas.toDataURL (https://deno.land/x/[email protected]/src/canvas.ts:151:43)

Using deno 1.40.1

skiaCanvas import in worker causes worker to freeze

When I import skiaCanvas in a worker, the import works but then the worker does not get messages from it's parent. Importing in the parent works fine.

Two files:
skia.js:

import * as skiaCanvas from 'https://deno.land/x/[email protected]/mod.ts'

const workerURL = new URL('./skiaWorker.js', import.meta.url).href
const worker = new Worker(workerURL, { type: 'module' })

worker.postMessage({ foo: 42 })
worker.onmessage = e => {
    console.log('main worker results', e.data)
}

skiaWorker:

// Works .. but freezes the onmessage below. Comment these out and it works
import * as skiaCanvas from 'https://deno.land/x/[email protected]/mod.ts'
console.log(Object.keys(skiaCanvas))

self.onmessage = e => {
    console.log('worker msg', e.data)

    self.postMessage(e.data)
    self.close()
}

This runs the worker with silly messages and skiaCanvas import:

deno run -A --unstable skia.js

The worker imports skiaCanvas but does not receive a message from it's parrent.

Comment out the top import/console.log and the worker runs as expected

Dependency download fails on windows

Wanted to use the library but couldn't since the folder where the dependency should be downloaded didn't exist. Creating the folder myself fixed this issue. If wanted i could also create a PR to fix this.

Can't show Japanese letters

I tried to fillText() in Japanese, but I can't.

context.font = '50px serif'

But it shows
Screenshot from 2023-04-05 21-25-32

What should I do?

[bug] `textAlign="center"` and `textAlign="right"` switched?

The issue
ctx.textAlign = "center" aligns the text to the right and "right" aligns the text to the center.

Reproducable code

import { createCanvas } from "https://deno.land/x/[email protected]/mod.ts";

const __dirname = new URL(".", import.meta.url).pathname;
const canvas = createCanvas(1253, 1080);

const ctx = canvas.getContext("2d");

ctx.moveTo(0, 0);
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.textAlign = "center"; // replace with "right"
ctx.textBaseline = "middle";

ctx.font = `100px cursive`;

ctx.shadowBlur = 0;
ctx.fillStyle = "#000000";
ctx.fillText(
  `Bottom Text`,
  canvas.width / 2,
  990,
);
canvas.save(`${__dirname}/out.png`, "png");

System
OS: Fedora Linux 36 (Workstation Edition) x86_64
Kernel: 5.19.15-201.fc36.x86_64
Deno: 1.26.2

Expected Result
out

Actual Result
out_3

skia_canvas 0.5.2 fails on Big Sur, requires Monterey

On my elderly iMac (late 2014) running Big Sur macOS 11 (November 19, 2020), skia_canvas 0.5.2 does not import correctly, creating the error below.

deno  --unstable repl -A
Deno 1.33.1
exit using ctrl+d, ctrl+c, or close()
> import * as skiaCanvas from 'https://deno.land/x/[email protected]/mod.ts'
Uncaught Error: Could not open library: Could not open library: dlopen(/Users/owen/Library/Caches/deno/plug/https/github.com/dde09b5bbcf801e9d3dbb0bf6276f9d048d6643f6b34855bc184ebffa990fd30.dylib, 5): Symbol not found: __ZNKSt3__115basic_stringbufIcNS_11char_traitsIcEENS_9allocatorIcEEE3strEv
  Referenced from: /Users/owen/Library/Caches/deno/plug/https/github.com/dde09b5bbcf801e9d3dbb0bf6276f9d048d6643f6b34855bc184ebffa990fd30.dylib (which was built for Mac OS X 12.6)
  Expected in: /usr/lib/libc++.1.dylib

    at new DynamicLibrary (ext:deno_ffi/00_ffi.js:440:46)
    at Object.dlopen (ext:deno_ffi/00_ffi.js:577:10)
    at dlopen (https://deno.land/x/[email protected]/mod.ts:145:15)
    at eventLoopTick (ext:core/01_core.js:166:11)
    at async https://deno.land/x/[email protected]/src/ffi.ts:961:10

If indeed this is generally true that Monterey (osx 12 October 25, 2021) or later is required, this seems to limit skia_canvas to a smaller community.

Could we somehow widen the systems on which skia_canvas runs?

Progress

  • Drawing rectangles
    • Context.clearRect()
    • Context.fillRect()
    • Context.strokeRect()
  • Drawing text
    • Context.fillText()
    • Context.strokeText()
    • Context.measureText()
  • Line styles
    • Context.lineWidth getter
    • Context.lineWidth setter
    • Context.lineCap getter
    • Context.lineCap setter
    • Context.lineJoin getter
    • Context.lineJoin setter
    • Context.miterLimit getter
    • Context.miterLimit setter
    • Context.getLineDash()
    • Context.setLineDash()
    • Context.lineDashOffset getter
    • Context.lineDashOffset setter
  • Text styles
    • Context.font getter
    • Context.font setter
    • Context.textAlign getter
    • Context.textAlign setter
    • Context.textBaseline getter
    • Context.textBaseline setter
    • Context.direction getter
    • Context.direction setter
    • Context.letterSpacing
    • Context.fontKerning
    • Context.fontStretch
    • Context.fontVariantCaps
    • Context.textRendering
    • Context.wordSpacing
  • Fill and stroke styles
    • Context.fillStyle getter
    • Context.fillStyle setter
    • Context.strokeStyle getter
    • Context.strokeStyle setter
  • Gradients and patterns
    • Context.createConicGradient()
    • Context.createLinearGradient()
    • Context.createRadialGradient()
    • Context.createPattern()
  • Shadows
    • Context.shadowBlur getter
    • Context.shadowBlur setter
    • Context.shadowColor getter
    • Context.shadowColor setter
    • Context.shadowOffsetX getter
    • Context.shadowOffsetX setter
    • Context.shadowOffsetY getter
    • Context.shadowOffsetY setter
  • Paths
    • Context.beginPath()
    • Context.closePath()
    • Context.moveTo()
    • Context.lineTo()
    • Context.bezierCurveTo()
    • Context.quadraticCurveTo()
    • Context.arc()
    • Context.arcTo()
    • Context.ellipse()
    • Context.rect()
    • Context.roundRect()
  • Drawing paths
    • Context.fill()
    • Context.stroke()
    • Context.drawFocusIfNeeded() (should we support it?)
    • Context.scrollPathIntoView() (should we support it?)
    • Context.clip()
    • Context.isPointInPath()
    • Context.isPointInStroke()
  • Transformations
    • Context.getTransform()
    • Context.rotate()
    • Context.scale()
    • Context.translate()
    • Context.transform()
    • Context.setTransform()
    • Context.resetTransform()
  • Compositing
    • Context.globalAlpha getter
    • Context.globalAlpha setter
    • Context.globalCompositeOperation getter
    • Context.globalCompositeOperation setter
  • Drawing images
    • Context.drawImage()
  • Pixel manipulation
    • Context.createImageData()
    • Context.getImageData()
    • Context.putImageData()
  • Image smoothing
    • Context.imageSmoothingEnabled getter
    • Context.imageSmoothingEnabled setter
    • Context.imageSmoothingQuality getter
    • Context.imageSmoothingQuality setter
  • The canvas state
    • Context.save()
    • Context.restore()
    • Context.canvas getter
    • Context.getContextAttributes()
    • Context.reset()
    • Context.isContextLost()
  • Filters
    • Context.filter

[bug] `fillText` failed with non usual latin symbols

I trying to draw text with cyrillic chars and got error.

ctx.font = '20px "Consolas"';
ctx.fillText("Ё", 50, 50);
error: Uncaught (in promise) Error: failed to fill text
      throw new Error("failed to fill text");
            ^
    at CanvasRenderingContext2D.fillText (https://deno.land/x/[email protected]/src/context2d.ts:296:13)
    at drawChar (file:///E:/programming/ts/charmap/src/main.ts:51:7)
    at file:///E:/programming/ts/charmap/src/main.ts:59:7
    at Array.forEach (<anonymous>)
    at file:///E:/programming/ts/charmap/src/main.ts:58:9
    at Array.forEach (<anonymous>)
    at drawMatrix (file:///E:/programming/ts/charmap/src/main.ts:57:10)
    at file:///E:/programming/ts/charmap/src/main.ts:37:1

I checked on other unicode symbols and seems like it only work with main EN ASCII table.
Using unicode hexcodes \u0090 also gives error.
It there any way to solve this issue?

Deno and Chrome canvas generation differ for the dataURL as well as picture size(in kilobytes)

Code.zip

The we.js file and test.html file are identical, when its coming to the calls for creating the canvas

ctx.clearRect(0, 0, 300, 300)
Fonts.register(Deno.readFileSync("C://Windows/Fonts/micross.ttf"), "Microsoft Sans Serif")
console.log(Fonts.families)
ctx.font = "10px Microsoft Sans Serif"
ctx.lineWidth = 1;
ctx.shadowColor = "rgba(0, 0, 0, 0)"
ctx.miterLimit = 10
ctx.strokeStyle = "#000000"

This part can be ignored in the we.js file, as these values are exactly like chrome uses them, we setted these values before, hoping it would fix the issue, but it didnt.

window.canvas and the canvas from deno it self have the same settings by adding this stuff, but probably somewhere its not matching for the skia part it self.

https://prnt.sc/pjG5YweCOTvC

Here again u can see the size difference

image
And in this image on the left is the browsers data url, on the right its deno. Same code, but way shorter output also resulting in a smaller file when u save the .png

More info:
Both pictures are .png
The font matches to browser
The settings we were able to access, match all

thank you for your time!

Unable to use `[email protected]` on deno main

At least as of denoland/deno@be7e2bd (and earlier), I can't import and use skia_canvas.

Example code in ffi_bug.ts:

import { createCanvas } from "https://deno.land/x/[email protected]/mod.ts";

const canvas = createCanvas(800, 250);

Running it:

➜ cargo run -- --unstable run --allow-all ffi_bug.ts
   Compiling semver v1.0.14
   Compiling napi_sym v0.50.0 (/Users/kai/code/src/github.com/denoland/deno/cli/napi/sym)
   Compiling rustc_version v0.4.0
   Compiling curve25519-dalek v4.1.1
   Compiling x25519-dalek v2.0.0
   Compiling deno_node v0.57.0 (/Users/kai/code/src/github.com/denoland/deno/ext/node)
   Compiling deno_crypto v0.134.0 (/Users/kai/code/src/github.com/denoland/deno/ext/crypto)
   Compiling deno_kv v0.28.0 (/Users/kai/code/src/github.com/denoland/deno/ext/kv)
   Compiling deno_runtime v0.128.0 (/Users/kai/code/src/github.com/denoland/deno/runtime)
   Compiling deno v1.37.1 (/Users/kai/code/src/github.com/denoland/deno/cli)
    Finished dev [unoptimized + debuginfo] target(s) in 1m 13s
     Running `target/debug/deno --unstable run --allow-all ffi_bug.ts`
error: Uncaught (in promise) TypeError: expected typed ArrayBufferView
const METRICS_PTR = Deno.UnsafePointer.of(METRICS);
                                       ^
    at Function.of (ext:deno_ffi/00_ffi.js:230:23)
    at https://deno.land/x/[email protected]/src/context2d.ts:191:40
    at eventLoopTick (ext:core/01_core.js:183:11)

Async Encoding

Just need to offload encoding to a separate thread and call with non blocking: true. It'll be useful for applications which handle concurrent requests and render images for them.

Also see: #27

Does not load on Ubuntu

This library did not work on Ubuntu 22.04, and probably other versions of Ubuntu.

import { createCanvas } from "https://deno.land/x/[email protected]/mod.ts";
Uncaught TypeError: Deno.dlopen is not a function
    at dlopen (https://deno.land/x/[email protected]/mod.ts:145:15)
    at eventLoopTick (ext:core/01_core.js:165:11)
    at async https://deno.land/x/[email protected]/src/ffi.ts:961:10

Cannot read private member #ptr from an object whose class did not declare it

I get this error below when running this simple method deep within a fairly complex project.

export function setIdentity(ctx) {
    ctx.save() 
    ctx.resetTransform() 
}
master: tests/denomodel.js 
cwd /Users/owen/Dropbox/src/agentscript
cwd /Users/owen/Dropbox/src/models
file:///Users/owen/Dropbox/src/agentscript/models/AvalancheModel.js
setIdentity ctx CanvasRenderingContext2D { canvas: Canvas {} }
error: Uncaught (in promise) TypeError: Cannot read private member #ptr from an object whose class did not declare it
    sk_context_save(this.#ptr);
                         ^
    at CanvasRenderingContext2D.save (https://deno.land/x/[email protected]/src/context2d.ts:1117:26)
    at setIdentity (file:///Users/owen/Dropbox/src/agentscript/src/domUtils.js:201:9)
    at fillCtxWithImage (file:///Users/owen/Dropbox/src/agentscript/src/domUtils.js:297:5)
    at Module.imageToCtx (file:///Users/owen/Dropbox/src/agentscript/src/domUtils.js:289:5)
    at new RGBDataSet (file:///Users/owen/Dropbox/src/agentscript/src/RGBDataSet.js:60:26)
    at Object.tileDataSet (file:///Users/owen/Dropbox/src/agentscript/src/TileData.js:45:16)
    at Object.zxyToDataSet (file:///Users/owen/Dropbox/src/agentscript/src/TileData.js:36:30)
    at eventLoopTick (ext:core/01_core.js:182:11)
    at async AvalancheModel.startup (file:///Users/owen/Dropbox/src/agentscript/models/AvalancheModel.js:24:22)
    at async Module.runModel (file:///Users/owen/Dropbox/src/agentscript/src/jsUtils.js:895:5)

The CanvasRenderingContext2D is made as shown in the docs:

const canvas = createCanvas(300, 300);
const ctx = canvas.getContext("2d");

I don't think this error is a javascript error but buried deep within skiaCanvas.

Can you think how this could happen? What the error code suggests?

Canvas creates weird pixels on border

So basically, when running this simple code:

import { createCanvas } from "https://deno.land/x/[email protected]/mod.ts";

const canvas = createCanvas(300, 300);
const ctx = canvas.getContext("2d");

// Set line width
ctx.lineWidth = 10;

// 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();

console.log(canvas.toDataURL("png", 100))

it should return a simple house, which it does, but the problem is that it also generates weird pixels on the border of the images:

how it should look like (canvas in nodejs);
1

how it looks like with this package for deno:
2

in this example you see that the top left of the image has like different colors to single pixels which is very weird (zoom to the top left to see it better)

An error related to `ImageData`

Code:

import { createCanvas, Image } from 'https://deno.land/x/[email protected]/mod.ts'

const inputFilename = 'input.jpg'
const outputFilename = 'output.png'

const image = await Image.load(inputFilename)

const canvas = createCanvas(image.width, image.height)
const ctx = canvas.getContext('2d')

ctx.drawImage(image, 0, 0)
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
ctx.putImageData(imageData, 0, 0)

canvas.save(outputFilename, 'png')

Input:
input

Output:
output

Path2D incompatability

Getting really tire of fighting incompatibilities!

If I don't reference your lib from /deps.ts in every module, I get this...

Property 'addPath' is missing in type 'import("https://deno.land/x/[email protected]/src/path2d").Path2D' but required in type 'Path2D'.deno-ts(2741)

Feels like fighting rust borrow checker.

Wasm Version

It should be possible to compile this library to Wasm and use the C API through Wasm. The wrapping code could be reused, just the loading logic would change between using Wasm and FFI. Sure, there will be some performance penalty but there are legitimate use cases such as running in a sandboxed environment such as Deno Deploy which does not support FFI but Wasm.

Also See: #22

SvgCanvas not generating <svg> close tag

It's probably something I'm doing wrong, but is there something stopping SvgCanvas from writing the closing tag here:

import { SvgCanvas } from "https://deno.land/x/[email protected]/mod.ts"

const canvas = new SvgCanvas(150, 150)
const ctx = canvas.getContext()

ctx.lineWidth = 2
ctx.strokeRect(10, 10, 120, 120)

canvas.save("./rectangles.svg") 
$ cat rectangles.svg

<?xml version="1.0" encoding="utf-8" ?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="150" height="150">
        <rect fill="none" stroke="black" stroke-width="2" stroke-miterlimit="4" x="10" y="10" width="120" height="120"/>

Any advice much appreciated. This is with Deno on macOS.

Image requires a pause before being completed

When getting an image using

let img = new skiaCanvas.Image(url)

The img is initially: Image { pending, src: undefined }
.. but after a pause it is fulfilled: Image { width: 256, height: 256 }

Here's a file, skiaimg, showing this.
You can also simply start a repl (deno repl -A --unstable) and drop all the text in it.

skiaimg:

// deno run -A --unstable skiaimg.js

import { delay } from 'https://deno.land/[email protected]/async/delay.ts'
import * as skiaCanvas from 'https://deno.land/x/[email protected]/mod.ts'
console.log('skiaCanvas', Object.keys(skiaCanvas))

const url =
'https://s3.amazonaws.com/elevation-tiles-prod/terrarium/13/1555/3084.png'

// prove url is ok
const fetched = await fetch(url).then(resp => resp.blob())
console.log('fetch test', fetched)

// use skia to get image. needs delay
let img = new skiaCanvas.Image(url)
console.log('img test', img)
await delay(1000)
console.log('img test', img)

WPT

We should run WPT tests for CanvasRenderingContext2D against this to test web compatibility and work on improving that.

GPU Backend

Ideally, this module should support GPU backend along with a windowing solution to draw directly into a canvas window.
Since Skia supports GPU natively, it shouldn't be too hard.

Benchmarks

It would be really nice to see some benchmarks in comparison with deno-canvas. If you are accepting PRs, I would love to contribute.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.