Giter VIP home page Giter VIP logo

identicon.js's People

Contributors

akhra avatar buildbreakdo avatar extend1994 avatar h0x91b avatar hai-ko avatar justerhan avatar luciditydesign avatar lukasz-karolewski avatar mitar avatar ppuleo avatar refset avatar stewartlord 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

identicon.js's Issues

Tagging Releases

Is there anyway you can start tagging releases? One of our projects relies on this library and the recent updates have caused our builds to fail unexpectedly after unrelated changes.

add bower package

Hi could you please register this as bower component? that would be really helpful.

I can create PR and do that for you, but please let me know that you would accept a PR.

Following github style

Hi @stewartlord,

Do you want to strictly follow github identicon style or are you open to pull requests which adds options to have some different behavior (colors, etc)?

Thanks

TypeError: PNGlib is not a constructor

After the most recent update (for NPM fixes) the above error now occurs. We are not using a module loading system. It seems the PNGLib is not present on window before the main library tries to use it.

Pink square for any hash

Hi,

It looks the only identicon I can generate is a pink square and I have no idea why:
identicon-issue

I can see my hash changing in page code and I have no related error in console:

<script src="/themes/Bootstrap3-custom/js/pnglib.js"></script>
<script src="/themes/Bootstrap3-custom/js/identicon.js"></script>
...
<script>
  var hash = "tg";
  var data = new Identicon(hash).toString();
  document.write('<img src="data:image/png;base64,' + data + '">');
</script>
...
<script>
  var hash = "test";
  var data = new Identicon(hash).toString();
  document.write('<img src="data:image/png;base64,' + data + '">');
</script>
...
<script>
  var hash = "maoli";
  var data = new Identicon(hash).toString();
  document.write('<img src="data:image/png;base64,' + data + '">');
</script>

Did I missed something?

EDIT

Removing the hash (var data = new Identicon().toString();) gives me correct identicons. If I use hash a put whatever value (php or not php generated) I have the pink square.

Copy-pasta replacement for ES Modules + better performance

TL;DR
If you just want some copy-pasta to get 30x performance improvement and escape the Angular CommonJS warning in your project, scroll to the end of the issue.

Hi @stewartlord,

First of all, thank you for this library. We have used it for quite a while now at my place of work to distinguish users by generating default avatars from their UUIDs. It served its purpose very well for a long time, and I must prefix any constructive criticism with my long overdue appreciation!

 _______ _    _          _   _ _  __ _____   _____     __          _______ 
 |__   __| |  | |   /\   | \ | | |/ // ____| |  __ \   /\ \        / / ____|
    | |  | |__| |  /  \  |  \| | ' /| (___   | |  | | /  \ \  /\  / / |  __ 
    | |  |  __  | / /\ \ | . ` |  <  \___ \  | |  | |/ /\ \ \/  \/ /| | |_ |
    | |  | |  | |/ ____ \| |\  | . \ ____) | | |__| / ____ \  /\  / | |__| |
    |_|  |_|  |_/_/    \_\_| \_|_|\_\_____/  |_____/_/    \_\/  \/   \_____|

It's kind of sad, but like many others, the only reason I even thought to visit this project page is because I finally got sick and tired of Angular yelling at me about CommonJS dependencies. Obviously, a tiny CommonJS library like Identicon.js is not really an issue, since there is no tree shaking to be done in the first place.

ES module usage would be nice, and so I went ahead in my usual autistic fashion and painstakingly migrated your library to TypeScript with proper class syntax and modern ES module exports...

Then I threw that code away.

While rewriting, I realized that the library does a LOT of jumping around between methods and even class/object boundaries and is kind of hard to reason about, which is a big red flag when it comes to performance because if a programmer has a hard time following the code, the optimizing JIT compiler probably also has a hard time understanding the code and therefore cannot optimize it.

Although I have a long history of being an arrogant a**hole and talking down to people, this is intended to be a constructive issue so I have whipped up some numbers for you and also some copy-pasta code that people could paste into their own projects if you would be so kind as to pin this issue (I am too busy/lazy to go make a proper NPM package right now, and I already spent a couple hours on this).

Now to the numbers. First, here is my testing code that I simply dumped in the middle of a REST API call in my project where I would have easy access to lots of hexadecimal UUIDs for use as seeds. I also peppered in some array copying with intermittent strings to make sure the JavaScript optimizer doesn't try anything fancy (i.e., remove any code) that would mess up the performance test.

let seeds: string[] = [];

// allMembers is a list of membership objects from a REST API in my project, but you could substitute
// some random seed generation code and make a big array of your own seeds if you don't trust me
// and want to test yourself
for (const { id, userID, projectID } of allMembers) {
    seeds.push(id, userID, projectID);
}

// Make sure to confuse the JIT lol (the strcmp at the end is a function for sorting alphabetically
seeds = [...seeds, "0adf9940-b117-4e6c-82ad-4a345024621d", ...seeds, ...seeds, "0adf9940-b117-4e6c-82ad-4a345024621d", ...seeds].sort(strcmp);

const identicons: string[] = [];
const start = performance.now();

for (const seed of seeds) {
    identicons.push(

        // My copy-pasta replacement for your library
        genIdenticonSVG(seed, {
            margin: 0.2,
            size: 64,
            background: [255, 255, 255, 255],
        }),

        // Your library, without any tampering or funny business
        // (new Identicon(seed, {
        //     margin: 0.2,
        //     size: 64,
        //     background: [255, 255, 255, 255],
        // })).toString(),

    );
}

console.log(identicons);
console.log(`Took ${Math.floor(performance.now() - start)}ms to produce ${identicons.length} identicons!`);

Okay, so now that we have the testing code out of the way, let's take a look at the numbers!

With my genIdenticonSVG function

image

With the Identicon.js library

image

I spam refreshed the memberships table in my app to re-run the API call and thus the test. With my function, the test generally took between 22 and 35 milliseconds. It never reached 40 ms. With the Identicon.js library, it always took at least 1300 ms. That means over a 30x performance improvement, at least on my computer.

So how did I do it? By simplifying the code in an OCD, straightforward manner. Any time I call the Identicon constructor, it is never to do anything other than immediately call toString()--there is no reason to have an Identicon class in the first place. Browsers put in a great deal of work to optimize object property lookups (even on class-based objects) because technically every JS object must behave like a hashmap and can change at any time. When you put everything into a single function scope with const number/string variables and whatnot, and put all the loops and code right there next to each other, it becomes

  1. much easier to read
  2. much easier for the browser to optimize (variable declarations can't change and it can more easily inline code inside the loops)

I also store rectangles as arrays/tuples ([x, y, width, height, color]) because, once again, object properties make JS engines suffer while array indexing is much easier for them to make guarantees about and thus optimize.

Now, there are a couple caveats to my code:

  1. I don't support PNG

    I would recommend a simple function like I have to generate the rectangles, and then have separate SVG and PNG functions which both internally call the function to get the rectangles and then do their thing with them because mixing in the { index(); getDump(); toString() } interface into the business code is part of what hurts the performance so much in the first place because it introduces a bunch of dynamic code into an otherwise low-level function

  2. I use btoa without a polyfill because I have the privilege of telling users not to use Internet Explorer and I only use the code in a frontend application so no need for Node support
  3. I do not have the same interface as your code, and I do not have the energy to make a proper PR to bring your library and the PNGlib code (which suffers similar performance problems) up-to-date

Copy-pasta re-implementation of the library (SVG only)

At long last, here is the code. It could still use some further cleanup and perf improvements, but I figure it is good enough for now. If I publish it as a library on NPM in the future, I will probably include PNG support and I will make sure to credit you and the people credited in your code (good on you for those big comments pointing to other programmers!) so that I am contributing to open source rather than stealing.

People can easily make this faster by simply removing the options and hard-coding the values they want to use for margin, saturation, etc. If you do need to use different options with this copy-pasta garbage, you could at least generate a fill-out options object once and pass that so you don't need to run the default (??) value code every time you generate an identicon with the exact same options.

// adapted from: https://gist.github.com/aemkei/1325937
function hsl2rgb(h: number, s: number, b: number): [number, number, number] {
    h *= 6;

    const lookup: readonly number[] = [
        b += s *= b < .5 ? b : 1 - b,
        b - h % 1 * s * 2,
        b -= s *= 2,
        b,
        b + h % 1 * s,
        b + s
    ];

    return[
        lookup[ ~~h    % 6 ] * 255, // red
        lookup[ (h|16) % 6 ] * 255, // green
        lookup[ (h|8)  % 6 ] * 255  // blue
    ];
}

/**
 * Create a CSS color string, such as "rgba(255, 122, 37, 0.6)" from number inputs. Red,
 * green, and blue values will be floored to integers. The alpha value will be normalized
 * automatically so you can pass a decimal in the range [0, 1] OR you can pass an integer
 * in the range [0, 255].
 */
function cssColor(r: number, g: number, b: number, a: number): string {
    const int = Math.floor;
    return `rgba(${int(r)},${int(g)},${int(b)},${(a >= 0) && (a <= 255) ? a/255 : 1})`;
}

export interface Options {
    /**
     * The background color, as an RGBA tuple. The red, green, and blue values
     * should be integers in the range [0, 255] while the alpha (last number)
     * can also be an integer in that range or can be normalized to the [0, 1]
     * range (in which case it would be a decimal).
     */
    background?: [number, number, number, number];
    /**
     * Decimal margin to determine spacing between rectangles. Defaults to 0.08.
     */
    margin?: number;
    /**
     * Width and height, in pixels, of the generated SVG viewport. Defaults to 64.
     */
    size?: number;
    /**
     * Do you like color? I like color. Defaults to 0.7.
     */
    saturation?: number;
    /**
     * How bright should the computed foreground color be? Defaults to 0.5.
     */
    brightness?: number;
}

/**
 * This code was produced by simplifying/optimizing the code from Identicon.js 2.3.3
 * http://github.com/stewartlord/identicon.js
 *
 * Copyright 2018, Stewart Lord <https://github.com/stewartlord>
 * Released under the BSD license
 * http://www.opensource.org/licenses/bsd-license.php
 * 
 * Also credit to me (Sam Claus <https://github.com/samclaus>) for the rewrite/optimization.
 */
export function genIdenticonSVG(hash: string, options: Partial<Options> = {}): string {
    if (hash.length < 15) {
        throw new Error("hash for identicon must be at least 15 characters");
    }

    const bg = cssColor(...(options.background ?? [240, 240, 240, 255]));
    const size = options.size ?? 64;
    const baseMargin = Math.floor(size * (options.margin ?? 0.08));
    const saturation = options.saturation ?? 0.7;
    const brightness = options.brightness ?? 0.5;

    // foreground defaults to last 7 chars as hue at 70% saturation, 50% brightness
    const hue = parseInt(hash.substr(-7), 16) / 0xfffffff;
    const fg = cssColor(...hsl2rgb(hue, saturation, brightness), 255);
    const cell = Math.floor((size - (baseMargin * 2)) / 5);
    const margin = Math.floor((size - cell * 5) / 2);

    // X, Y, width, height, color for each rectangle
    const rectangles: [number, number, number, number, string][] = [];

    // the first 15 characters of the hash control the pixels (even/odd)
    // they are drawn down the middle first, then mirrored outwards
    for (let i = 0; i < 15; i++) {
        const color = parseInt(hash.charAt(i), 16) % 2 ? bg : fg;

        if (i < 5) {
            rectangles.push([2 * cell + margin, i * cell + margin, cell, cell, color]);
        } else if (i < 10) {
            rectangles.push([1 * cell + margin, (i - 5) * cell + margin, cell, cell, color]);
            rectangles.push([3 * cell + margin, (i - 5) * cell + margin, cell, cell, color]);
        } else if (i < 15) {
            rectangles.push([0 * cell + margin, (i - 10) * cell + margin, cell, cell, color]);
            rectangles.push([4 * cell + margin, (i - 10) * cell + margin, cell, cell, color]);
        }
    }

    const stroke = size * 0.005;

    let xml = `<svg xmlns='http://www.w3.org/2000/svg' width='${size}' height='${size}' style='background-color:${bg};'><g style='fill:${fg}; stroke:${fg}; stroke-width:${stroke};'>`;

    for (const [x, y, w, h, color] of rectangles) {
        if (color !== bg) {
            xml += `<rect x='${x}' y='${y}' width='${w}' height='${h}'/>`;
        }
    }

    xml += "</g></svg>"

    return btoa(xml);
}

Generate hash instead of throw

Bit by some bad data (totally my fault), what was returned from the API was not a string and this line ended up crashing the app out. If a throw is present, means users have to wrap any call to this API in a try-catch; this is not explicitly mentioned anywhere. Likely best to avoid identicon generation failures generating 500/server errors, if it was a critical portion of an app, then may be a different conclusion.

What are thoughts around generating the hash if it is not present and extending the string to 15 chars if length < 15? More defensive approach.

        if (typeof(hash) !== 'string' || hash.length < 15) {
            throw 'A hash of at least 15 characters is required.';
        }

Largely Unmaintained

This project is largely unmaintained. If anyone would like to support a fork I would be happy to link to it from the README on this repo or otherwise handoff maintenance.

HSB/HSV vs HSL, Brightness vs Lightness

This is a very minor issue, which depending on the change could be breaking. However I figured I'd at least document it in the issues list.

The parameters for the library are saturation and brightness with the hue being adjusted. The issue is that HSL (Hue, Saturation, Lightness) is being used not HSB/HSV (Hue, Saturation, Brightness/Value) (HSV == HSB, HSV != HSL, HSB != HSL).

Therefore I suggest renaming the brightness parameter to lightness.

The reason I ran into this issue was I was porting the colour extraction algorithm to python. I wasn't sure if HSL was being used or HSB. As the function call was hsl(h,s,b) with a note stating that it had been adapted from else where (Maybe it was adapted to HSB but they forgot to rename etc).

To make matters worst python doesn't have a built-in HSB function, it does have one for HSV (Which is the same thing). And to add to that the python function is for HLS as opposed HSL.

So far the above comments revolve around it being confusing to read the code / port. However It also has a real impact on users of the library. I may have selected a saturation and brightness value from photoshop or http://colorizer.org, that I like. However the library is actually using HSL not HSB/HSV therefore I would be getting different colours than I expected.

I can raise PR if requested, but like I said, I just wanted to document this incase somebody else ran into it.

Setting margin to 0 does not work

Margin settings are not being parsed correctly. Assume it is because 0 is evaluated as a falsey value thus letting the .2 default take over, 0.000001 does indeed work.

{
        size: 40,
        margin: 0,
        background: [250, 250, 250, 255],
        format: 'svg'
}

OSX: ../src/JPEGStream.h:10:10: fatal error: 'jpeglib.h' file not found

$ npm install identicon --save

> [email protected] install /Users/anon/Desktop/dev/pholder/node_modules/canvas
> node-gyp rebuild

  SOLINK_MODULE(target) Release/canvas-postbuild.node
  CXX(target) Release/obj.target/canvas/src/Canvas.o
In file included from ../src/Canvas.cc:20:
../src/JPEGStream.h:10:10: fatal error: 'jpeglib.h' file not found
#include <jpeglib.h>
         ^
1 error generated.
make: *** [Release/obj.target/canvas/src/Canvas.o] Error 1
gyp ERR! build error 

ES module support

Hi @stewartlord ,

Thanks for the handy library, any chance you can make it importable as an ECMAScript module? Angular, for example, complains about CommonJS or AMD dependencies:

[1] WARNING in /Users/nunoarruda/repos/Pulse-Angular/src/app/profiles/profile-list/profile-list.component.ts depends on 'identicon.js'. CommonJS or AMD dependencies can cause optimization bailouts.
[1] For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

Here's why: https://angular.io/guide/build#configuring-commonjs-dependencies

Synchronous image generation and performance

The Identicon.toString() method is synchronous.
Generating an image in node may be an expensive action. This may lead to blocking code.

Is there any performance issue when generating images of size i.e. 512*512px? Does any benchmark exist?

I wonder what would be the performance impact if the image was generated on a server dynamically on every request.

I hope the question is clear and good enough for GitHub issues. Otherwise please kindly ask or redirect me to a proper place.

Foreground color producing no identicon.

I've been trying to generate an identicon, passing [255, 69, 0, 1] as the rgba color (it's #ff4500), but the produced identicon files don't have any identicon. I tried with black as per the documentation, and it worked.

  • Node.js: 12.14 (Docker on Mac)
  • Identicon library: 2.3.3

Thanks in advance! And thanks for a great library ๐Ÿ™

Can't this work on the server?

I use the same example code from identicon.js' homepage:

// set up options
var hash = "c157a79031e1c40f85931829bc5fc552";  // 15+ hex chars
var options = {
      foreground: [0, 0, 0, 255],               // rgba black
      background: [255, 255, 255, 255],         // rgba white
      margin: 0.2,                              // 20% margin
      size: 420,                                // 420px square
      format: 'svg'                             // use SVG instead of PNG
    };
 
// create a base64 encoded SVG
var data = new Identicon(hash, options).toString();

console.log(data);

It works fine in the browser like this:

PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSc0MjAnIGhlaWdodD0nNDIwJyBzdHlsZT0nYmFja2dyb3VuZC1jb2xvcjpyZ2JhKDI1NSwyNTUsMjU1LDEpOyc+PGcgc3R5bGU9J2ZpbGw6cmdiYSgwLDAsMCwxKTsgc3Ryb2tlOnJnYmEoMCwwLDAsMSk7IHN0cm9rZS13aWR0aDoyLjE7Jz48cmVjdCAgeD0nMTg1JyB5PSc4NScgd2lkdGg9JzUwJyBoZWlnaHQ9JzUwJy8+PHJlY3QgIHg9JzE4NScgeT0nMjg1JyB3aWR0aD0nNTAnIGhlaWdodD0nNTAnLz48cmVjdCAgeD0nMTM1JyB5PScxODUnIHdpZHRoPSc1MCcgaGVpZ2h0PSc1MCcvPjxyZWN0ICB4PScyMzUnIHk9JzE4NScgd2lkdGg9JzUwJyBoZWlnaHQ9JzUwJy8+PHJlY3QgIHg9Jzg1JyB5PSc4NScgd2lkdGg9JzUwJyBoZWlnaHQ9JzUwJy8+PHJlY3QgIHg9JzI4NScgeT0nODUnIHdpZHRoPSc1MCcgaGVpZ2h0PSc1MCcvPjxyZWN0ICB4PSc4NScgeT0nMTg1JyB3aWR0aD0nNTAnIGhlaWdodD0nNTAnLz48cmVjdCAgeD0nMjg1JyB5PScxODUnIHdpZHRoPSc1MCcgaGVpZ2h0PSc1MCcvPjxyZWN0ICB4PSc4NScgeT0nMjM1JyB3aWR0aD0nNTAnIGhlaWdodD0nNTAnLz48cmVjdCAgeD0nMjg1JyB5PScyMzUnIHdpZHRoPSc1MCcgaGVpZ2h0PSc1MCcvPjxyZWN0ICB4PSc4NScgeT0nMjg1JyB3aWR0aD0nNTAnIGhlaWdodD0nNTAnLz48cmVjdCAgeD0nMjg1JyB5PScyODUnIHdpZHRoPSc1MCcgaGVpZ2h0PSc1MCcvPjwvZz48L3N2Zz4=

but, emm..... Unexpected results on the server side like this:

iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAADAFBMVEXw8PDYACYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADByinnAAABAHRSTlP//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmfXxgAAAHlJREFUeNoBbgCR/wAAAAEBAQEBAQAAAAAAAQEBAQEBAAAAAQEBAQEBAQEBAQABAQEBAQEBAQEBAAEBAQEAAAEBAQEAAQEBAQAAAQEBAQAAAAAAAQEAAAAAAAAAAAABAQAAAAAAAQEBAQAAAQEBAQABAQEBAAABAQEBD7oARe51XwsAAAAASUVORK5CYII=

What happend?

Probably don't want base64 svg

@stewartlord Just looking to cut down on memory footprint here, is there any way to not have a base64 version for SVG? According to Chris Coyier here: https://css-tricks.com/probably-dont-base64-svg/ we don't need to base64 svg, unnecessarily comes out 133% bigger.

Is it currently possible to generate just SVG? Tried browsing around the source and using .render() instead of .toString() -- since I see .toString() is just .render().getBase64() -- but that did not work.

Canvas or SVG implementation

Creating PNG images may not be such an up-to-date implementation. Do you know an implementation, which e.g. uses SVG or HTML5 canvas to show the image?

Or would you always choose this PNG implementation? If so, why?

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.