GithubHelp home page GithubHelp logo

foliojs / png.js Goto Github PK

View Code? Open in Web Editor NEW
490.0 490.0 92.0 2.37 MB

A (animated) PNG decoder in JavaScript for the HTML5 canvas element and Node.js

Home Page: http://devongovett.github.com/png.js

License: MIT License

JavaScript 97.47% HTML 2.53%

png.js's People

Contributors

acruikshank avatar blikblum avatar dependabot[bot] avatar devongovett avatar jbuck avatar meltingice 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  avatar  avatar  avatar  avatar  avatar  avatar

png.js's Issues

decoded pixels giving black image

decoded pixels giving black image of a white background with black text written on it. Attaching the image which fails in decoding.
any help much appreciated
testing_bg

How to outuput the pixels value as an RGB array instead of Buffer.

Hi,

I tried the decoding function in Node JS. When I loged, I got a Buffer instead of the expected array of pixels RGB values. How can I get an RGB array instead please.

var PNG = require("png-js"); PNG.decode("UVB-TEST.png", function (pixels) { // pixels is a 1d array (in rgba order) of decoded pixel data console.log(pixels); });

I would also know if there is a possibility to decode a function by providing its url instead of saving it in a local folder (because I need to process hundreds of images).

Thank you for your assistance.

Indexed png transparency increased to incorrrect length of 255

Hi,

in png.js at line 135 you're incorrectly lengthening transparency.indexed to 255, if it's shorter.

The max length of that array should actually be the length of the palette divided by 3. And if it's parsed and is any longer there should be an error.

So it should read,

short = (this.palette.length/3) - this.transparency.indexed.length;

Impossible to catch error thrown from inside decodePixels' zlib.inflate's callback

When throwing an error from inside zlib.inflate's callback it goes right down to the event queue handlers, internal to node, and not to the user code. As this is uncaught it will crash the application even if only one image has a failure.

You can trap them with process.on('uncaughtException', ...) to avoid the hard crash, but then fn() never gets called and most use case programs will just keep waiting for a decode that never finishes, an unnecessary timeout.

Any error should either pass through to a callback function or be logged but never thrown from inside the decode coroutine.
Maybe a secondary optional reject parameter: decodePixels(fn, reject) to avoid breaking the api?

Node v16.17.1

Lines:
https://github.com/foliojs/png.js/blob/master/png-node.js#L185
https://github.com/foliojs/png.js/blob/master/png-node.js#L293

MWE

const { inflate } = require('zlib');

// Same with inflate, gunzip, unzip

process.on('uncaughtException', err => {
  console.error('Uncaught Error', err);
});

const buf = Buffer.alloc(1);
try {
  inflate(buf, (error, decompressed) => {
    throw new Error('See stack trace. Example usage: Found error / wrong data');
  });
  console.log('Continue');
}catch(e) {
  console.error('Catch!', e);
}

Stack trace for the throw:

    at Inflate.cb (/mwe.js:12:11)
    at Inflate.zlibBufferOnError (node:zlib:146:8)
    at Inflate.emit (node:events:513:28)
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)

Can't capture exceptions when adding "invalid" PNG to the document

Trying to add a "problematic" PNG into a pdf causes an unmanaged exception in our application because pdfKit doesn't give us any way to capture the exception.

The problem is in the asynchronous API internally used to decode PNGs. Look this code into png-node.js file:

decodePixels(fn) {
    return zlib.inflate(this.imgData, (err, data) => {
       ...
      switch (data[pos++]) {
          ....
          default:
            throw new Error(`Invalid filter algorithm: ${data[pos - 1]}`);
     }
     ...
     return fn(pixels);
   }
} 

An internal throw new Error("invalid filter..:") is raised into the zlib.inflate callback causing NODE to capture it as an unmanaged exception.

Wrapping call into a try { } catch { } structure, doesn't help (because Inflate is called asynchronously )

try {
  pdf.image(imageFile, ...)
} catch(e){
  console.log("This message is not shown when an internal decode exception is raised");
}

In summary, calling image.decodePixels(function(data){...}) with problematic images can produce errors that are not "capturable" by the caller .

Only a comment: png-node.js API is asynchronows but without "error" management... that's really a bad library for a server side NODE application

you can find pieces of code like this:

PNG.decode = function(path, fn) {
  return fs.readFile(path, function(err, file) {
    var png;
    png = new PNG(file);
    return png.decode(function(pixels) {
      return fn(pixels);
   });
 });
};

As you can see, the "err" parameter in the callback is not treated properly and, in fact, the "fn" parameter doesn't expect to be informed about possible errors.

Can't not decode this file.

qq 20170601110555

Error: Invalid filter algorithm: 241
    at /path/to/my/project/png-node.js:242:21
    at Inflate.onEnd (zlib.js:227:5)
    at emitNone (events.js:72:20)
    at Inflate.emit (events.js:166:7)
    at endReadableNT (_stream_readable.js:921:12)
    at nextTickCallbackWith2Args (node.js:442:9)
    at process._tickCallback (node.js:356:17)

Can't decode png with BGR

Hi,

I'm using png-js to decode the png pics. When it comes to png with BGR (PNG files compressed by xcode), there would be error. Here is the error log.

path_to_project/node_modules/png-js/png-node.js:176
       throw err;
                ^
Error: incorrect header check
    at Zlib._binding.onerror (zlib.js:295:17)

I have no idea what to do.

Error: Invalid filter algorithm: 255

..........\node_modules\png-js\png-node.js:242
throw new Error("Invalid filter algorithm: " + data[pos - 1]);
^

Error: Invalid filter algorithm: 255
at Inflate.cb ( ........\node_modules\png-js\png-node.js:242:21)
at Inflate.zlibBufferOnEnd (node:zlib:161:10)
at Inflate.emit (node:events:520:28)
at endReadableNT (node:internal/streams/readable:1346:12)
at processTicksAndRejections (node:internal/process/task_queues:83:21)

Decoding PNG without DOM

Hi, is it possible to decode PNG with your library without using HTML elements, CSS and SVG? Just converting numbers to numbers? And without network communication?

I think the only thing missing in png.js is converting PNG to iOS app and sending it ti App Store.

Extraneous data after IEND not detected

Since the library also detects corrupt files in terms of being incomplete, I'd expect it to also detect any corrupt images that have data succeeding IEND and breaking image minification tools for example, e.g. grunt-contrib-imagemin with

Error: * Processing: app/images/layout/sticky_0.png
    Warning: Extraneous data found after IEND
    125x66 pixels, 4x8 bits/pixel, RGB+alpha
    Reducing image to 2x8 bits/pixel, grayscale+alpha
    Recoverable errors found in input. Rerun OptiPNG with -fix enabled.
    Error: Previous error(s) not fixed

Example image:
extraneous

offer async PNG.load()

I don't see any reason for PNG.load() to be synchronous. I understand it can be a desired behavior but why not make something like :

PNG.load = function(path,callback) {
      var file;
      if(!callback){
        file = fs.readFileSync(path);
        return new PNG(file);
      }else{
        file = fs.readFile(path,function(err,file){
         if(err) callback(err);
         return callback(null,new PNG(file));
        });
      }
    };

Of course it's an improvisation and there may be cleaner ways to achieve it, but I think the core idea is useful.

My use case is : I'm only interested in text tags so PNG.decode is a no-go, but I still want async operations.

README uses `sudo npm`

It's not a good idea to install npm modules using sudo. I'd recommend you don't advertise this method in your README.

png.decode callback function

The callback function for png.decode should have two arguments. The first should be for handling an error, the second should be the image data.

As it stands, if an image is loaded for a file which does not exist, the cryptic crash happens:

TypeError: Cannot read property '8' of undefined

From browser Worker

I am trying to use this from a Web Worker in a browser.

I get the image data by doing xhr with responseType arraybuffer. I then do var p = new PNG(arrbuf);

However this gets stuck into an infinite loop. I see this is because:

      while (true) {
        chunkSize = this.readUInt32();
        section = ((function() {
          var _i, _results;
          _results = [];
          for (i = _i = 0; _i < 4; i = ++_i) {
            _results.push(String.fromCharCode(this.data[this.pos++]));
          }
          return _results;
        }).call(this)).join('');

Can you please help me modify to use in Web Worker scope.

Thanks!

16-bit PNGs not rendered correctly

Hi,

I was trying to render a 16-bit png but doesn't seem like it supports 16 bit. I do that both "bits" and "pixelBitlength" were set to 16.

Any idea?

Thanks!

No License

Hi, the package.json file has no license and the is no LICENSE or COPYING file present in the repo so it seems this project is not really open-source right now.
Is this intentional or just an oversight?

png-js in angular

Hi,

I would like to use client-side png decoder with angular, installed png-js, and imported as:
import * PNG from png-js'

but when I examine in browser PNG it is coming from png-node.js. How can I tell it to use png.js (used for client side)?

**Note sorry for sending this as an issue (obviously it is not) but I couldn't find a forum to ask my question.

Thanks.

"Invalid arguments" when pixelBytes set to 0.5

I want to load in some very small images with indexed colour, in the browser. I don't actually want to display the image, only read the colours of the pixels, but documentation is a little thin, and I'm only as far as using the example code to load the image into a canvas element and it's throwing an "invalid arguments" error.

Breaking as the error is thrown shows it's at png.js line 231:

pixels = new Uint8Array(scanlineLength * this.height);

because scanlineLength is set to 7.5.

That was set a few lines earlier, because width is 15 and pixelBytes is 0.5, and pixelBytes is 0.5 because pixelBitLength is 4 and this is divided by 8.

Sample image is at http://tremby.net/dump/finn.png

Having data passed from PHP, how can we handle the file?

I've this snippet reading a png

   <?php
        $file_name = './ReactNative-snapshot-image6513693026486043647.png';
        $image_file_content = base64_encode(file_get_contents( $file_name ));

        $image_size = getimagesize( $file_name );
    ?>

I need to convert the png to a Uint8ClampedArray (to decode a QRCode client-side, long story)

Is there a way using your lib to get file content from a base64 string?

For instance, I am doing a similar thing using jpeg-js

    const jpegData = Buffer.from("<?php echo $image_file_content ?>", 'base64');
    const rawImageData = jpeg.decode(jpegData);
    const clamped_array = Uint8ClampedArray.from(rawImageData.data);
    const decodedGreenpass = window.jsQR(
          clamped_array,
         <?php echo $image_size[0]; ?>,
         <?php echo $image_size[1]; ?>
    );

I need to obtain in some way pngData or a Uint8ClampedArray

Encode

Thanks a ton for png.js! I'm loving it for handling ARDrone video.

It would be awesome if it were bidirectional as well - PNG.encode(rgbaData, width, height); and png.save('filename.png'); I want to send a stream of PNGs up to the browser after piping them through some processing.

I can try to implement this, but I'm a bit intimidated by http://www.w3.org/TR/PNG/ . Any help you (or anyone reading this) can give would be much appreciated.

Implemented interlacing support for Node.js (in JavaScript, not CoffeeScript).

I wanted to make sure this works, so I didn't try to fiddle with png-node.coffee, I modified the .js output.

    PNG.prototype.decodePixels = function(fn) {
      var _this = this;
      return zlib.inflate(this.imgData, function(err, data) {
        if (err) throw err;
        var pixelBytes = _this.pixelBitlength / 8;
        var fullPixels = new Buffer(_this.width * _this.height * pixelBytes);
        var pos = 0;
        function pass(x0, y0, dx, dy) {
          var byte, c, col, i, left, p, pa, paeth, pb, pc, pixels, row, scanlineLength, upper, upperLeft;
          var w = Math.ceil((_this.width - x0) / dx), h = Math.ceil((_this.height - y0) / dy);
          var isFull = _this.width == w && _this.height == h;
          scanlineLength = pixelBytes * w;
          pixels = isFull ? fullPixels : new Buffer(scanlineLength * h);
          row = 0;
          c = 0;
          while (row < h && pos < data.length) {
            switch (data[pos++]) {
              case 0:
                for (i = 0; i < scanlineLength; i += 1) {
                  pixels[c++] = data[pos++];
                }
                break;
              case 1:
                for (i = 0; i < scanlineLength; i += 1) {
                  byte = data[pos++];
                  left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
                  pixels[c++] = (byte + left) % 256;
                }
                break;
              case 2:
                for (i = 0; i < scanlineLength; i += 1) {
                  byte = data[pos++];
                  col = (i - (i % pixelBytes)) / pixelBytes;
                  upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
                  pixels[c++] = (upper + byte) % 256;
                }
                break;
              case 3:
                for (i = 0; i < scanlineLength; i += 1) {
                  byte = data[pos++];
                  col = (i - (i % pixelBytes)) / pixelBytes;
                  left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
                  upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
                  pixels[c++] = (byte + Math.floor((left + upper) / 2)) % 256;
                }
                break;
              case 4:
                for (i = 0; i < scanlineLength; i += 1) {
                  byte = data[pos++];
                  col = (i - (i % pixelBytes)) / pixelBytes;
                  left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
                  if (row === 0) {
                    upper = upperLeft = 0;
                  } else {
                    upper = pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
                    upperLeft = col && pixels[(row - 1) * scanlineLength + (col - 1) * pixelBytes + (i % pixelBytes)];
                  }
                  p = left + upper - upperLeft;
                  pa = Math.abs(p - left);
                  pb = Math.abs(p - upper);
                  pc = Math.abs(p - upperLeft);
                  if (pa <= pb && pa <= pc) {
                    paeth = left;
                  } else if (pb <= pc) {
                    paeth = upper;
                  } else {
                    paeth = upperLeft;
                  }
                  pixels[c++] = (byte + paeth) % 256;
                }
                break;
              default:
                throw new Error("Invalid filter algorithm: " + data[pos - 1]);
            }
            if (!isFull) {
              var fullPos = ((y0 + row * dy) * _this.width + x0) * pixelBytes;
              var partPos = row * scanlineLength;
              for (i = 0; i < w; i += 1) {
                for (var j = 0; j < pixelBytes; j += 1)
                  fullPixels[fullPos++] = pixels[partPos++];
                fullPos += (dx - 1) * pixelBytes;
              }
            }
            row++;
          }
        }
        if (_this.interlaceMethod == 1) {
          /*
            1 6 4 6 2 6 4 6
            7 7 7 7 7 7 7 7
            5 6 5 6 5 6 5 6
            7 7 7 7 7 7 7 7
            3 6 4 6 3 6 4 6
            7 7 7 7 7 7 7 7
            5 6 5 6 5 6 5 6
            7 7 7 7 7 7 7 7
          */
          pass(0, 0, 8, 8); // 1
          /* NOTE these seem to follow the pattern:
           * pass(x, 0, 2*x, 2*x);
           * pass(0, x,   x, 2*x);
           * with x being 4, 2, 1.
           */
          pass(4, 0, 8, 8); // 2
          pass(0, 4, 4, 8); // 3

          pass(2, 0, 4, 4); // 4
          pass(0, 2, 2, 4); // 5

          pass(1, 0, 2, 2); // 6
          pass(0, 1, 1, 2); // 7
        } else
          pass(0, 0, 1, 1);
        return fn(fullPixels);
      });
    };

Can't open PNGs created using Windows 8.1's Paint

I don't seem to be able to get png-js to load PNGs made in Windows 8.1's Paint on Linux or Windows 8.1.

Repro source:

var PNG = require("png-js")
var png = new PNG("test.png")

Expected behaviour: completes without any errors or visible side effects.
Actual behaviour: crashes while constructing the PNG with the following error:
C:\Users\jameswilddev\Desktop\node_modules\png-js\png-node.js:140
throw new Error("Incomplete or corrupt PNG file");
^
Error: Incomplete or corrupt PNG file
at new PNG (C:\Users\jameswilddev\Desktop\node_modules\png-js\png-node.js:14
0:17)
at Object. (C:\Users\jameswilddev\Desktop\repro\repro.js:2:11)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:906:3

Environment details:
Windows 8.1 x64
Node.js v0.10.33
png-js 0.1.1

Ubuntu Linux 14.04.1 LTS (Trusty)
Node.js v0.10.35
png-js 0.1.1

I can open this image without a problem in Paint, Chrome or GIMP. Have attached but don't know if GitHub will do any pre-processing on it which will fix it, so I've also uploaded it to my Cloud9 at:

https://sunruse-jameswilddev.c9.io/test.png

test

Thank you for reading.

Invalid filter algorithm: 222

I have problem when i use png image. But i found code to fix this problem. please change code to
PNG.prototype.decodePixels = function(fn) { var _this = this; return zlib.inflate(this.imgData, function(err, data) { if (err) throw err; var pixelBytes = _this.pixelBitlength / 8; var fullPixels = new Buffer(_this.width * _this.height * pixelBytes); var pos = 0; function pass(x0, y0, dx, dy) { var byte, c, col, i, left, p, pa, paeth, pb, pc, pixels, row, scanlineLength, upper, upperLeft; var w = Math.ceil((_this.width - x0) / dx), h = Math.ceil((_this.height - y0) / dy); var isFull = _this.width == w && _this.height == h; scanlineLength = pixelBytes * w; pixels = isFull ? fullPixels : new Buffer(scanlineLength * h); row = 0; c = 0; while (row < h && pos < data.length) { switch (data[pos++]) { case 0: for (i = 0; i < scanlineLength; i += 1) { pixels[c++] = data[pos++]; } break; case 1: for (i = 0; i < scanlineLength; i += 1) { byte = data[pos++]; left = i < pixelBytes ? 0 : pixels[c - pixelBytes]; pixels[c++] = (byte + left) % 256; } break; case 2: for (i = 0; i < scanlineLength; i += 1) { byte = data[pos++]; col = (i - (i % pixelBytes)) / pixelBytes; upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)]; pixels[c++] = (upper + byte) % 256; } break; case 3: for (i = 0; i < scanlineLength; i += 1) { byte = data[pos++]; col = (i - (i % pixelBytes)) / pixelBytes; left = i < pixelBytes ? 0 : pixels[c - pixelBytes]; upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)]; pixels[c++] = (byte + Math.floor((left + upper) / 2)) % 256; } break; case 4: for (i = 0; i < scanlineLength; i += 1) { byte = data[pos++]; col = (i - (i % pixelBytes)) / pixelBytes; left = i < pixelBytes ? 0 : pixels[c - pixelBytes]; if (row === 0) { upper = upperLeft = 0; } else { upper = pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)]; upperLeft = col && pixels[(row - 1) * scanlineLength + (col - 1) * pixelBytes + (i % pixelBytes)]; } p = left + upper - upperLeft; pa = Math.abs(p - left); pb = Math.abs(p - upper); pc = Math.abs(p - upperLeft); if (pa <= pb && pa <= pc) { paeth = left; } else if (pb <= pc) { paeth = upper; } else { paeth = upperLeft; } pixels[c++] = (byte + paeth) % 256; } break; default: throw new Error("Invalid filter algorithm: " + data[pos - 1]); } if (!isFull) { var fullPos = ((y0 + row * dy) * _this.width + x0) * pixelBytes; var partPos = row * scanlineLength; for (i = 0; i < w; i += 1) { for (var j = 0; j < pixelBytes; j += 1) fullPixels[fullPos++] = pixels[partPos++]; fullPos += (dx - 1) * pixelBytes; } } row++; } } if (_this.interlaceMethod == 1) { /* 1 6 4 6 2 6 4 6 7 7 7 7 7 7 7 7 5 6 5 6 5 6 5 6 7 7 7 7 7 7 7 7 3 6 4 6 3 6 4 6 7 7 7 7 7 7 7 7 5 6 5 6 5 6 5 6 7 7 7 7 7 7 7 7 */ pass(0, 0, 8, 8); // 1 /* NOTE these seem to follow the pattern: * pass(x, 0, 2*x, 2*x); * pass(0, x, x, 2*x); * with x being 4, 2, 1. */ pass(4, 0, 8, 8); // 2 pass(0, 4, 4, 8); // 3 pass(2, 0, 4, 4); // 4 pass(0, 2, 2, 4); // 5 pass(1, 0, 2, 2); // 6 pass(0, 1, 1, 2); // 7 } else pass(0, 0, 1, 1); return fn(fullPixels); }); };

on file png-node.js #8

Trying to manually decode the image in browser - error

Hi

Doing something in this manner (CoffeeScript, can provide compiled version)

image_url = "/images/ninja.png"
PNG.load image_url, null, (png) ->
    png.decode (pixels) ->
        console.log pixels

Fails here:

data = imageData.data;
length = data.length; // Cannot read property 'length' of undefined 

in .copyToImageData.

what's the pixel ordering

The README states pixels is a 1d array of decoded pixel data but does not mention what the ordering is. Is this the same as a canvas image data object, with [r,g,b,a] pattern for each screen pixel? (if so, can the README be amended with that information? if not: same request =)

Make library browser friendly

Hi @devongovett !

On my current effort of getting rid of your libraries's forks on react-pdf (textkit, unicode-properties, pdfkit, fontkit and this lib), I think it would be beneficial for everybody to make this library a bit more browser friendly.

These are some of the issues I currently have with png.js:

  • Node version depends on fs, which is the one that pdfkit uses. So I cant use pdfkit without adding shims
  • Web version does not export the PNG object. Only adds it globally to window
  • Blocker for using directly pdfkit if your lib runs seamlessly on node and web

Changes proposal:

  • Write some tests to ensure everything works as before
  • Rewrite to ES6 (optional)
  • Make library browser friendly: ignoring fs on web build and (maybe) adding the XMLHttpRequest instead. Maybe adding the animation decoding also to this core (fcTL, fdAT sections)? There's no issues with zlib and Buffer since bundlers will shim them automatically (at least as far as I saw)
  • Keep /png.js with all the canvas manipulation for the people who is already using it

I already have a react-pdf fork with some of these points, and it's working great. These types of changes will make one day possible for me to rely directly on the main packages, and actively contribute to those. It's getting very complicated for me to do so when I have to also work on the forks

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.